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