Skip to main content
Version: 3.5.0

Split Fee Payment

This example shows how a transfer transaction can be made by a user who holds no AVT and is not connected to the gateway, by having a “payer” build, submit and pay the transaction fee on their behalf.

important

This operation uses a relayer account that the sender authorizes to submit the transfer transaction. You can learn more about relayers HERE.

You can get the AVN_GATEWAY_URL and AVN_RELAYER here.

const { AvnApi, SetupMode, SigningMode } = require("avn-api");
const axios = require('axios');
const AVN_GATEWAY_URL = "gateway url of your chosen network"
const options = {
suri: "suri of your account",
setupMode: SetupMode.SingleUser,
signingMode: SigningMode.SuriBased,
};

const USER = '5Dy6k...'; // AvN account (address or public key) of the user
const TOKEN = '0x123a...'; // Ethereum address of the token being transferred
const TRANSFER_AMOUNT = '1000000000000000';
const TRANSFER_RECEIPIENT = '5F36q...'; // AvN account of the transfer recipient
const RELAYER = '5CCv3...'; // AvN relayer the payer will be using
const PAYER = '5FQfm...'; // AvN account paying the transfer fee

let api;

async function main() {
const avnSdk = new AvnApi(AVN_GATEWAY_URL, options);
await avnSdk.init();
const api = await avnSdk.apis();

// The user's token nonce is retrieved and passed to the user:
const userNonceParams = { accountId: USER, nonceType: 'token' };
const userTokenNonce = await jsonRpcRequest('query', 'getNonce', userNonceParams);
// who then generates and returns an authorisation signature for the transfer:
const userProxySignature = userGeneratesTransferSignatureOffline(userTokenNonce);

// The payer now retrieves their own relayer fee:
const relayerFeeParams = { relayer: RELAYER, user: PAYER, transactionType: 'proxyTokenTransfer' };
const relayerFeeForPayer = await jsonRpcRequest('query', 'getRelayerFees', relayerFeeParams);
// and payment nonce:
const payerNonceParams = { accountId: PAYER, nonceType: 'payment' };
const payerPaymentNonce = await jsonRpcRequest('query', 'getNonce', payerNonceParams);
// and generates a fee payment signature:
const feePaymentParams = {
relayer: RELAYER,
user: USER,
proxySignature: userProxySignature,
relayerFee: relayerFee,
paymentNonce: paymentNonce
};
const payerFeePaymentSignature = avnSdk.proxyUtils.generateFeePaymentSignature(feePaymentParams);

// The user's transfer request can now be sent and the payer will pay the AVT fee:
const proxyTokenTransferParams = {
relayer: RELAYER,
user: USER,
payer: PAYER,
recipient: RECIPIENT,
token: TOKEN,
amount: TRANSFER_AMOUNT,
proxySignature: userProxySignature,
feePaymentSignature: payerFeePaymentSignature,
paymentNonce: payerPaymentNonce
};
await jsonRpcRequest('send', 'proxyTokenTransfer', proxyTokenTransferParams);
}

function userGeneratesTransferSignatureOffline(userTokenNonce) {
// User initialises their own offline api to access its signing functions
const USER_SEED = '0xfe45...'
let user_sdk = new AvnApi(null, { suri: USER_SEED });
await user_sdk.init();
const user_api = await user_sdk.apis();

const tokenTransferParams = {
relayer: RELAYER,
user: USER,
recipient: RECIPIENT,
token: TOKEN,
amount: TRANSFER_AMOUNT,
nonce: userTokenNonce
};

return avnSdk.proxyUtils.generateProxySignature('proxyTokenTransfer', tokenTransferParams);
}

async function jsonRpcRequest(path, method, params) {
const awtToken = api.awt.generateAwtToken();
const url = `${gateway}/${path}`;
const body = { jsonrpc: '2.0', id: 1, method, params };
const headers = { 'content-type': 'application/json', Authorization: `bearer ${awtToken}` };
const response = await axios.post(url, body, { headers });
return response.data.result;
}

if (require.main === module) main();