External Signers & Raw Tx
toRawTx() to hand a built transaction to an external signer or existing RPC client — a synchronous ethers/viem/web3.js request (EvmRawTx) on EVM, or the underlying @solana/web3.js Transaction on Solana.
toRawTx() is the lowest-level handoff: it hands a transaction you built with wative-core to your own signer or RPC client, so you can slot it into an existing ethers / viem / @solana/web3.js stack. Neither form signs or broadcasts.
toRawTx() is deliberately not on the shared Transaction interface, because the two chains do not share its contract — EVM's is a synchronous pure read, while Solana's builds (possibly fetching a blockhash), caches, seals the transaction's fields, and returns a live object by reference. Hold the concrete EvmTransaction / SvmTransaction type (which buildTransaction() returns) to call it — a value typed only as Transaction will not expose it.
EVM — EvmTransaction.toRawTx()
Synchronous. Returns a plain EvmRawTx (the TransactionRequest shape every major EVM client consumes). It returns whatever fields are currently set; fields not yet resolved (nonce, gasLimit, the gas-price family) are simply omitted, leaving your consumer to auto-fill them from its own provider. It does not mutate, sign, or hit the network.
const evm = acc.wallets[0].evm;
const tx = await evm.buildTransaction({
to: "0x1234567890123456789012345678901234567890",
value: 1_000_000_000_000_000n,
chainId: 1,
});
const raw = tx.toRawTx(); // synchronous — EvmRawTx
// Hand it to ethers, viem, web3.js, or raw JSON-RPC:
const response = await ethersWallet.sendTransaction(raw);EvmRawTx
| Field | Type | Always present? |
|---|---|---|
from | string | yes |
to | string | yes |
value | bigint | yes |
data | string | yes |
type | EvmTxType | yes |
chainId | ChainId | yes |
nonce | number | only if set |
gasPrice | bigint | only if set |
maxFeePerGas | bigint | only if set |
maxPriorityFeePerGas | bigint | only if set |
rpcUrl | string | only if set |
gasLimit | bigint | only if set |
accessList | ReadonlyArray<{ address: string; storageKeys: ReadonlyArray<string> }> | only if set |
Solana — SvmTransaction.toRawTx()
Asynchronous. Returns the underlying @solana/web3.js Transaction, fully populated with its instructions, fee payer, and recentBlockhash. You can sign it with your own Keypair, append instructions, or route it through your own RPC. It does not sign or broadcast.
const svm = acc.wallets[0].svm;
const tx = svm.buildTransaction({ recipient, amount: 5000n });
const built = await tx.toRawTx(); // @solana/web3.js Transaction
// Sign and send it with your own stack:
built.partialSign(myKeypair);
const sig = await connection.sendRawTransaction(built.serialize());Because Solana's toRawTx() builds the transaction, calling it also seals the SvmTransaction's fields — they can no longer be reassigned afterwards (build a new transaction to change one). The object it returns is the live built transaction, handed back by reference.
External fee payer
SvmTransaction.sign() can only produce the from account's signature and refuses a distinct feePayer. For a sponsored / relayer flow, take the raw transaction and have the external fee payer sign it there:
const tx = new SvmTransaction({
from: senderPubkey,
recipient,
amount: 5000n,
feePayer: relayerPubkey, // distinct from `from`
recentBlockhash,
});
const built = await tx.toRawTx(); // sign() would refuse this feePayer; toRawTx does not
built.partialSign(relayerKeypair); // fee payer signs externally
built.partialSign(senderKeypair);Offline Solana handoff with recentBlockhash
Solana's toRawTx() needs a recentBlockhash at build time. Supply one in the constructor and it can produce the @solana/web3.js Transaction with no bound address and no RPC call — the whole point of a raw-tx handoff. Without a supplied blockhash, it needs a bound address so it can fetch one over RPC.
import { SvmTransaction } from "wative-core";
const tx = new SvmTransaction({
from: "SenderPubkey…",
recipient: "RecipientPubkey…",
amount: 5000n,
recentBlockhash: "9xQe…recentBlockhash", // makes the build fully offline
});
const built = await tx.toRawTx(); // no Address, no network