libtokensv 0.1.0
libtokensv: ^0.1.0 copied to clipboard
BSV token scripts for libspiffy wallets, as plugins: PushDrop to start, the token format BRC-100 overlays use. Also a client for BSV overlay services (SLAP and SHIP lookup, submit).
libtokensv #
Token scripts for libspiffy wallets, as
libspiffy plugins, and a client for BSV overlay services. libspiffy itself is
not changed: the plugins go through its ScriptPlugin /
TransactionBuilderPlugin interface, as tstokenlib does.
PushDrop #
PushDrop is the token format BRC-100 overlays use (message box host advertisements, SHIP and SLAP advertisements, and others): data fields in a spendable output, locked to a key.
<lockingPublicKey> OP_CHECKSIG <field 1> ... <field n> OP_2DROP ... [OP_DROP]
PushDrop.lock and PushDrop.decode write and read these scripts exactly as
@bsv/sdk's PushDrop template does (the tests check against vectors it
wrote).
In a wallet #
Register the plugin in the isolate the libspiffy wallet runs in:
PluginRegistry().register(PushDropPlugin(network: NetworkType.MAIN));
and pay its output spec with the wallet's PayInvoiceCommand:
final spec = PushDropPlugin.outputSpec(
outputs: [PushDropOutput(lockingScript: newToken)], // tokens to make
spends: [PushDropSpend(txid: ..., vout: 0, satoshis: BigInt.one,
lockingScript: oldToken)], // tokens to spend
);
// PayInvoiceCommand(walletId: ..., invoiceId: ..., outputs: [spec], ...)
The wallet funds the fee and gets the change. Replacing a token is spending the old one and making the new one in one transaction; withdrawing one is spending it alone.
A token is spent with a signature by its locking key, which the wallet must
hold: one of its HD keys, or a BRC-42 (type-42) key it has recorded with the
coordinator's RecordType42AddressesCommand (libspiffy 5.5.0). The plugin's
extractMetadata names the address of the locking key as the token's owner,
so the wallet tracks a token locked to a key it holds as its own, without
counting it in the balance or spending it as change.
Signed fields, and the key a token is locked to #
BRC-100 tokens usually carry a signature over their fields, made with a
BRC-42 child of the identity key (createSignature), and the reference
client locks the token to that same child. A libspiffy wallet refuses to
sign data with a key it holds coins under (such a signature can be a spend
signature), so once the locking key is recorded it can no longer sign the
fields of the next token. Lock the token to a different child instead: the
overlays check the field signature, not the lock. For a message box
advertisement: fields signed with protocol [1, 'messagebox advertisement'],
key 1, counterparty anyone, as tm_messagebox verifies; the token locked
to the same protocol and key with counterparty self, recorded as the
derivation with the wallet's anchor key as both anchor and sender and the
invoice number 1-messagebox advertisement-1. Both derive from the identity,
so a restored wallet finds its tokens again.
Overlay services #
OverlayClient asks BRC-24 lookup services and submits BRC-22 transactions,
finding hosts as @bsv/sdk's LookupResolver and TopicBroadcaster do: the
hosts of a lookup service through the SLAP trackers (ls_slap), the hosts of
a topic through its SHIP advertisements (ls_ship).
final overlay = OverlayClient.forNetwork(OverlayNetwork.mainnet);
final outputs = await overlay.lookup('ls_messagebox', {'identityKey': key});
final result = await overlay.submit(beef, ['tm_messagebox']);
if (!result.acknowledgedIn('tm_messagebox')) { /* not admitted */ }