Documentation
¶
Overview ¶
Package token implements CIP-56 token operations such as mint, burn, transfer, and balance queries.
Index ¶
- Variables
- func ConvertChoiceContext(raw json.RawMessage) (map[string]string, error)
- func ConvertDisclosedContracts(raw json.RawMessage, fallbackDomainID string) ([]*lapiv2.DisclosedContract, error)
- type AcceptChoiceContext
- type AcceptContextResponse
- type AnyValue
- type AnyValueMap
- type BurnRequest
- type ChoiceArguments
- type Client
- func (c *Client) AcceptTransferInstruction(ctx context.Context, partyID, instructionCID, instrumentAdmin string) error
- func (c *Client) Burn(ctx context.Context, req *BurnRequest) error
- func (c *Client) ExecuteTransfer(ctx context.Context, req *ExecuteTransferRequest) error
- func (c *Client) FindPendingInboundTransferInstructions(ctx context.Context, partyID string) ([]string, error)
- func (c *Client) GetAllHoldings(ctx context.Context) ([]*Holding, error)
- func (c *Client) GetAllocationFactory(ctx context.Context) (*TransferFactoryInfo, error)
- func (c *Client) GetBalanceByFingerprint(ctx context.Context, fingerprint string, tokenSymbol string) (string, error)
- func (c *Client) GetBalanceByPartyID(ctx context.Context, partyID string, tokenSymbol string) (string, error)
- func (c *Client) GetHoldings(ctx context.Context, ownerParty string, tokenSymbol string) ([]*Holding, error)
- func (c *Client) GetHoldingsByParty(ctx context.Context, ownerParty, instrumentID string) ([]*Holding, error)
- func (c *Client) GetTokenConfigCID(ctx context.Context, tokenSymbol string) (string, error)
- func (c *Client) GetTokenTransferEvents(ctx context.Context) ([]*TokenTransferEvent, error)
- func (c *Client) GetTotalSupply(ctx context.Context, tokenSymbol string) (string, error)
- func (c *Client) GetTransferFactory(ctx context.Context) (*TransferFactoryInfo, error)
- func (c *Client) Mint(ctx context.Context, req *MintRequest) (string, error)
- func (c *Client) PrepareAcceptTransfer(ctx context.Context, partyID, instructionCID, instrumentAdmin string) (*PreparedTransfer, error)
- func (c *Client) PrepareTransfer(ctx context.Context, req *PrepareTransferRequest) (*PreparedTransfer, error)
- func (c *Client) TransferByFingerprint(ctx context.Context, ...) error
- func (c *Client) TransferByPartyID(ctx context.Context, ...) error
- func (c *Client) TransferInternalByPartyID(ctx context.Context, ...) error
- type Config
- type EventType
- type ExecuteTransferRequest
- type ExternalTokenConfig
- type ExtraArgs
- type Holding
- type InstrumentRef
- type KeyResolver
- type MintRequest
- type Option
- type PrepareTransferRequest
- type PreparedTransfer
- type RegistryClient
- type RegistryRequest
- type RegistryResponse
- type RegistryTransferDetail
- type Signer
- type TemplateIdentifier
- type Token
- type TokenTransferEvent
- type TransferFactoryInfo
Constants ¶
This section is empty.
Variables ¶
var ErrInsufficientBalance = errors.New("insufficient balance")
ErrInsufficientBalance indicates the owner's total unlocked balance is less than the required amount.
var ErrTransferFactoryNotFound = errors.New("no active CIP56TransferFactory found")
ErrTransferFactoryNotFound indicates no active CIP56TransferFactory contract exists on the ledger.
Functions ¶
func ConvertChoiceContext ¶
func ConvertChoiceContext(raw json.RawMessage) (map[string]string, error)
ConvertChoiceContext parses the registry's choice context JSON into a map suitable for EncodeExtraArgs. Returns nil for null or empty input. Used for the legacy TextMap-of-Text shape. AllocationFactory-based registries return the richer AnyValue shape, which is parsed by ConvertAnyValueChoiceContext instead.
func ConvertDisclosedContracts ¶
func ConvertDisclosedContracts(raw json.RawMessage, fallbackDomainID string) ([]*lapiv2.DisclosedContract, error)
ConvertDisclosedContracts parses the registry's disclosed contracts JSON into proto messages.
Types ¶
type AcceptChoiceContext ¶
AcceptChoiceContext holds the TextMap AnyValue for TransferInstruction_Accept.
func ConvertAnyValueChoiceContext ¶
func ConvertAnyValueChoiceContext(raw json.RawMessage) (AcceptChoiceContext, error)
ConvertAnyValueChoiceContext parses an AnyValue-shaped registry choice context (`{"values": {key: {tag, value}, ...}}`) into AcceptChoiceContext. Used when the registry returns context entries for AllocationFactory's TransferFactory_Transfer choice (instrument-configuration as AV_ContractId, sender-credentials as AV_List). Returns an empty context when raw is null or doesn't carry the AnyValue shape.
type AcceptContextResponse ¶
type AcceptContextResponse struct {
ChoiceContextData AcceptChoiceContext `json:"choiceContextData"`
DisclosedContracts []registryDisclosedContract `json:"disclosedContracts"`
}
AcceptContextResponse is returned by the registrar's accept choice-context endpoint.
type AnyValue ¶
type AnyValue struct {
Tag string `json:"tag"`
Value json.RawMessage `json:"value"`
}
AnyValue is the JSON {"tag": "...", "value": ...} ADT for a Daml-LF AnyValue. Tags: AV_ContractId | AV_Text | AV_Party | AV_Bool | AV_Int | AV_Decimal | AV_List | AV_Map.
type AnyValueMap ¶
AnyValueMap models the `{"values": {...}}` AnyValue container that wraps metadata and context maps in the Splice token-standard JSON.
type BurnRequest ¶
type BurnRequest struct {
HoldingCID string
Amount string
TokenSymbol string // needed for GetTokenConfigCID lookup
EventMeta map[string]string // bridge context; nil for native burns
}
BurnRequest represents an issuer burn request via TokenConfig.
type ChoiceArguments ¶
type ChoiceArguments struct {
ExpectedAdmin string `json:"expectedAdmin"`
Transfer RegistryTransferDetail `json:"transfer"`
ExtraArgs ExtraArgs `json:"extraArgs"`
}
ChoiceArguments wraps the on-ledger TransferFactory_Transfer choice arguments alongside the off-ledger extraArgs (context + meta) consumed by the registry.
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client implements CIP-56 token operations.
func (*Client) AcceptTransferInstruction ¶
func (*Client) ExecuteTransfer ¶
func (c *Client) ExecuteTransfer(ctx context.Context, req *ExecuteTransferRequest) error
func (*Client) FindPendingInboundTransferInstructions ¶
func (*Client) GetAllHoldings ¶
func (*Client) GetAllocationFactory ¶
func (c *Client) GetAllocationFactory(ctx context.Context) (*TransferFactoryInfo, error)
GetAllocationFactory finds any active contract implementing the Splice TransferFactory interface. Used as a fallback when no CIP56TransferFactory exists (e.g. tokens using AllocationFactory from utility_registry_app_v0). Uses an interface filter keyed on SpliceTransferPackageID so the concrete template's package ID never needs to be known.
func (*Client) GetBalanceByFingerprint ¶
func (*Client) GetBalanceByPartyID ¶
func (*Client) GetHoldings ¶
func (*Client) GetHoldingsByParty ¶
func (c *Client) GetHoldingsByParty(ctx context.Context, ownerParty, instrumentID string) ([]*Holding, error)
GetHoldingsByParty queries all Splice HoldingV1 holdings visible to the given party. This is the unified query path for all Splice-compliant tokens (CIP-56 and external like USDCx). If instrumentID is non-empty, results are filtered to that instrument. TODO: add unit tests with mocked ledger client (happy path, filtering, errors).
func (*Client) GetTokenConfigCID ¶
func (*Client) GetTokenTransferEvents ¶
func (c *Client) GetTokenTransferEvents(ctx context.Context) ([]*TokenTransferEvent, error)
func (*Client) GetTotalSupply ¶
func (*Client) GetTransferFactory ¶
func (c *Client) GetTransferFactory(ctx context.Context) (*TransferFactoryInfo, error)
func (*Client) PrepareAcceptTransfer ¶
func (*Client) PrepareTransfer ¶
func (c *Client) PrepareTransfer(ctx context.Context, req *PrepareTransferRequest) (*PreparedTransfer, error)
func (*Client) TransferByFingerprint ¶
func (*Client) TransferByPartyID ¶
type Config ¶
type Config struct {
DomainID string `yaml:"domain_id"`
IssuerParty string `yaml:"issuer_party"`
UserID string `yaml:"user_id"`
CIP56PackageID string `yaml:"cip56_package_id" validate:"required"`
SpliceTransferPackageID string `yaml:"splice_transfer_package_id" validate:"required"`
SpliceHoldingPackageID string `yaml:"splice_holding_package_id" validate:"required"`
UtilityRegistryAppPackageID string `yaml:"utility_registry_app_package_id"`
// UtilityRegistryPackageID is the utility_registry_v0 package ID.
// Required when using AllocationFactory-based tokens (e.g., USDCx on P2) so that
// InstrumentConfiguration and TransferRule can be looked up and provided as context
// for the TransferFactory_Transfer choice.
UtilityRegistryPackageID string `yaml:"utility_registry_package_id"`
// ExternalTokens maps InstrumentAdmin party IDs to their registry configuration.
// Tokens whose InstrumentAdmin matches IssuerParty use local ACS-based factory discovery.
// Tokens whose InstrumentAdmin is in this map use the external registry API.
ExternalTokens map[string]ExternalTokenConfig `yaml:"external_tokens"`
}
Config contains the configuration required to initialize the token client.
type ExecuteTransferRequest ¶
type ExecuteTransferRequest struct {
PreparedTransfer *PreparedTransfer // The prepared transfer to execute
Signature []byte // DER-encoded ECDSA signature of TransactionHash
SignedBy string // Canton multihash fingerprint of signing key
}
ExecuteTransferRequest contains the client-signed data to complete a non-custodial transfer.
type ExternalTokenConfig ¶
type ExternalTokenConfig struct {
RegistryURL string `yaml:"registry_url" validate:"required"`
}
ExternalTokenConfig holds the registry endpoint for an external token issuer. Key in the map is the InstrumentAdmin party ID (e.g., Circle's Bridge-Operator).
type ExtraArgs ¶
type ExtraArgs struct {
Context AnyValueMap `json:"context"`
Meta AnyValueMap `json:"meta"`
}
ExtraArgs carries the off-ledger context and meta AnyValue maps required by the AllocationFactory's TransferFactory_Transfer choice.
type Holding ¶
type Holding struct {
ContractID string
Issuer string
Owner string
Amount string
Symbol string // derived from Metadata["splice.chainsafe.io/symbol"]
InstrumentAdmin string
InstrumentID string
Locked bool
Metadata map[string]string
}
Holding represents a CIP56Holding contract (Splice-compliant).
type InstrumentRef ¶
InstrumentRef is the structured instrument identifier the registry expects: the issuer admin party plus the instrument id within that issuer's namespace.
type KeyResolver ¶
KeyResolver looks up a signer for the given Canton party ID. Used by Interactive Submission to sign transactions on behalf of external parties.
type MintRequest ¶
type MintRequest struct {
RecipientParty string
Amount string
TokenSymbol string // needed for GetTokenConfigCID lookup
ConfigCID string
EventMeta map[string]string // bridge context; nil for native mints
}
MintRequest represents an issuer mint request via TokenConfig.
type Option ¶
type Option func(*settings)
Option configures the token client.
func WithKeyResolver ¶
func WithKeyResolver(kr KeyResolver) Option
WithKeyResolver provides a function to look up signing keys by party ID. Required for transfers involving external parties (Interactive Submission).
func WithLogger ¶
WithLogger sets a custom logger for the token client.
func WithRegistryClient ¶
func WithRegistryClient(rc *RegistryClient) Option
WithRegistryClient sets the HTTP client for external Transfer Factory Registry API calls. Required for transferring tokens issued by external parties (e.g., USDCx).
type PrepareTransferRequest ¶
type PrepareTransferRequest struct {
FromPartyID string
ToPartyID string
Amount string
TokenSymbol string
}
PrepareTransferRequest contains the parameters for preparing a non-custodial transfer.
type PreparedTransfer ¶
type PreparedTransfer struct {
TransferID string // UUID
TransactionHash []byte // PreparedTransactionHash from Canton (what client signs)
PreparedTransaction *interactivev2.PreparedTransaction // Opaque protobuf message (passed back on execute)
HashingSchemeVersion interactivev2.HashingSchemeVersion // Must match on execute
PartyID string // The acting party
ExpiresAt time.Time // Cache TTL deadline
}
PreparedTransfer holds the result of a prepare step for non-custodial signing.
type RegistryClient ¶
type RegistryClient struct {
// contains filtered or unexported fields
}
RegistryClient calls the Splice Transfer Factory Registry API to discover transfer factories for external tokens (e.g., USDCx).
func NewRegistryClient ¶
func NewRegistryClient(httpClient *http.Client) *RegistryClient
NewRegistryClient creates a new registry client.
func (*RegistryClient) GetAcceptChoiceContext ¶
func (rc *RegistryClient) GetAcceptChoiceContext( ctx context.Context, registryBaseURL, registrarParty, instructionCID string, ) (*AcceptContextResponse, error)
GetAcceptChoiceContext calls the registrar's accept choice-context endpoint for a pending TransferInstruction. Returns the choiceContextData (AnyValue map) and disclosed contracts needed to exercise TransferInstruction_Accept.
func (*RegistryClient) GetTransferFactory ¶
func (rc *RegistryClient) GetTransferFactory( ctx context.Context, registryBaseURL, registrarParty string, req *RegistryRequest, ) (*RegistryResponse, error)
GetTransferFactory calls the registry to discover the transfer factory for an external token. registrarParty is the issuer's party ID under whose namespace the registry is mounted (DA's hosted multi-registrar API multiplexes registrars by URL path).
type RegistryRequest ¶
type RegistryRequest struct {
ChoiceArguments ChoiceArguments `json:"choiceArguments"`
ExcludeDebugFields bool `json:"excludeDebugFields"`
}
RegistryRequest is the POST body for the Transfer Factory Registry API. Shape matches the Splice token-standard spec as hosted by DA's utilities API (e.g. api.utilities.digitalasset-dev.com): choice arguments are wrapped in `choiceArguments`, with a sibling `excludeDebugFields` flag.
type RegistryResponse ¶
type RegistryResponse struct {
FactoryID string `json:"factoryId"`
TransferKind string `json:"transferKind"`
ChoiceContext json.RawMessage `json:"choiceContext"`
DisclosedContracts json.RawMessage `json:"disclosedContracts"`
}
RegistryResponse is the registry response as consumed by the SDK. `ChoiceContext` holds the AnyValue map (i.e. `choiceContext.choiceContextData` from the wire shape) and `DisclosedContracts` holds the array — both lifted out of the wire envelope by GetTransferFactory so the downstream converters (ConvertAnyValueChoiceContext / ConvertDisclosedContracts) can consume them directly.
type RegistryTransferDetail ¶
type RegistryTransferDetail struct {
Sender string `json:"sender"`
Receiver string `json:"receiver"`
Amount string `json:"amount"`
InstrumentID InstrumentRef `json:"instrumentId"`
InputHoldingCIDs []string `json:"inputHoldingCids"`
Meta AnyValueMap `json:"meta"`
ExecuteBefore string `json:"executeBefore"`
RequestedAt string `json:"requestedAt"`
}
RegistryTransferDetail contains the transfer parameters for registry lookup. `executeBefore` and `requestedAt` are RFC3339 timestamps; the registry uses them to assert the transfer falls within the issuer's validity window.
type Signer ¶
Signer can produce DER-encoded ECDSA signatures for Canton Interactive Submission. SignDER hashes the message with SHA-256 before signing (Canton returns multihash data). Fingerprint returns the Canton key fingerprint (multihash of SPKI public key).
type TemplateIdentifier ¶
type TemplateIdentifier struct {
PackageID string `json:"package_id"`
ModuleName string `json:"module_name"`
EntityName string `json:"entity_name"`
}
TemplateIdentifier is a portable representation of a Daml template/interface reference.
type Token ¶
type Token interface {
// GetTokenConfigCID returns the active TokenConfig contract ID for the given token symbol.
GetTokenConfigCID(ctx context.Context, tokenSymbol string) (string, error)
// Mint mints tokens using TokenConfig.IssuerMint and returns the created holding contract ID.
Mint(ctx context.Context, req *MintRequest) (string, error)
// Burn burns tokens using TokenConfig.IssuerBurn.
Burn(ctx context.Context, req *BurnRequest) error
// GetHoldings returns holdings for the owner and token symbol.
// Delegates to GetHoldingsByParty using the Splice HoldingV1 interface.
GetHoldings(ctx context.Context, ownerParty string, tokenSymbol string) ([]*Holding, error)
// GetHoldingsByParty queries all Splice HoldingV1 holdings visible to the given party,
// optionally filtered by instrumentID (empty string returns all instruments).
// This is the unified query path for all Splice-compliant tokens (CIP-56 and external).
GetHoldingsByParty(ctx context.Context, ownerParty, instrumentID string) ([]*Holding, error)
// GetAllHoldings returns all CIP56Holding contracts queried as IssuerParty.
// Used by the indexer and totalSupply — does NOT use the unified HoldingV1 path.
GetAllHoldings(ctx context.Context) ([]*Holding, error) // TODO: use pagination
// GetBalanceByFingerprint returns the owner's total balance (sum of holdings) for the token symbol.
GetBalanceByFingerprint(ctx context.Context, fingerprint string, tokenSymbol string) (string, error)
// GetBalanceByPartyID returns the owner's total balance (sum of holdings) for the token symbol.
GetBalanceByPartyID(ctx context.Context, partyID string, tokenSymbol string) (string, error)
// GetTotalSupply returns the total supply (sum across all holdings) for the token symbol.
GetTotalSupply(ctx context.Context, tokenSymbol string) (string, error)
// TransferByFingerprint transfers tokens by resolving fingerprints to parties.
// idempotencyKey is used as the Canton CommandId for idempotent submission.
TransferByFingerprint(ctx context.Context, idempotencyKey, fromFingerprint, toFingerprint, amount, tokenSymbol string) error
// TransferByPartyID transfers tokens by party IDs using Interactive Submission.
// idempotencyKey is used as the Canton CommandId for idempotent submission.
// Requires a KeyResolver configured via WithKeyResolver (external/secp256k1 parties only).
TransferByPartyID(ctx context.Context, idempotencyKey, fromParty, toParty, amount, tokenSymbol string) error
// TransferInternalByPartyID transfers tokens for an internal Canton party using
// regular command submission (SubmitAndWaitForTransaction). Unlike TransferByPartyID,
// no KeyResolver is required — the Canton node holds the signing key. Use this for
// issuer or bridge parties that are not registered with an external secp256k1 key.
// idempotencyKey is used as the Canton CommandId for idempotent submission.
TransferInternalByPartyID(ctx context.Context, idempotencyKey, fromParty, toParty, amount, tokenSymbol string) error
// GetTokenTransferEvents returns all active CIP56.Events.TokenTransferEvent contracts visible to relayerParty.
GetTokenTransferEvents(ctx context.Context) ([]*TokenTransferEvent, error)
// GetTransferFactory returns the active CIP56TransferFactory contract ID and its
// CreatedEventBlob for explicit contract disclosure by external wallets (Splice Registry API).
GetTransferFactory(ctx context.Context) (*TransferFactoryInfo, error)
// PrepareTransfer builds a Canton transaction for a non-custodial transfer and returns
// the hash that the client must sign externally.
PrepareTransfer(ctx context.Context, req *PrepareTransferRequest) (*PreparedTransfer, error)
// ExecuteTransfer completes a previously prepared transfer using the client's DER signature.
ExecuteTransfer(ctx context.Context, req *ExecuteTransferRequest) error
// FindPendingInboundTransferInstructions returns contract IDs of active TransferOffer contracts
// where partyID is an observer (i.e. the receiver). Used by the accept worker to find offers
// to accept on behalf of custodial parties.
FindPendingInboundTransferInstructions(ctx context.Context, partyID string) ([]string, error)
// AcceptTransferInstruction accepts a pending inbound transfer for a custodial party.
// Calls the registrar's accept choice-context endpoint (keyed by instrumentAdmin), encodes
// the AnyValue choiceContext, and exercises TransferInstruction_Accept via SubmitAndWait.
AcceptTransferInstruction(ctx context.Context, partyID, instructionCID, instrumentAdmin string) error
// PrepareAcceptTransfer builds a Canton transaction for accepting a pending inbound
// transfer instruction and returns the hash that the client must sign externally.
// Use ExecuteTransfer to complete the accept once the client has signed.
PrepareAcceptTransfer(
ctx context.Context, partyID, instructionCID, instrumentAdmin string,
) (*PreparedTransfer, error)
}
Token defines CIP-56 token operations.
type TokenTransferEvent ¶
type TokenTransferEvent struct {
ContractID string
Issuer string
FromParty string // empty = mint (no sender)
ToParty string // empty = burn (no receiver)
Amount string
InstrumentAdmin string
InstrumentID string
Timestamp time.Time
Meta map[string]string // bridge context; nil for native ops
AuditObservers []string
}
TokenTransferEvent is a decoded representation of a CIP56.Events.TokenTransferEvent. Unified event for all token mutations (mint, burn, transfer). See canton-erc20 repository: daml/cip56-token/src/CIP56/Events.daml
func (*TokenTransferEvent) EventType ¶
func (e *TokenTransferEvent) EventType() EventType
EventType derives the event type from fromParty/toParty.
func (*TokenTransferEvent) EvmDestination ¶
func (e *TokenTransferEvent) EvmDestination() string
EvmDestination returns the bridge withdrawal address from metadata.
func (*TokenTransferEvent) EvmTxHash ¶
func (e *TokenTransferEvent) EvmTxHash() string
EvmTxHash returns the bridge deposit tx hash from metadata.
func (*TokenTransferEvent) UserFingerprint ¶
func (e *TokenTransferEvent) UserFingerprint() string
UserFingerprint returns the bridge audit fingerprint from metadata.
type TransferFactoryInfo ¶
type TransferFactoryInfo struct {
ContractID string
CreatedEventBlob []byte
TemplateID TemplateIdentifier
}
TransferFactoryInfo contains the CIP56TransferFactory contract details required by external wallets for Splice-compliant explicit contract disclosure.