Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
53abd8d
address: add DelegationKeyChecker interface to verify asset delegatio…
Roasbeef Jul 24, 2025
80da439
supplycommit: add MintCommitter and BurnSupplyCommitter interfaces
Roasbeef Jul 24, 2025
b405ebd
tapgarden: extend GardenKit with delegation and supply commit support
Roasbeef Jul 24, 2025
73b8625
tapfreighter: add delegation key filtering for burn supply commits
Roasbeef Jul 24, 2025
d4924b2
tapgarden: add delegation key filtering for mint supply commits
Roasbeef Jul 24, 2025
e64fdb4
tapcfg: wire delegation checker to garden and freighter subsystems
Roasbeef Jul 24, 2025
3ead5f5
tapgarden: add tests for mint supply commit delegation key filtering
Roasbeef Jul 24, 2025
e761e70
tapfreighter: add tests for burn supply commit filtering
Roasbeef Jul 24, 2025
83a5d54
universe: add new CommitPoint() and TapscriptRoot() methods to RootCo…
Roasbeef Aug 15, 2025
d1a0e89
multi: add outpoint field to mint anchor uni commitment
Roasbeef Aug 15, 2025
2ba46f8
tapdb: set the outpoint of a pre commitment during insertion
Roasbeef Aug 15, 2025
3f4fcac
tapdb: remove extra call to applySupplyUpdatesInternal
Roasbeef Aug 15, 2025
75e1b83
tapdb: make sure we actually mark pre commitments as spent
Roasbeef Aug 15, 2025
8750d61
tapdb: add test to ensure pre commitment spend detection works
Roasbeef Aug 15, 2025
f1ba65b
tapdb: fix bug by ensuring that we write the full keydesc to disk
Roasbeef Aug 15, 2025
81f33ea
universe/supplycommit: fix PSBT bug, ensure the TaprootMerkleRoot is set
Roasbeef Aug 15, 2025
d003bfc
universe/supplycommit: add additional logging
Roasbeef Aug 15, 2025
74462fa
itest: add supply commit mint/burn itests
Roasbeef Aug 15, 2025
0390ec1
docs: add release notes
Roasbeef Aug 20, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 88 additions & 0 deletions address/book.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,18 @@ var (
// ErrAssetMetaNotFound is returned when an asset meta is not found in
// the database.
ErrAssetMetaNotFound = fmt.Errorf("asset meta not found")

// ErrAssetGroupQueryFailed is returned when querying for an asset group
// fails.
ErrAssetGroupQueryFailed = fmt.Errorf("asset group query failed")

// ErrAssetMetaQueryFailed is returned when querying for asset metadata
// fails.
ErrAssetMetaQueryFailed = fmt.Errorf("asset meta query failed")

// ErrDelegationKeyQueryFailed is returned when querying for delegation
// key fails.
ErrDelegationKeyQueryFailed = fmt.Errorf("delegation key query failed")
)

// AddrWithKeyInfo wraps a normal Taproot Asset struct with key descriptor
Expand Down Expand Up @@ -165,6 +177,12 @@ type Storage interface {
// database.
FetchAllAssetMeta(
ctx context.Context) (map[asset.ID]*proof.MetaReveal, error)

// FetchInternalKeyLocator attempts to fetch the key locator information
// for the given raw internal key. If the key cannot be found, then
// ErrInternalKeyNotFound is returned.
FetchInternalKeyLocator(ctx context.Context,
rawKey *btcec.PublicKey) (keychain.KeyLocator, error)
}

// KeyRing is used to create script and internal keys for Taproot Asset
Expand Down Expand Up @@ -841,3 +859,73 @@ func (b *Book) RemoveSubscriber(

return nil
}

// DelegationKeyChecker is used to verify that we control the delegation key
// for a given asset, which is required for creating supply commitments.
type DelegationKeyChecker interface {
// HasDelegationKey checks if we control the delegation key for the
// given asset ID. Returns true if we have the private key for the
// asset's delegation key, false otherwise.
HasDelegationKey(ctx context.Context, assetID asset.ID) (bool, error)
}

// HasDelegationKey checks if we control the delegation key for the given
// asset ID. Returns true if we have the private key for the asset's
// delegation key, false otherwise.
//
// NOTE: This is part of the DelegationKeyChecker interface.
func (b *Book) HasDelegationKey(ctx context.Context,
assetID asset.ID) (bool, error) {

assetGroup, err := b.cfg.Store.QueryAssetGroupByID(ctx, assetID)
if err != nil {
return false, fmt.Errorf("%w: %w", ErrAssetGroupQueryFailed,
err)
}

// If the asset doesn't have a group, it can't have a delegation key. So
// we just return false here.
if assetGroup == nil || assetGroup.GroupKey == nil {
return false, nil
}

// Retrieve asset meta reveal for the asset ID. This will be used to
// obtain the supply commitment delegation key.
metaReveal, err := b.cfg.Store.FetchAssetMetaForAsset(ctx, assetID)
if err != nil {
return false, fmt.Errorf("%w: %w", ErrAssetMetaQueryFailed, err)
}

// If there's no meta reveal or delegation key, we can't control it.
if metaReveal == nil || metaReveal.DelegationKey.IsNone() {
return false, nil
}

delegationPubKey, err := metaReveal.DelegationKey.UnwrapOrErr(
fmt.Errorf("delegation key not found for given asset"),
)
if err != nil {
return false, err
}

// Now that we have the delegation key, we'll see if we know of the
// internal key locator. If we do, then this means that we were the ones
// that created it in the first place.
_, err = b.cfg.Store.FetchInternalKeyLocator(ctx, &delegationPubKey)
switch {
// If we get this error, then we don't control this delegation key.
case errors.Is(err, ErrInternalKeyNotFound):
return false, nil
case err != nil:
return false, fmt.Errorf("%w: %w",
ErrDelegationKeyQueryFailed, err)
}

// If we reached this point, then we know that we control the delegation
// key.
return true, nil
}

// A compile-time assertion to ensure Book implements the DelegationKeyChecker
// interface.
var _ DelegationKeyChecker = (*Book)(nil)
Loading