TransactionBuilder allows you to orchestrate complex account management and state changes. Understanding how these actions execute is critical for writing safe smart contracts and scripts.
1. Atomicity & Execution
All actions added to a single transaction are executed sequentially as one atomic unit on-chain:- If all actions succeed, the state changes produced by those actions are committed and any promises (cross-contract calls) they created are emitted.
- If any action fails (e.g. a function call panics, a transfer hits insufficient balance, etc.), the entire transaction is reverted.
2. The “Factory” Pattern (Batching)
Because of the atomicity rules above, we can safely use the “Factory” pattern: creating a new sub-account, funding it, deploying a contract to it, and initializing that contract—all in one transaction.3. Managing Access Keys
NEAR has a unique permission system based on Access Keys. You can add multiple keys to a single account with different permission levels.Adding a Restricted Key (FunctionCall)
This is how “Sign in with NEAR” works. You create a key that can only call specific methods on a specific contract. It cannot transfer NEAR.The
allowance is a specific amount of NEAR set aside strictly for gas fees. It cannot be transferred or withdrawn. If the key uses up this allowance, it will be deleted automatically.Rotating Keys (Security)
To rotate keys (e.g., for security hygiene), you add a new key and delete the old one in the same transaction. This prevents you from locking yourself out.4. Staking
You can stake NEAR natively with a validator to earn rewards.To unstake, you typically need to call function methods (
unstake, withdraw) on the staking pool contract rather than using a native action.5. Deleting Accounts
You can delete an account to recover its storage rent (the NEAR locked to pay for its data). The account passed to.transaction() is the account being deleted, and the beneficiary receives the remaining NEAR balance.
6. Transaction Lifecycle & Finality
When you call.send(), you can control exactly when near-kit returns using the waitUntil option.
The Lifecycle
- Validation: RPC checks structure.
- Inclusion: The transaction hits a validator node. Signature is checked, gas is pre-paid, nonce is updated.
- Execution: The receipt is processed. If it’s a function call, the VM runs.
- Finalization: The block containing the transaction is finalized by consensus.
waitUntil Options
You can pass these options to .send({ waitUntil: "..." }).
EXECUTED_OPTIMISTIC (Default)
- Returns: When the entire chain of receipts finishes execution.
- Data: Full logs and return values are available.
INCLUDED
- Returns: When the transaction is in a block.
- Data: No return values or logs are available yet.
FINAL
- Returns: When the block containing the last receipt is finalized.
- State: 100% irreversible.