Deposits and mints
The deposit
Section titled “The deposit”function deposit(uint256 units, uint8 ownerScheme, bytes32 owner) returns (uint64 nonce)function depositAtLeast(uint256 units, uint8 ownerScheme, bytes32 owner, uint256 minMinted) returns (uint64 nonce)The two are the same deposit. depositAtLeast also reverts, taking nothing, unless at least minMinted is minted:
the fee can rise with deposits that land just before, and this bounds what the depositor accepts. The web app and
the wallet always use it.
The vault:
- requires
ownerScheme ≤ 4andowner ≠ 0, andminDeposit ≤ units ≤ maxDeposit; - computes the fee and requires
minted = units − fee > 0(andminted ≥ minMinted). The fee ismax(minDepositFee, ceil(units × feeBps / 10⁴))while the whole deposit fits under half of the vault’s deposit meter, and more for the part above it (the meter counts the deposits of the last 24 hours), up tosurgeFeeBps(see the rising deposit fee); - pulls
units × scaleof the token and requires that its balance grew by exactly that amount (this refuses tokens that charge a transfer fee); - assigns the next nonce: deposits are numbered 0, 1, 2, … per vault;
- adds the fee to
feesAccruedand recordsdepositMinted[nonce] = mintedfor a possible refund; - emits the event:
event Deposit(uint64 indexed nonce, address indexed sender, uint8 ownerScheme, bytes32 owner, uint256 units, uint256 fee, uint256 minted);Every nonce is minted on Kaspa exactly once, or refunded. The minted amount is the event’s minted field,
never more.
The flow
Section titled “The flow”The mint
Section titled “The mint”BridgeMint.mint mints 1 to 3 consecutive deposits of one chain, starting exactly at that chain’s next nonce.
The covenant checks, on-chain, whoever builds the transaction:
- Minting is not paused. Every recipient has
amount > 0, a valid owner scheme, borrow scheme0x00, borrow guard of 32 zero bytes, and extension commitment of 32 zero bytes. first_nonceequals the chain’s next nonce. The nonce advances by the number of recipients.age_daais at most the age of the minter UTXO. The input’s sequence is a relative lock: consensus accepts the transaction only once the UTXO is that old, which proves the age without trusting the submitter. The spend starts a new UTXO at age zero, so a stretch of time can refill the allowance only once.- The total is at most the refilled allowance and at most
remaining(the hard cap). - Three signatures by distinct signers, in increasing signer order, over the mint digest.
- The successor BridgeMint carries exactly the updated state and the same KAS value, and each minted output is
a standard
KCC20state equal to its recipient.
mint digest = BLAKE3( "kUSDT/mint/v2" ‖ covenant_id[32] ‖ chain[1] ‖ first_nonce[8] ‖ age_daa[8] ‖ for each recipient: owner_scheme[1] ‖ owner[32] ‖ amount[8] )All integers are 8-byte little-endian. The digest binds the deployment, the chain, the nonces, every recipient and every amount, so a signature cannot be reused for anything else.
What signers check before signing
Section titled “What signers check before signing”The specification requires every signer to check every request against its own nodes, and to take nothing the coordinator says as fact. For a mint, that means a signer signs only if:
- the deposit’s block is final and every one of its EVM RPCs reports the same event, field for field (see Finality);
- the recipients and amounts in the digest equal the events’
ownerScheme,ownerandminted, nonce by nonce; - the vault’s
depositMinted(nonce), read on every RPC, is not zero, so a refunded nonce is never minted; - it has not signed a different mint starting at that nonce.
The signer does not read the next nonce from Kaspa: BridgeMint itself refuses a mint that does not start at that chain’s next nonce.
Ordering and batching
Section titled “Ordering and batching”| Rule | Effect |
|---|---|
| One chain per mint | A mint carries chain = 0x01 or 0x02, never both |
| Consecutive nonces | A batch of up to 3 deposits must be n, n+1, n+2 |
| Separate counters | nonce_ethereum and nonce_bsc advance independently |
| No skipping | A deposit cannot be passed over except by skip_nonce (4 of 5), followed by a refund |
Because mints follow the nonces strictly, a deposit that can never be minted would block every later deposit
of its chain. skip_nonce exists for that case; see Refunds.
Who pays for the minted outputs
Section titled “Who pays for the minted outputs”The minter keeps its own KAS deposit (minter.value == self.value). The covenant leaves the KAS of the new
token outputs to whoever submits the mint. In kUSDT, the coordinator’s Kaspa funding pays it, together with the
network fee, out of the deposit fee. Each minted state carries 1.5 KAS, which belongs to the holder from then on
and travels with the token. See
Storage mass.