Minimal React Hook (EVM)
const bridge = useCallback(async ({ amount, destinationDomain, isNative }) => {
assertWalletConnected();
const quote = await fetchEcdsaQuote({
localDomain,
destinationDomain,
isV2: true,
isNative,
});
const params = buildTransferV2Params({
amount,
destinationDomain,
quote,
isNative,
recipient: toBytes32(destinationAddress),
});
await ensureAllowance(params, isNative);
const overrides = isNative ? { value: params.fee + params.gasDropAmount } : {};
return cashmere.transferV2(params, overrides);
}, [provider, cashmere, usdc]);
Wrap the helper utilities (fetchEcdsaQuote, buildTransferV2Params, ensureAllowance) around your existing network stack so that decimals and deadlines are handled consistently.
Node.js Treasury Distributor
async function distribute({ amount, fromDomain, routes }) {
const signer = buildSigner(fromDomain);
const cashmere = loadCashmereContract(fromDomain, signer);
const usdc = loadUsdcContract(fromDomain, signer);
const allowance = computeAllowance({ amount, routes });
await usdc.approve(cashmere.target, allowance);
for (const route of routes) {
const quote = await fetchEcdsaQuote({
localDomain: fromDomain,
destinationDomain: route.domain,
isV2: true,
isNative: route.isNativeFee,
});
const params = buildTransferV2Params({ amount, quote, recipient: route.recipient });
const overrides = route.isNativeFee ? { value: params.fee + params.gasDropAmount } : {};
await cashmere.transferV2(params, overrides);
}
}
Fetch Circle’s minimumFee guidance per domain pair through https://iris-api.circle.com/v2/burn/USDC/fees/{sourceDomainId}/{destDomainId} and map the result to your maxFee / minFinalityThreshold selection.
Status Dashboard Snippet
async function fetchRecentTransfers(address) {
const url = new URL('https://kapi.cashmere.exchange/transactionsmainnet');
url.searchParams.set('senders', address);
url.searchParams.set('limit', '25');
const res = await fetch(url.toString());
if (!res.ok) throw new Error('Failed to fetch transactions');
const body = await res.json();
return body.transactions.map((tx) => ({
hash: tx.source_tx_hash,
route: `${tx.source_domain} → ${tx.destination_domain}`,
amount: Number(tx.deposit_amount) / 1e6, // display helper (USDC = 6 decimals)
relayerFee: Number(tx.relayer_fee) / 1e6,
status: tx.confirmed ? 'confirmed' : 'pending',
completed: tx.confirmed,
}));
}
Solana Transfer (Anchor)
const quote = await fetchEd25519Quote({ localDomain: 5, destinationDomain, version: 2 });
const config = await loadCashmereConfig(connection);
const signatureIx = buildEd25519Ix(quote);
const transferIx = await cashmereProgram.methods.transferV2(
new BN(amount.toString()),
destinationDomain,
toBytes(recipientAta),
toBytes(destinationOwner),
new BN(quote.fee),
new BN(quote.deadline),
new BN(gasDropLamports.toString()),
isNativeFee,
new BN(maxFee.toString()),
new BN(finalityThreshold),
).accounts(buildAccountMap({ owner, config, destinationDomain })).instruction();
const tx = assembleAndSign({
payer: owner,
ixs: [setComputeUnits(), signatureIx, transferIx],
lookupTables: [cashmereLookupTable],
additionalSigners: [cashmereMessageSigner],
});
await connection.sendAndConfirmTransaction(tx);
Sui Transfer (Transactions API)
const quote = await fetchEd25519Quote({ localDomain: 8, destinationDomain, isNative });
const tx = new Transaction();
const modules = loadSuiConstants(); // resolve module IDs & on-chain object IDs from configuration
const usdcCoin = coinWithBalance({ type: modules.usdcType, balance: burnAmountPlusGasDrop });
const nativeFeeCoin = buildNativeFeeCoin(tx, { quote, gasDropNative, isNative });
const [ticket, depositInfo] = tx.moveCall({
target: `${modules.cashmereTransfer}::prepare_deposit_for_burn_ticket`,
typeArguments: [modules.usdcType],
arguments: buildPrepareArgs({ quote, nativeFeeCoin, recipientHex, solanaOwnerHex, modules }),
});
const [burnMessage, circleMessage] = tx.moveCall({
target: `${modules.tokenMessenger}::deposit_for_burn_with_package_auth`,
typeArguments: [modules.usdcType, `${modules.cashmereTransfer}::Auth`],
arguments: buildDepositArgs({ ticket, modules }),
});
tx.moveCall({
target: `${modules.cashmereTransfer}::post_deposit_for_burn`,
arguments: [burnMessage, circleMessage, depositInfo, tx.object(modules.configId)],
});
await wallet.signAndExecuteTransaction({ transaction: tx });
recipientHex / solanaOwnerHex are 32-byte hex strings. Use left-padded bytes for EVM/Sui/Aptos destinations and the wallet public key when bridging into Solana.
- When
fee_is_native=true, convert SUI to 9-decimal “mist” and pass fee + gas_drop_amount inside nativeFeeCoin.
Aptos Transfer (ts-sdk)
const quote = await fetchEd25519Quote({ localDomain: 9, destinationDomain, isNative });
const payload = buildTransferOuterPayload({
amount,
destinationDomain,
recipientHex,
solanaOwnerHex,
quote,
isNative,
gasDropMicro,
});
// buildTransferOuterPayload should reference process.env.APTOS_CASHMERE_MODULE and USDC type constants rather than embedding literal addresses.
const tx = await aptos.transaction.build.simple({ sender, data: payload });
const signer = selectWalletSigner();
const submission = await signer.signAndSubmit(tx);
await aptos.waitForTransaction({ transactionHash: submission.hash });
recipientHex / solanaOwnerHex are 32-byte hex strings. Left-pad EVM/Aptos/Sui addresses and use the Solana wallet address only when bridging into Solana.
- Pontem expects the Ed25519 signature as a byte array;
Array.from(Buffer.from(...)) satisfies that requirement.
Always validate the deadline returned by the Gas API. If the quote is within ~30 seconds of expiring, request a fresh signature before prompting the user to sign.