@futureverse/transact
Higher-level API for building, sponsoring, and submitting transactions on TRN — handles fee proxying, futurepass proxy wrapping, and gasless flows.
Futureverse winddown
Futureverse (the publisher of @futureverse/*) is in winddown. The hosted services this package talked to (auth.futureverse.app, pass-api.futureverse.app, signer.futureverse.app) have been re-hosted by gen3labs at futurepass.gen3labs.tech (issuer) and fpsigner.gen3labs.tech (signer). For new projects, switch to the matching @gen3labs/* package — drop-in surface, default URLs already point at the gen3labs infra. The Asset Register API has no community replacement yet; see the Migration playbook for the per-package map.
- Version
0.8.0- Published
- 2025-08-14
- License
- n/a
- Status
fv-winddown- npm
- https://www.npmjs.com/package/@futureverse/transact
- Types
./index.d.ts- Maintainers
- admin-futureverse, garethdainesnpm, jcsanpedro
- Depends on
viem·@polkadot/api·@polkadot/util·@polkadot/types·@futureverse/signer·ripple-binary-codec·@polkadot/util-crypto·@therootnetwork/api-types- Recent versions
0.6.0·0.6.1·0.7.0·0.7.1·0.7.0-beta.0·0.7.0-beta.1·0.7.2·0.8.0
Why use it
You want one method to "send this call" without manually choosing between EVM eth_sendTransaction, Substrate signAndSend, FuturePass proxyExtrinsic, or FeeProxy callWithFeePreferences. Especially valuable when the user is signed in via FuturePass (custodial) — transact routes the call through the right precompile/pallet.
When to skip it
You only ever call vanilla EVM contracts with a wallet-held key. Then plain viem writeContract is simpler.
Pairs with
@futureverse/transact-react— React hooks@futureverse/auth— session source@futureverse/signer— signing
Alternatives
@gen3labs/futurepass-transact(fork-active) —@therootnetwork/extrinsic(trn-active) — lower-level, Substrate-only
Example
import { TransactClient } from '@futureverse/transact';
const client = new TransactClient({ chain: 'root', signer });
const result = await client.send(
client.tx.assets.transfer({ assetId: 2, to: recipient, amount: 1_000_000n }),
{ feePreference: { assetId: 1 } } // pay in ROOT
);Gotchas
- When the signer is a FuturePass session, the call is wrapped in
futurepass.proxyExtrinsicautomatically — make sure the FuturePass owns the funds you’re moving. - Fee preference defaults to native XRP unless overridden.
Upstream README
Futureverse Transact Library
An API to help facilitate transactions on The Root Network
Installation
NPM:
npm install @futureverse/transact --saveYarn:
yarn add @futureverse/transactDependancies
{
"@futureverse/signer": "0.6.6",
"@polkadot/api": "^10.13.1",
"@polkadot/util": "^12.6.2",
"@polkadot/util-crypto": "^12.6.2",
"@polkadot/types": "^10.13.1",
"@therootnetwork/api-types": "^1.0.3",
"viem": "^2.18.1"
}Usage
This example shows how to mint an NFT on a Root Network Collection
import { useAuth, useFutureverseSigner } from '@futureverse/auth-react';
import { TransactionBuilder } from '@futureverse/transact';
import { useTrnApi } from '@futureverse/transact-react';
const { userSession } = useAuth();
const [builder, setBuilder] = useState();
const signer = useFutureverseSigner();
const { trnApi } = useTrnApi();
const triggerInit = useCallback(async () => {
if (!trnApi || !signer || !userSession) {
return null;
}
const nftBuilder = await TransactionBuilder.nft(trnApi, signer, userSession.eoa, 709732).mint({ quantity: 1, walletAddress: userSession?.futurepass });
setBuilder(nftBuilder);
}, [trnApi, signer, userSession]);
const signExtrinsic = useCallback(async () => {
if (builder) {
const result = await builder?.signAndSend({ onSign, onSend });
setResult(result as ExtrinsicResult);
}
}, [builder, onSend, onSign, toSign]);
return (
<>
<button
onClick={() => {
triggerInit();
}}
>
Mint 1 Nft
</button>
<button
onClick={() => {
signExtrinsic();
}}
>
Sign & Send
</button>
</>
);This example shows how to transfer a token to an wallet address on a Root Network Collection, but minting using the Fee Proxy to pay for gas with a chosen token.
import { useAuth, useFutureverseSigner } from '@futureverse/auth-react';
import { TransactionBuilder } from '@futureverse/transact';
import { useTrnApi } from '@futureverse/transact-react';
const { userSession } = useAuth();
const [builder, setBuilder] = useState();
const signer = useFutureverseSigner();
const { trnApi } = useTrnApi();
const triggerInit = useCallback(async () => {
if (!trnApi || !signer || !userSession) {
return null;
}
const nftBuilder = await TransactionBuilder.transfer({ destinationAddress: userSession?.futurepass, amount: 1 }).addFeeProxy({ assetId: ROOT_TOKEN_ID, slippage: 5 });
setBuilder(nftBuilder);
}, [trnApi, signer, userSession]);
const signExtrinsic = useCallback(async () => {
if (builder) {
const result = await builder?.signAndSend({ onSign, onSend });
setResult(result as ExtrinsicResult);
}
}, [builder, onSend, onSign, toSign]);
return (
<>
<button
onClick={() => {
triggerInit();
}}
>
Mint 1 Nft
</button>
<button
onClick={() => {
signExtrinsic();
}}
>
Sign & Send
</button>
</>
);This example shows how to mint an NFT on a Root Network Collection, but minting using the FuturePass to pay the gas.
import { useAuth, useFutureverseSigner } from '@futureverse/auth-react';
import { TransactionBuilder } from '@futureverse/transact';
import { useTrnApi } from '@futureverse/transact-react';
const { userSession } = useAuth();
const [builder, setBuilder] = useState();
const signer = useFutureverseSigner();
const { trnApi } = useTrnApi();
const triggerInit = useCallback(async () => {
if (!trnApi || !signer || !userSession) {
return null;
}
const nftBuilder = await TransactionBuilder.nft(trnApi, signer, userSession.eoa, 709732).mint({ quantity: 1, walletAddress: userSession?.futurepass }).addFuturePass(userSession.futurepass);
setBuilder(nftBuilder);
}, [trnApi, signer, userSession]);
const signExtrinsic = useCallback(async () => {
if (builder) {
const result = await builder?.signAndSend({ onSign, onSend });
setResult(result as ExtrinsicResult);
}
}, [builder, onSend, onSign, toSign]);
return (
<>
<button
onClick={() => {
triggerInit();
}}
>
Mint 1 Nft
</button>
<button
onClick={() => {
signExtrinsic();
}}
>
Sign & Send
</button>
</>
);This example shows how to batch multiple transactions on The Root Network Collection together and send them using the FuturePass to pay the gas combined with the fee proxy to pay with a chosen token.
import { useAuth, useFutureverseSigner } from '@futureverse/auth-react';
import { TransactionBuilder } from '@futureverse/transact';
import { useTrnApi } from 'providers/TRNProvider';
const { userSession } = useAuth();
const [builder, setBuilder] = useState();
const signer = useFutureverseSigner();
const { trnApi } = useTrnApi();
const triggerInit = useCallback(async () => {
if (!trnApi || !signer || !userSession) {
return null;
}
const tx1 = trnApi?.tx?.nft.mint(709732, 1, eoa);
const tx2 = trnApi?.tx?.nft.mint(709732, 5, fp);
const tx3 = trnApi?.tx?.assetsExt.transfer(1, fp, 1, true);
const tx4 = trnApi?.tx?.assetsExt.transfer(2, fp, 10, true);
const tx5 = trnApi?.tx?.nft.mint(709732, 3, eoa);
const batchBuilder = await TransactionBuilder.batch(trnApi, signer, userSession.eoa).addExtrinsic(tx1).addExtrinsic(tx2).addExtrinsic(tx3).addExtrinsic(tx4).addExtrinsic(tx5).batchAll().addFuturePassAndFeeProxy({
futurePass: userSession.futurepass,
assetId: assetId,
slippage: 5,
});
setBuilder(nftBuilder);
}, [trnApi, signer, userSession]);
const signExtrinsic = useCallback(async () => {
if (builder) {
const result = await builder?.signAndSend({ onSign, onSend });
setResult(result as ExtrinsicResult);
}
}, [builder, onSend, onSign, toSign]);
return (
<>
<button
onClick={() => {
triggerInit();
}}
>
Mint 1 Nft
</button>
<button
onClick={() => {
signExtrinsic();
}}
>
Sign & Send
</button>
</>
);