Skip to content

[group key addrs 6/6]: send and receive support for V2 addresses #1587

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: pedersen-keys-refactor
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
60 changes: 50 additions & 10 deletions address/address.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"github.com/lightninglabs/taproot-assets/asset"
"github.com/lightninglabs/taproot-assets/commitment"
"github.com/lightninglabs/taproot-assets/fn"
"github.com/lightninglabs/taproot-assets/proof"
"github.com/lightninglabs/taproot-assets/taprpc"
"github.com/lightningnetwork/lnd/tlv"
)
Expand Down Expand Up @@ -48,7 +49,8 @@ var (
// create a Taproot Asset address for a Normal asset with an amount of
// zero.
ErrInvalidAmountNormal = errors.New(
"address: normal asset amount of zero",
"address: zero amount cannot be used for normal asset " +
"addresses of V0 or V1",
)

// ErrUnsupportedAssetType is an error returned when we attempt to
Expand All @@ -72,6 +74,12 @@ var (
// ErrUnknownVersion is returned when encountering an address with an
// unrecognised version number.
ErrUnknownVersion = errors.New("address: unknown version number")

// ErrInvalidProofCourierAddr is returned when we attempt to create a
// Taproot Asset address with a proof courier address that is not valid.
ErrInvalidProofCourierAddr = errors.New(
"address: invalid proof courier address",
)
)

// Version denotes the version of a Taproot Asset address format.
Expand All @@ -84,8 +92,12 @@ const (
// V1 addresses use V2 Taproot Asset commitments.
V1 Version = 1

// V2 addresses support sending grouped assets and require the new
// auth mailbox proof courier address format.
V2 Version = 2

// LatestVersion is the latest supported Taproot Asset address version.
latestVersion = V1
latestVersion = V2
)

// Tap represents a Taproot Asset address. Taproot Asset addresses specify an
Expand All @@ -101,7 +113,8 @@ type Tap struct {
// AssetVersion is the Taproot Asset version of the asset.
AssetVersion asset.Version

// AssetID is the asset ID of the asset.
// AssetID is the asset ID of the asset. This will be all zeroes for
// V2 addresses that have a group key set.
AssetID asset.ID

// GroupKey is the tweaked public key that is used to associate assets
Expand All @@ -110,7 +123,12 @@ type Tap struct {
GroupKey *btcec.PublicKey

// ScriptKey represents a tweaked Taproot output key encumbering the
// different ways an asset can be spent.
// different ways an asset can be spent. For V2 addresses, this key is
// not the tweaked Taproot output key but instead the bare/raw/internal
// script key. The sender will use this key to encrypt the send fragment
// that they post to the proof courier's mailbox. The raw script key
// will also be used by the sender to derive different Taproot output
// script keys for each asset ID.
ScriptKey btcec.PublicKey

// InternalKey is the BIP-0340/0341 public key of the receiver.
Expand All @@ -122,14 +140,19 @@ type Tap struct {
TapscriptSibling *commitment.TapscriptPreimage

// Amount is the number of asset units being requested by the receiver.
// The amount is allowed to be zero for V2 addresses, where the sender
// will post a fragment containing the asset IDs and amounts to the
// proof courier's mailbox.
Amount uint64

// assetGen is the receiving asset's genesis metadata which directly
// maps to its unique ID within the Taproot Asset protocol.
assetGen asset.Genesis

// ProofCourierAddr is the address of the proof courier that will be
// used to distribute related proofs for this address.
// used to distribute related proofs for this address. For V2 addresses
// the proof courier address is mandatory and must be a valid auth
// mailbox address.
ProofCourierAddr url.URL

// UnknownOddTypes is a map of unknown odd types that were encountered
Expand Down Expand Up @@ -191,7 +214,7 @@ func New(version Version, genesis asset.Genesis, groupKey *btcec.PublicKey,
}

case asset.Normal:
if amt == 0 {
if amt == 0 && version < V2 {
return nil, ErrInvalidAmountNormal
}

Expand All @@ -208,6 +231,16 @@ func New(version Version, genesis asset.Genesis, groupKey *btcec.PublicKey,
return nil, ErrUnknownVersion
}

// Addresses with version 2 or later must use the new authmailbox proof
// courier type.
if version >= V2 &&
proofCourierAddr.Scheme != proof.AuthMailboxUniRpcCourierType {

return nil, fmt.Errorf("%w: address version %d must use the "+
"'%s' proof courier type", ErrInvalidProofCourierAddr,
version, proof.AuthMailboxUniRpcCourierType)
}

// We can only use a tapscript sibling that is not a Taproot Asset
// commitment.
if tapscriptSibling != nil {
Expand Down Expand Up @@ -259,7 +292,7 @@ func CommitmentVersion(vers Version) (*commitment.TapCommitmentVersion,
// can't know without accessing all leaves of the commitment itself.
case V0:
return nil, nil
case V1:
case V1, V2:
return fn.Ptr(commitment.TapCommitmentV2), nil
default:
return nil, ErrUnknownVersion
Expand Down Expand Up @@ -465,15 +498,16 @@ func (a *Tap) EncodeAddress() (string, error) {

// String returns the string representation of a Taproot Asset address.
func (a *Tap) String() string {
return fmt.Sprintf("TapAddr{id=%s, amount=%d, script_key=%x}",
a.AssetID, a.Amount, a.ScriptKey.SerializeCompressed())
s := asset.NewSpecifierOptionalGroupPubKey(a.AssetID, a.GroupKey)
return fmt.Sprintf("TapAddr{specifier=%s, amount=%d, script_key=%x}",
&s, a.Amount, a.ScriptKey.SerializeCompressed())
}

// IsUnknownVersion returns true if the address version is not recognized by
// this implementation of tap.
func IsUnknownVersion(v Version) bool {
switch v {
case V0, V1:
case V0, V1, V2:
return false
default:
return true
Expand Down Expand Up @@ -553,6 +587,9 @@ func UnmarshalVersion(version taprpc.AddrVersion) (Version, error) {
case taprpc.AddrVersion_ADDR_VERSION_V1:
return V1, nil

case taprpc.AddrVersion_ADDR_VERSION_V2:
return V2, nil

default:
return 0, fmt.Errorf("unknown address version: %v", version)
}
Expand All @@ -570,6 +607,9 @@ func MarshalVersion(version Version) (taprpc.AddrVersion, error) {
case V1:
return taprpc.AddrVersion_ADDR_VERSION_V1, nil

case V2:
return taprpc.AddrVersion_ADDR_VERSION_V2, nil

default:
return 0, fmt.Errorf("unknown address version: %v", version)
}
Expand Down
Loading
Loading