Skip to main content
Version: 2.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 AVN_API = require('avn-api');
const axios = require('axios');

const AVN_GATEWAY_URL = 'https://...';
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() {
api = new AVN_API(); // We assume the AVN_SURI of the payer is already set
await api.init();

// 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 = api.proxy.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_api = new AvnApi(null, { suri: USER_SEED });
await user_api.init();

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

return user_api.proxy.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();