Send a transaction
Overview
This guide describes how to send transactions to the blockchain using Lockbox.
To send a transaction, make a call to the Lockbox SDK with the necessary parameters. The SDK then sends the transaction to the blockchain. The SDK supports the following types of transactions:
- Transfer tokens: the default type, used for transferring assets like the native token RON and various ERC-20 tokens from one source to one destination.
- Contract call: Directly call any function of a smart contract.
- Sign messages: Sign messages with the standard Ethereum prefix.
- Approve tokens: Approve ERC-20 tokens to be spent on another address.
When sending a transaction, you can choose how you want to manage gas fees: let the SDK estimate the fees automatically, or estimate them manually before sending the transaction. For more information, see Estimate gas.
All operations with transactions return a transaction hash. After obtaining it, you need to confirm that the transaction is successful before any further handling.
Prerequisites
Complete the steps in Create a keyless wallet.
Interact with wallets
Lockbox is EIP-1193 compliant, which means it can be used with any provider that supports this standard. The following examples show how to use Lockbox with popular libraries like ethers.js, Web3.js, and viem.
- ethers.js (v5)
- Web3.js
- viem
- Standalone
Usage with ethers.js (v5):
import * as ethers from "ethers";
const walletProvider = new ethers.providers.Web3Provider(lockbox.getProvider());
Usage with Web3.js:
import Web3 from "web3";
const walletProvider = new Web3(lockbox.getProvider());
Usage with viem:
import { createWalletClient, custom } from "viem";
import { saigon } from "viem/chains";
const walletProvider = createWalletClient({
chain: saigon,
transport: custom(lockbox.getProvider()),
});
Standalone usage:
const accounts = await lockbox.getProvider().request<string[]>({ method: "eth_requestAccounts" })
if (accounts.length) {
const balance = await lockbox.getProvider().request<string>({ method: "eth_getBalance", params: [accounts[0] as Hex, "latest"] })
}
Transfer RON
Transfer the RON token from one address to another.
- Web
- Unity
const tx = await walletProvider
.getSigner()
.sendTransaction({ to: toAddress, value: rawAmount, type: type });
You can choose to manually construct a txJSON
object based on the EVM (Ethereum Virtual Machine) standard, or let the SDK fill in the transaction parameters automatically.
This example shows how to transfer 10 RON to another address:
const amount: BigNumber = BigNumber.from(10)
const toAddress = ${RECEIVER_ADDRESS};
const tx = await walletProvider
.getSigner()
.sendTransaction({ to: toAddress, value: amount})
console.log(tx.hash); // Transaction hash
Task<(string txHash, MPCError error)> MPC.TransferNativeToken(string toAddress, string amount, string password);
This example shows how to transfer 10 RON to another address:
string toAddress = "0xedb40e7abaa613a0b06d86260dd55c7eb2df2447";
string amount = "0xde0b6b3a7640000"; // 1 RON
string password = $"{RECOVERY_PASSWORD}";
await MPC.Initialize(CreateAccessToken(userId));
var (txHash, error) = await MPC.TransferNativeToken(toAddress, amount, password);
if (error != null)
{
Debug.LogError($"Error transferring native token: {error.message}");
}
else
{
Debug.Log($"Transaction hash of transferring 1 RON: {txHash}");
}
Transfer ERC-20 token
Transfer an ERC-20 token, such as AXS, to a specified address.
- Web
- Unity
const txData = await contract.transfer(toAddress, rawAmount);
This example shows how to transfer 1 AXS to another address:
// Create a contract instance using Ethers.js
import { Contract } from "ethers";
const contractAddress = `0x3c4e17b9056272ce1b49f6900d8cfd6171a1869d`; // AXS Contract
const contract = new Contract(contractAddress, ABI, walletProvider.getSigner());
const toAddress = `${RECEIVER_ADDRESS}`;
const amount = ethers.utils.parseUnits("1", 18); // 1 AXS
// Transfer - function of smart contract
const txData = await contract.transfer(toAddress, amount);
Task<(string txHash, MPCError error)> MPC.TransferERC20Token(string tokenAddress, string toAddress, string amount, string password);
This example shows how to transfer 1 AXS to another address:
string tokenAddress = "0x3c4e17b9056272ce1b49f6900d8cfd6171a1869d"; // AXS contract
string toAddress = "0xedb40e7abaa613a0b06d86260dd55c7eb2df2447";
string amount = "0xde0b6b3a7640000"; // 1 AXS
string password = $"{RECOVERY_PASSWORD}";
var (txHash, error) = await MPC.TransferERC20Token(tokenAddress, toAddress, amount, password);
if (error != null)
{
Debug.LogError($"Error when transferring ERC-20: {JsonConvert.SerializeObject(error)}");
}
else
{
Debug.Log($"Transaction hash of transferring 1 AXS: {txHash}");
}
Approve ERC-20 token
Allow a smart contract to spend a specified amount of an ERC-20 token, such as AXS.
- Web
- Unity
Invoke the approve
ERC-20 function through walletProvider
:
// Create a contract using Ethers.js
import { Contract } from "ethers";
...
const contract = new Contract(contractAddress, ABI, walletProvider.getSigner());
// Approve - function of smart contract
const approveTX = await contract.approve(spender, amount);
This example shows how to approve a smart contract to spend 1 AXS:
const contractAddress = "0x3c4e17b9056272ce1b49f6900d8cfd6171a1869d"; // AXS contract
const ABI = `${AXS_ABI}`;
const spender = `${SPENDER_ADDRESS}`;
const approveAmount = ethers.utils.parseUnits("1", 18); // 1 AXS
// Create a contract instance
const contract = new Contract(contractAddress, ABI, walletProvider.getSigner());
// Use approve() in contract
const approveTxHash = await contract.approve(spender, approveAmount);
//...
Task<(string txHash, MPCError error)> MPC.ApproveERC20Token(string spenderAddress, string tokenAddress, string amount, string password);
This example shows how to approve a smart contract to spend 1 AXS:
string spenderAddress = "0xedb40e7abaa613a0b06d86260dd55c7eb2df2447";
string tokenAddress = "0x3c4e17b9056272ce1b49f6900d8cfd6171a1869d"; // AXS contract
string amount = "0xde0b6b3a7640000"; // 1 AXS
string password = $"{RECOVERY_PASSWORD}";
var (txHash, error) = await MPC.ApproveERC20Token(spenderAddress, tokenAddress, amount, password);
if (error != null)
{
Debug.LogError($"Error when approving ERC-20: {JsonConvert.SerializeObject(error)}");
}
else
{
Debug.Log($"Transaction hash of approving 1 AXS: {txHash}");
}
Call contract function
Call any function of a smart contract.
- Web
- Unity
Before invoking a contract call using walletProvider
, you need to compute the input field, including the function selector and parameters.
const contract = new Contract(contractAddress, ABI, walletProvider.getSigner());
Do not use the transfer()
and approve()
ERC-20 functions directly within contract calls.
This example shows how to call the function submit_numbers(uint8[],uint256[])
from a contract with specific parameters submit_numbers([12],[1])
:
const contractAddress = "0xaeD7F0FaEc15981835aaAeEd9c8D21327385743e"; // AXS
const ABI = {
...
{
inputs: [
{
internalType: "uint8[]",
name: "numbers",
type: "uint8[]"
},
{
internalType: "uint256[]",
name: "points",
type: "uint256[]"
},
],
name: "submit_numbers",
outputs: [],
stateMutability: "payable",
type: "function"
},
...
};
const contract = new Contract(contractAddress, ABI , walletProvider.getSigner());
const tx = await contract.submit_numbers([12], [1]);
To invoke a contract call, follow these steps:
- Initialize the MPC environment.
- Generate transaction calldata using one of the two ways:
- By following the Contract ABI Specification.
- By calling the SDK method
MPCUtils.CreateTxJsonInput
. For more information, see the bottom of this section.
- Call the
CallContract
method:
Task<(string txHash, MPCError error)> MPC.CallContract(string from, string to, string value, string input, string password);
Example:
string from = "0xB980D30Dc0c318BccFf6C760eDf465Fa9D2950Bd";
string to = "0xDa44546C0715ae78D454fE8B84f0235081584Fe0";
string value = "0xde0b6b3a7640000"; // 1 RON
string password = $"{RECOVERY_PASSWORD}";
string input = "0x7da5cd66000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000002082d1fedd8c2d2408c22869c49000f5e375ddbb000000000000000000000000000000000000000000000000000000006593f08b0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000a959726154953bae111746e265e6d754f48570e60000000000000000000000003c4e17b9056272ce1b49f6900d8cfd6171a1869d";
var (txHash, error) = await MPC.CallContract(from, to, value, input, password);
if (error != null)
{
Debug.LogError($"Error when calling contract: {JsonConvert.SerializeObject(error)}");
}
else
{
Debug.Log($"Transaction hash of calling contract to swap 1 RON to AXS: {txHash}");
}
How to generate transaction calldata using CreateTxJsonInput
- Encode the information about the function being called using the function selector.
- Call the
CreateTxJsonInput
method:string selector = "0xa9059cbb";
string contractAddress = "0xaeD7F0FaEc15981835aaAeEd9c8D21327385743e";
string amount = "0xde0b6b3a7640000"; // 1 RON
string calldata = MPCUtils.CreateTxJsonInput(selector, contractAddress, amount);
Sign message
Sign a string message with the standard \x19Ethereum Signed Message
prefix.
- Web
- Unity
Before signing a message, ensure it's encoded to the Base64 format.
To sign a message using walletProvider
, call the signMessage
function:
const txHash = await walletProvider.getSigner().signMessage(message);
Example:
const encodedMessage =
"Sign this message to breed Axie #223495 with Axie #123232";
const txHash = await walletProvider.getSigner().signMessage(encodedMessage);
//...
Task<(string signedMessage, MPCError error)> MPC.SignMessage(string message, string password);
Example:
string password = $"{RECOVERY_PASSWORD}";
string message = "Sign this message to breed Axie #223495 with Axie #123232";
var (data, error) = await MPC.SignMessage(message, password);
if (error != null)
{
Debug.LogError($"Error when signing message: {JsonConvert.SerializeObject(error)}");
}
else
{
Debug.Log($"Signature: {JsonConvert.SerializeObject(data)}");
}