Create a transaction
Overview
This guide describes how to create and send transactions to the blockchain using MPC (multi-party computation).
In the MPC Solution, every transaction is created through an MPC SDK call. The SDK supports the following operation types:
- Transfer: the default type, used for transferring assets like RON and ERC20 tokens from one source to one destination.
- Contract call: Directly call any method of a smart contract.
- Sign: Sign a message with the standard Ethereum prefix.
- Approve: Approve an ERC20 asset 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 an MPC wallet.
- Register the smart contracts with which your game needs to interact. All requests to unregistered contracts are denied.
- For new developers, the system sets payment limits for specific ERC20 tokens and native tokens. You can increase these limits by implementing additional security measures, such as MFA (multi-factor authentication).
Transfer RON
Transfer the RON token from one address to another.
- Core
- Providers
- Unity
To transfer RON using mpcCore
, call the transferNativeToken
function.
const txData = await mpcCore.transferNativeToken(accessToken, privateKeyShard, txJSON);
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. For more information, see Transaction JSON.
This example shows how to transfer 10 RON to another address:
const accessToken = `${ACCESS_TOKEN}`;
const privateKeyShard = `${PRIVATE_KEY}`;
const receiver = "0xcd3cf91e7f0601ab98c95dd18b4f99221bcf0b20";
const amount = "0x8ac7230489e80000"; // 10 RON
const toAddress = "0xcd3cf91e7f0601ab98c95dd18b4f99221bcf0b10";
const txJSON = {
to: toAddress,
value: amount
};
const txHash = await mpcCore.transferNativeToken(accessToken, privateKeyShard, txJSON);
console.log(txHash); // Transaction hash
mpcProvider
inherits the sendTransaction
method from other providers, such as Ethers.js and Web3.js, simplifying transaction execution with MPC for experienced developers.
const txData = await mpcProvider.getSigner().sendTransaction({
to: toAddress,
value: rawAmount
});
This example shows how to transfer 10 RON to another address:
const toAddress = "0xcd3cf91e7f0601ab98c95dd18b4f99221bcf0b20";
const amount = "0x8ac7230489e80000"; // 10 RON
const txData = await mpcProvider.getSigner().sendTransaction({ to: toAddress, value: amount });
To transfer RON, use the TransferNativeToken
method:
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 ERC20 token
Transfer an ERC20 token, such as AXS, from one address to another.
- Core
- Providers
- Unity
To transfer an ERC20 token using mpcCore
, call the transferERC20Token
function:
const txData = await mpcCore.transferERC20Token(accessToken, privateKeyShard, contractAddress, receiverAddress, amount)
This example shows how to transfer 1 AXS to another aaddress:
const accessToken : string = `${ACCESS_TOKEN}`;
const privateKeyShard : string = `${PRIVATE_KEY}`;
const contractAddress : string = "0x3c4e17b9056272ce1b49f6900d8cfd6171a1869d"; // AXS contract
const amount : string = "0xde0b6b3a7640000"; // 1 AXS
const address : string = '0xcd3cf91e7f0601ab98c95dd18b4f99221bcf0b20';
const txData = await mpcCore.transferERC20Token(accessToken, privateKeyShard, contractAddress, receiverAddress, amount);
mpcProvider
inherits the transfer
function from other providers, such as Ethers.js or Web3.js.
// Create a contract instance using Ethers.js
import { Contract } from "ethers";
const contract = new Contract(contractAddress, ABI, mpcProvider.getSigner());
// Transfer - function of smart contract
const txData = await contract.transfer(toAddress, amount);
This example shows how to transfer 1 AXS to another address:
const toAddress = "0xcd3cf91e7f0601ab98c95dd18b4f99221bcf0b20";
const amount = "0xde0b6b3a7640000"; // 1 AXS
const txData = await contract.transfer(toAddress, amount);
To transfer an ERC20 token, use the TransferERC20Token
method:
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 ERC20: {JsonConvert.SerializeObject(error)}");
}
else
{
Debug.Log($"Transaction hash of transferring 1 AXS: {txHash}");
}
Approve ERC20 token
Authorize a smart contract to spend a specific amount of an ERC20 token, such as AXS.
- Core
- Providers
- Unity
To approve an ERC20 token using mpcCore
, call the approveERC20Token
function:
const approveTx = await mpcCore.approveERC20Token(accessToken, privateKeyShard, contractAddress, spenderAddress, amount);
This example shows how to approve a smart contract to spend 1 AXS:
const accessToken : string = `${ACCESS_TOKEN}`;
const privateKeyShard : string = `${PRIVATE_KEY}`;
const contractAddress : string = "0x3c4e17b9056272ce1b49f6900d8cfd6171a1869d"; // AXS contract
const spenderAddress : string = "0xcd3cf91e7f0601ab98c95dd18b4f99221bcf0b20";
const amount : string = "0xde0b6b3a7640000"; // 1 AXS
const approveTx = await mpcCore.approveERC20Token(accessToken, privateKeyShard, contractAddress, spenderAddress, amount);
Invoke the approve
ERC20 function through mpcProvider
:
// Create a contract using Ethers.js
import { Contract } from "ethers";
...
const contract = new Contract(contractAddress, ABI, mpcProvider.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:
import { MpcCore, MpcProviders } from "sm-mpc";
const contractAddress = "0x3c4e17b9056272ce1b49f6900d8cfd6171a1869d"; // AXS contract
const ABI = `${AXS_ABI}`;
const mpcProvider = MpcProviders.create(
"wss://project-x.skymavis.one/",
"https://saigon-testnet.roninchain.com/rpc",
2021,
;)
const spender = "0xcd3cf91e7f0601ab98c95dd18b4f99221bcf0b20";
const approveAmount = "0xde0b6b3a7640000"; // 1 AXS
// Create a contract instance
const contract = new Contract(contractAddress, ABI, mpcProvider.getSigner());
// Use approve() in contract
const approveTxHash = await contract.approve(spender, approveAmount);
//...
To approve a token to spend an amount of ERC20 tokens, use the ApproveERC20Token
method:
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 ERC20: {JsonConvert.SerializeObject(error)}");
}
else
{
Debug.Log($"Transaction hash of approving 1 AXS: {txHash}");
}
Call contract function
You can call any function of a smart contract using the MPC SDK.
- Core
- Providers
- Unity
To invoke a contract call using mpcCore
, call the callContract
function:
const contract = await mpcCore.callContract(accessToken, privateKeyShard, txJSON);
// Call function in smart contract
contract.functionName(args);
You can choose to manually construct a txJSON
object based on the EVM standard, or let the SDK fill in the transaction parameters automatically. For more information, see Transaction JSON.
This example shows how to call a function (submit_numbers(uint8[],uint256[])
) from a contract with specific parameters (submit_numbers([12],[1])
):
const accessToken = `${ACCESS_TOKEN}`;
const privateKeyShard = `${PRIVATE_KEY}`;
const contractAddress = "0xaeD7F0FaEc15981835aaAeEd9c8D21327385743e";
const ABI = {
...
{
inputs: [
{
internalType: "uint8[]",
name: "numbers",
type: "uint8[]",
},
{
internalType: "uint256[]",
name: "points",
type: "uint256[]",
},
],
name: "submit_numbers",
outputs: [],
stateMutability: "payable",
type: "function"
},
...
};
const voidSigner = new ethers.VoidSigner(contractAddress, mpcProvider);
const contract = new ethers.Contract(contractAddress, ABI, voidSigner);
const unsignTx = await contract.populateTransaction.submit_numbers([1], [1]);
const txJSON = {
"data": unsignTx.data, // unsignTx.data return data hex value from ABI transactsion
"gas": ..,
"gasPrice": ...,
"nonce": ...,
"to": ${Contract_Addess},
"value": "0xde0b6b3a7640000", // 1 RON
"r": "0x0",
"v": "0x0",
"s": "0x0",
"chainId": ...,
};
const txData = await mpcCore.callContract(accessToken, privateKeyShard, txJSON);
console.log(tx.data.txHash);
Before invoking a contract call using mpcProvider
, you need to compute the input field, including the function selector and parameters.
const contract = new Contract(contractAddress, ABI, mpcProvider.getSigner());
Refrain from invoking the transfer()
and approve()
ERC20 functions directly within contract calls.
This example shows how to call a 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 , mpcProvider.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
The MPC SDK exclusively supports signing string-type messages.
- Core
- Providers
- Unity
To sign a message using mpcCore
, use the private key shard correspondent to the public address that you generated in Create an MPC wallet, as well as the user's access token after they signed in with their Sky Mavis account.
const result = await mpcCore.signMessage(accessToken, privateKeyShard, message);
Example:
const accessToken = `${ACCESS_TOKEN}`;
const privateKeyShard = `${PRIVATE_KEY}`;
// "Sign this message to breed Axie #223495 with Axie #123232"
const encodedMessage = "U2lnbiB0aGlzIG1lc3NhZ2UgdG8gYnJlZWQgQXhpZSAjMjIzNDk1IHdpdGggQXhpZSAjMTIzMjMy";
const result = await mpcCore.signMessage(accessToken, privateKeyShard, encodedMessage);
//...
Before signing a message, ensure it's encoded to the Base64 format.
To sign a message using mpcProvider
, call the signMessage
function:
const txHash = await mpcProvider.getSigner().signMessage(message);
Example:
// "Sign this message to breed Axie #223495 with Axie #123232"
const encodedMessage = "U2lnbiB0aGlzIG1lc3NhZ2UgdG8gYnJlZWQgQXhpZSAjMjIzNDk1IHdpdGggQXhpZSAjMTIzMjMy"
const txHash = await mpcProvider.getSigner().signMessage(encodedMessage);
//...
To sign a messasge, use the SignMessage
method:
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)}");
}