Skip to main content

Gas Vouchers

Vouchers empower users with gas-free interactions, allowing seamless messaging to specific programs from any actor.

An example of using vouchers is shown in the Battleship game. Users without tokens on their balance can make moves by sending messages to a program using a voucher.

Issue a Voucher

Use the api.voucher.issue method to issue a new voucher for a user, which can be used to pay for sending messages to programs.

import { VoucherIssued } from '@gear-js/api';

const programs = ['0x1234...', '0x5678...'];
const spenderAddress = '0x...';
const validForOneHour = (60 * 60) / 3; // number of blocks in one hour

const { extrinsic } = await api.voucher.issue(spenderAddress, 100 * 10 ** 12, validForOneHour, programs, true);

// To enable the voucher for code uploading, set the last argument of the `.issue` method to true.

extrinsic.signAndSend(account, ({ events }) => {
const voucherIssuedEvent = events.find(({event: { method }}) => method === 'VoucherIssued')?.event as VoucherIssued;

if (voucherIssuedEvent) {
console.log(voucherIssuedEvent.toJSON());
}
})

Check Voucher Existence

The api.voucher.exists method verifies the existence of a voucher for a specific user and program. It returns a boolean value indicating whether the voucher exists.

const voucherExists = await api.voucher.exists(accountId, programId)

Retrieve All Vouchers for an Account

The api.voucher.getAllForAccount method retrieves an object in which the key is the voucher ID and the value is an array of programs for which the voucher can be utilized.

const allVouchers = await api.voucher.getAllForAccount(accountId);

Get voucher details

const details = api.voucher.details(spenderAddress, voucherId);
console.log(`Voucher details:
owner: ${details.owner}
programs: ${details.programs}
expiry: ${details.expiry}`);

Send a Message Using the Issued Voucher

To send a message with a voucher, you can use the api.voucher.call method.

const messageTx = api.message.send({
destination: destination,
payload: somePayload,
gasLimit: 10000000,
value: 1000
}, meta);

const voucherTx = api.voucher.call(voucherId, { SendMessage: messageTx });
await voucherTx.signAndSend(account, (events) => {
console.log(events.toHuman());
});

Send a Reply with an Issued Voucher

Sending a reply with an issued voucher works in the same way as sending a message with a voucher.

const messageTx = api.message.sendReply(...);

const voucherTx = api.voucher.call(voucherId, { SendReply: messageTx });
await voucherTx.signAndSend(account, (events) => {
console.log(events.toHuman());
});

Upload Code with an Issued Voucher

const { extrinsic } = await api.code.upload(code);

const tx = api.voucher.call(voucherId, { UploadCode: extrinsic })
await tx.signAndSend(account, (events) => {
console.log(events.toHuman());
});

Update a Voucher

The api.voucher.update method can be used to update a voucher. All parameters in the third argument are optional; however, at least one parameter must be specified.

const tx = await api.voucher.update(
spenderAddress,
voucherId,
{
moveOwnership: newOwnerAddress, // The new voucher owner
balanceTopUp: 1_000 * 10 ** 12, // Top up voucher balance
appendPrograms: ['0x9123...', '0x4567...'], // Append programs for which the voucher can be used
prolongValidity: 1_000_000 // Prolong the voucher validity for 1_000_000 blocks
}
)

Revoke a Voucher

The api.voucher.revoke method is used to revoke an issued voucher. A voucher can only be revoked after its validity period has expired. Unused funds are returned to a voucher issuer.

const tx = api.voucher.revoke(spenderAddress, voucherId);
tx.signAndSend(...);

Decline a Voucher

The api.voucher.decline method can be used to decline an existing voucher that has not yet expired. This action will mark the voucher as expired so you will be able to Revoke it.

const tx = api.voucher.decline(voucherId);
tx.signAndSend(...);

Get Voucher Constants

// Minimum and maximum duration of the voucher in blocks
const minBlocks = await api.voucher.minDuration();
const maxBlocks = await api.voucher.maxDuration();

// Maximum amount of programs that can be added to the voucher
const maxProgramsAmount = await api.voucher.maxProgramsAmount();