2.43 FuturePass (Native API example) At a glance What it is Create a FuturePass, send an extrinsic through it, register a delegate and decode a proxy error. Futureverse’s Native API example for The Root Network, with its README and source. Where it sits Part II — Building · Chapter 2.43 Covers Examples · Source files Source github.com/futureversecom/trn-examples/tree/main/examples/substrate/use-futurepass
| At a glance | |
|---|---|
| What it is | Create a FuturePass, send an extrinsic through it, register a delegate and decode a proxy error. Futureverse’s Native API example for The Root Network, with its README and source. |
| Where it sits | Part II — Building · Chapter 2.43 |
| Covers | Examples · Source files |
| Source | github.com/futureversecom/trn-examples/tree/main/examples/substrate/use-futurepass |
Create a FuturePass, send an extrinsic through it, register a delegate and decode a proxy error. Reference: futurepass pallet.
Copied from Futureverse’s
futureversecom/trn-examples, deleted with its GitHub organisation, at commit44c9e16of 2024-10-31. Apache-2.0: license. Before you run it, read Running the examples.
You don’t need a FuturePass
This page treats FuturePass as something to use. You don’t need one: where the page uses a FuturePass, use an account in your own wallet instead — any EIP-6963 wallet app, MetaMask preferred. If you have a FuturePass, you can move what’s in it to your wallet at any time: https://root.trn.codeology.co.nz/wallet/futurepass. FuturePass explains how it works.
Offline destinations
Some places this page points to did not answer when last checked:
docs-beta.therootnetwork.com— does not resolve (checked 2026-10-18)stackblitz.com/github/futureversecom— StackBlitz loads these projects from the deleted futureversecom organisation on GitHub (checked 2026-10-18)
Run in StackBlitz (repository deleted, checked 2026-10-18) · Pallet Documentation (offline, checked 2026-10-18)
IMPORTANT
Ensure the following ENV vars are available before running the examples
CALLER_PRIVATE_KEY- Private key of an account that submits the transaction. Follow this guide to create and fund an account with some test tokens on Porcini (testnet) if you don't have one yet.
2.43.1 Examples
bash
# change your working directory to this example first
cd examples/substrate/use-futurepass
# export all required environments
export CALLER_PRIVATE_KEY=
# creates new FPass account
pnpm call:createAccount
# call an extrinsic as FPass account
pnpm call:proxyExtrinsic
# decode error when using proxyExtrinsic
pnpm call:decodeProxyError
# register a delegate to FPass account
pnpm call:registerDelegate2.43.2 Source files
src/createAccount.ts2.43.2.1
ts
import { filterExtrinsicEvents } from "@trne/utils/filterExtrinsicEvents";
import { formatEventData } from "@trne/utils/formatEventData";
import { sendExtrinsic } from "@trne/utils/sendExtrinsic";
import { withChainApi } from "@trne/utils/withChainApi";
import { Wallet } from "ethers";
/**
* Use `futurepass.create` extrinsic to create a new FPass account
*
* Assumes the caller has XRP to pay for gas, and some ROOT to reserve the account
*/
withChainApi("porcini", async (api, caller, logger) => {
const account = Wallet.createRandom();
logger.info(
{
parameters: {
account: account.address,
},
},
`create a "futurepass.create" extrinsic`
);
const extrinsic = api.tx.futurepass.create(account.address);
logger.info(`dispatch extrinsic from caller="${caller.address}"`);
const { result, extrinsicId } = await sendExtrinsic(extrinsic, caller, { log: logger });
const [createEvent] = filterExtrinsicEvents(result.events, ["Futurepass.FuturepassCreated"]);
logger.info(
{
result: {
extrinsicId,
blockNumber: result.blockNumber,
createEvent: formatEventData(createEvent.event),
},
},
"receive result"
);
});src/decodeProxyError.ts2.43.2.2
ts
import { BN, hexToU8a } from "@polkadot/util";
import { filterExtrinsicEvents } from "@trne/utils/filterExtrinsicEvents";
import { formatEventData } from "@trne/utils/formatEventData";
import { sendExtrinsic } from "@trne/utils/sendExtrinsic";
import { withChainApi } from "@trne/utils/withChainApi";
import assert from "node:assert";
/**
* Use `futurepass.proxyExtrinsic` to dispatch an extrinsic that is set to failed deliberately
* to demostrate how to extract and decode the error.
*
* Assumes the FPass account has XRP to pay for gas.
*/
withChainApi("porcini", async (api, caller, logger) => {
const fpAccount = (await api.query.futurepass.holders(caller.address)).unwrapOr(undefined);
assert(fpAccount);
logger.info(
{
futurepass: {
holder: caller.address,
account: fpAccount.toString(),
},
},
"futurepass details"
);
// force error as Asset ID 3 does not exist
const call = api.tx.assets.transfer(3, fpAccount, 1);
logger.info(
{
parameters: {
fpAccount,
call,
},
},
`create a "futurepass.proxyExtrinsic" extrinsic`
);
const extrinsic = api.tx.futurepass.proxyExtrinsic(fpAccount, call);
logger.info(`dispatch extrinsic from caller="${caller.address}"`);
const { result, extrinsicId } = await sendExtrinsic(extrinsic, caller, { log: logger });
const [executedEvent] = filterExtrinsicEvents(result.events, ["Proxy.ProxyExecuted"]);
const { err } = executedEvent.event.data[0].toJSON() as {
err: {
module: {
index: number;
error: `0x${string}`;
};
};
};
const { section, name, docs } = api.registry.findMetaError({
index: new BN(err.module.index),
error: hexToU8a(err.module.error),
});
logger.info(
{
error: {
code: `${section}.${name}`,
docs,
},
},
`proxy executed error`
);
logger.info(
{
result: {
extrinsicId,
blockNumber: result.blockNumber,
executedEvent: formatEventData(executedEvent.event),
},
},
"receive result"
);
});src/proxyExtrinsic.ts2.43.2.3
ts
import { filterExtrinsicEvents } from "@trne/utils/filterExtrinsicEvents";
import { formatEventData } from "@trne/utils/formatEventData";
import { sendExtrinsic } from "@trne/utils/sendExtrinsic";
import { withChainApi } from "@trne/utils/withChainApi";
import assert from "node:assert";
/**
* Use `futurepass.proxyExtrinsic` to call `system.remarkWithEvent` and have FPasss account
* to pay for gas.
*
* Assume FPass account of the caller has XRP to pay for gas.
*/
withChainApi("porcini", async (api, caller, logger) => {
const fpAccount = (await api.query.futurepass.holders(caller.address)).unwrapOr(undefined);
assert(fpAccount);
logger.info(
{
futurepass: {
holder: caller.address,
account: fpAccount.toString(),
},
},
"futurepass details"
);
const call = api.tx.system.remarkWithEvent("Hello World");
logger.info(
{
parameters: {
fpAccount,
call,
},
},
`create a "futurepass.proxyExtrinsic" extrinsic`
);
const extrinsic = api.tx.futurepass.proxyExtrinsic(fpAccount, call);
logger.info(`dispatch extrinsic from caller="${caller.address}"`);
const { result, extrinsicId } = await sendExtrinsic(extrinsic, caller, { log: logger });
const [proxyEvent, remarkEvent] = filterExtrinsicEvents(result.events, [
"Futurepass.ProxyExecuted",
// depending on what extrinsic call you have, filter out the right event here
"System.Remarked",
]);
logger.info(
{
result: {
extrinsicId,
blockNumber: result.blockNumber,
proxyEvent: formatEventData(proxyEvent.event),
remarkEvent: formatEventData(remarkEvent.event),
},
},
"receive result"
);
});src/registerDelegate.ts2.43.2.4
ts
import { fetchFinalisedHead } from "@trne/utils/fetchFinalisedHead";
import { filterExtrinsicEvents } from "@trne/utils/filterExtrinsicEvents";
import { formatEventData } from "@trne/utils/formatEventData";
import { sendExtrinsic } from "@trne/utils/sendExtrinsic";
import { withChainApi } from "@trne/utils/withChainApi";
import { getEthersProvider } from "@trne/utils/withEthersProvider";
import { utils as ethers, Wallet } from "ethers";
import assert from "node:assert";
enum ProxyType {
NoPermission = 0,
Any = 1,
}
withChainApi("porcini", async (api, caller, logger) => {
const provider = getEthersProvider("porcini");
const delegate = Wallet.createRandom().connect(provider);
const proxyType = ProxyType.Any;
// recommended low number, 75 blocks ~= 5 minutes
const deadline = (await fetchFinalisedHead(api)) + 75;
const fpAccount = (await api.query.futurepass.holders(caller.address)).unwrapOr(undefined);
assert(fpAccount);
logger.info(
{
futurepass: {
holder: caller.address,
account: fpAccount.toString(),
},
},
"futurepass details"
);
const message = ethers
.solidityKeccak256(
["address", "address", "uint8", "uint32"],
[fpAccount, delegate.address, proxyType, deadline]
)
.substring(2);
logger.info(
{
payload: {
fpAccount,
address: delegate.address,
proxyType,
deadline,
},
},
"require delegate to sign a payload"
);
const signature = await delegate.signMessage(message);
logger.info(
{
parameters: {
fpAccount,
address: delegate.address,
proxyType,
deadline,
signature,
},
},
`create a "futurepass.registerDelegateWithSignature" extrinsic`
);
const extrinsic = api.tx.futurepass.registerDelegateWithSignature(
fpAccount, // Futurepass account to register the account as delegate
delegate.address, // The delegated account for the futurepass
proxyType, // Delegate permission level
deadline, // Deadline for the signature
signature // Signature of the message parameters
);
const { result, extrinsicId } = await sendExtrinsic(extrinsic, caller, { log: logger });
const [delegatedEvent] = filterExtrinsicEvents(result.events, ["Futurepass.DelegateRegistered"]);
logger.info(
{
result: {
extrinsicId,
blockNumber: result.blockNumber,
delegatedEvent: formatEventData(delegatedEvent.event),
},
},
"receive result"
);
});package.json2.43.2.5
json
{
"scripts": {
"call": "tsx --tsconfig ../../../tsconfig.json",
"call:createAccount": "pnpm call src/createAccount.ts",
"call:proxyExtrinsic": "pnpm call src/proxyExtrinsic.ts",
"call:decodeProxyError": "pnpm call src/decodeProxyError.ts",
"call:registerDelegate": "pnpm call src/registerDelegate.ts"
}
}Source:
futureversecom/trn-examples, examples/substrate/use-futurepass (deleted) · commit 44c9e16, 2024-10-31 · Apache-2.0, license · part of Code examplesAssociated docs
Where else you might go from here. Following one is optional — this chapter stands without them.
- Back matter — read in order
See also— The whole of Back matter as one continuous page, reprinted from its chapters without change.- Code examples
See also— Futureverse’s code examples for The Root Network: scripts for the native API and the EVM, and two contract projects, each with its README and source.- Contents
See also— Every chapter in this book, each with the one line that tells you what you get by reading it.- Front matter — read in order
See also— The whole of Front matter as one continuous page, reprinted from its chapters without change.- FuturePass
See also— FuturePass, the on-chain identity + proxy account model Futureverse built on The Root Network: what it is, where it lives on chain, and how a holder moves what's in it to their own wallet.- FuturePass (pallet)
See also— Create a [FuturePass]learn/glossary) account for the delegator who is able to make calls on behalf of FuturePass.- Guides for the code examples
See also— How Futureverse’s TRN code examples get a test account: create one in MetaMask and fund it from the Porcini faucet.- Identity and Smart Wallet Protocols
See also— Our native identity protocol allows users to establish a persistent and secure digital identity that can be used across multiple metaverse applications and…