Skip to main content

Documentation Index

Fetch the complete documentation index at: https://www.dynamic.xyz/docs/llms.txt

Use this file to discover all available pages before exploring further.

Overview

DynamicEvmWalletClient::sendTransaction signs an EIP-1559 transaction with the MPC ceremony and broadcasts the result via JSON-RPC in one call. Returns the transaction hash as a 0x-prefixed hex string. sendTransaction is the recommended path for most apps. Reach for signTransaction only if you need the signed RLP out-of-band — co-signing, custom relayers, or assembling the raw tx yourself.

Prerequisites

Sign + Broadcast in One Call

import java.math.BigInteger;
import xyz.dynamic.waas.evm.EvmTransaction;
import xyz.dynamic.waas.evm.opts.SendTransactionOpts;

EvmTransaction tx = EvmTransaction.builder()
    .chainId(11155111L)                                  // Sepolia
    .nonce(BigInteger.ZERO)
    .maxFeePerGas(new BigInteger("10000000000"))
    .maxPriorityFeePerGas(new BigInteger("1000000000"))
    .gasLimit(new BigInteger("21000"))
    .to("0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB")
    .value(BigInteger.ZERO)
    .data("0x")
    .build();

String txHash = client.sendTransaction(SendTransactionOpts.builder()
    .transaction(tx)
    .walletProperties(walletProperties)
    .externalServerKeyShares(externalServerKeyShares)
    .rpcUrl("https://sepolia.infura.io/v3/<your-key>")
    .build()
).join();

System.out.println("Submitted tx: " + txHash);
System.out.println("Explorer: https://sepolia.etherscan.io/tx/" + txHash);
A fresh JSON-RPC client is constructed per call. For high-throughput scenarios, compose signTransaction with your own pooled Web3j instance instead.

Building the Nonce

Fetch the current pending nonce from your RPC before each send — concurrent sendTransaction calls against the same wallet without nonce coordination will conflict:
import org.web3j.protocol.Web3j;
import org.web3j.protocol.http.HttpService;
import org.web3j.protocol.core.DefaultBlockParameterName;

Web3j w3 = Web3j.build(new HttpService("https://sepolia.infura.io/v3/<your-key>"));
BigInteger nonce = w3
    .ethGetTransactionCount(walletProperties.accountAddress(), DefaultBlockParameterName.PENDING)
    .send()
    .getTransactionCount();

Gas Estimation

EIP-1559 fees vary block to block — query the latest base fee + tip estimate, then bake them into the transaction:
BigInteger baseFee  = w3.ethGetBlockByNumber(DefaultBlockParameterName.PENDING, false)
    .send().getBlock().getBaseFeePerGas();
BigInteger tip      = new BigInteger("1000000000");        // 1 gwei
BigInteger maxFee   = baseFee.multiply(BigInteger.TWO).add(tip);

Common Transaction Types

ETH Transfer

EvmTransaction transfer = EvmTransaction.builder()
    .chainId(1L)
    .nonce(nonce)
    .maxFeePerGas(maxFee)
    .maxPriorityFeePerGas(tip)
    .gasLimit(new BigInteger("21000"))
    .to("0xRecipientAddress")
    .value(new BigInteger("100000000000000000"))           // 0.1 ETH in wei
    .data("0x")
    .build();

Contract Interaction

EvmTransaction call = EvmTransaction.builder()
    .chainId(1L)
    .nonce(nonce)
    .maxFeePerGas(maxFee)
    .maxPriorityFeePerGas(tip)
    .gasLimit(new BigInteger("100000"))
    .to("0xContractAddress")
    .value(BigInteger.ZERO)
    .data("0xFunctionSelector...")
    .build();

Error Handling

import java.util.concurrent.CompletionException;
import xyz.dynamic.waas.core.exceptions.DynamicSdkException;

try {
    String txHash = client.sendTransaction(opts).join();
    log.info("Submitted: {}", txHash);
} catch (CompletionException ce) {
    if (ce.getCause() instanceof DynamicSdkException dse) {
        log.error("Send failed: {}", dse.getMessage(), dse);
    } else {
        throw ce;
    }
}
sendTransaction returns the JSON-RPC error verbatim when the broadcast itself fails (e.g. nonce too low, replacement transaction underpriced) — match on the error message or retry with a refreshed nonce.

Next Steps