Shuttle Docs

sendTransaction and ethSendTransaction

Send assets; ethSendTransaction is the EVM compatibility alias.

GroupSending
RuntimesTypeScript browser/server, React client adapter, Python/Go server
Updated2026-09-16

Status and network boundary

Proposed target SDK behavior for implementation. No executable SDK or adapter coverage was verified by this revision. The planned send adapters are Ethereum, BNB Smart Chain, Solana and TRON; this is a target, not a current support claim. Address creation evidence for another network does not prove send support there.

One wallet is network-scoped. The requested network must exactly match the wallet network; this call never migrates a key/address, chooses another wallet or treats one family address as another.

Business action#

Authorize, sign and submit one high-level native or token transfer without making the application construct nonce, gas fields, recent blockhash, serialized transaction bytes or chain-specific token instruction data. An advanced EVM contract call remains a separate transaction action so the generic transfer amount is never confused with EVM value.

Proposed primary call#

sendTransaction(
  input: SendTransactionInput,
  options?: CallOptions,
): Promise<Operation<SendTransactionResult>>

TypeScript uses requestId, walletId, a discriminated network, one transaction, actor, optional bounded feeAuthorization, and optional operation-bound authorization. Exact quantities are bigint; JavaScript number, fractions and implicit unit conversion are rejected.

Go uses RequestID, WalletID, Network, Transaction, Actor and FeeAuthorization. Exact quantities use copied big.Int values. Context cancellation after dispatch makes the result unknown and requires GetOperation with the same request identity.

Transfer and advanced transaction shapes#

The ordinary transaction is one explicit transfer:

Text
{
  kind: "transfer",
  asset: { kind: "native" } | { kind: "token", assetId: <network-scoped identifier> },
  to: <validated destination for the selected network>,
  amount: <exact asset base-unit integer>
}

amount always means units of the selected asset. For a token transfer it is the token amount, not native-coin value, gas, rent or fee. The implementation resolves token decimals/contract or mint metadata from the explicit network-scoped asset identity and rejects ambiguity.

The only preserved advanced transaction action in this base target is EVM-specific:

Text
{
  kind: "evmCall",
  to: <EVM address>,
  value: <exact native base-unit integer>,
  data: <explicit bytes>
}

evmCall is valid only for Ethereum or BNB Smart Chain. There is no invented universal raw-transaction structure for Solana or TRON. Additional family-specific contract/program actions require a separate accepted contract.

EVM compatibility alias#

ethSendTransaction remains as a compatibility alias for the prior EVM method name. It accepts only an Ethereum or BNB Smart Chain wallet and the old EVM call/fee input, validates the same safe boundaries, converts it once to sendTransaction({ transaction: { kind: "evmCall", ... } }), and returns the same operation identity/result. It is not a multichain method and cannot bypass fee, policy, authorization or idempotency checks. New integrations use sendTransaction.

Fees, signing and broadcast#

The service builds the family-specific unsigned transaction only after wallet/network, destination, asset and amount validation. Its selected fee must fit the caller's explicit authorization bounds and the wallet policy; an absent bound never means unlimited fees. The operation fingerprint binds the selected network, wallet, asset, recipient, amount or EVM call, fee limits and request ID. Any material change requires new authorization.

Signing, network submission, successful execution and finality are distinct states. A transaction hash/signature proves neither execution nor finality. The result exposes chain identity only when known and retains the lifecycle evidence that the backend can actually distinguish.

Network-fee funding in v1#

No smart-wallet, account-abstraction or delegated-account mechanism is introduced. Native fee-payer sponsorship is supported only for Solana, whose protocol permits a separate fee payer. The transaction binds the wallet signer and sponsor fee payer, both required signatures, exact fee quote, maximum fee and quote expiry before approval. The sponsor uses separate treasury authorization and spending limits.

EVM v1 supports gas funding, not same-transaction sponsorship: a separately authorized treasury transfer may pre-fund or reimburse the wallet. That funding has its own requestId, policy, limit, operation and event. It never silently changes the user transaction, delegates the account, or claims a paymaster/sponsor effect. No sponsorship is promised for another network without primary protocol and adapter evidence.

Durable recovery and safe replay#

Same request ID and same immutable transaction material converges on one logical transfer; changed material conflicts. After timeout, restart or transport loss, use getOperation(requestId). The SDK may retransmit the same signed transaction only when that exact signed identity is still valid and the accepted adapter contract proves replay safe.

An expired Solana recent blockhash cannot be silently replaced: the adapter first reconciles whether the old signed transaction landed. Building with a new blockhash changes signed material and requires a new explicit authorization/operation transition defined by the future contract. Equivalent family-specific expiry, nonce and replacement rules must also fail closed; timeout never authorizes a fresh transfer.

getSendTransactionStatus remains an optional chain-detail read. Normal integrations use the durable operation result and do not need an application polling loop.

Authorization, errors and acceptance#

An action already permitted by current grants may complete automatically. Otherwise the SDK uses the mode-appropriate owner/service handler once or returns requiresAction; it cannot do both. Embedded actions use owner authority. Server-wallet payouts use the named service identity plus policy, transaction limit and required approvers. User login never grants treasury authority. Denial, expiry, insufficient agreement, wrong mode/wallet/network, unsupported asset/adapter, invalid destination, nonpositive/ambiguous amount or fee outside bounds submits nothing.

See Transactions, Approvals, getOperation, and getSendTransactionStatus.