Get started
The fastest path from nothing to a funded account that can send MNA is the CLI. It installs one binary, inter, shaped after Solana's so the commands are where you expect them.
npm install -g @intertrain-network/cli
inter config set --url mainnet
inter keygen new
inter balancekeygen new prints a recovery phrase once and writes the key to ~/.intertrain/id.json with mode 600. The phrase is shown a single time and stored nowhere — write it down before moving on.
Getting MNA
MNA is bought with USDC. Your USDC is locked on the chain it came from and the same amount appears here as wUSDC, which you then swap for MNA at a fixed 1 USDC = 1 MNA. Two steps, about two minutes.
Before you start
- A browser wallet — Rabby is the smoother one on Intertrain today; MetaMask works but prices fees oddly on new chains.
- USDC on Ethereum, and a little ETH for gas.
- Bring at least $50. Ethereum charges the same gas whether you move $5 or $5,000, so small amounts lose most of their value to fees before they arrive. This is Ethereum's cost, not ours.
1 · Add Intertrain to your wallet
Open the wallet and connect. It offers to add the network for you. Everything below happens in the Bridge window.
2 · Deposit your USDC
On the Deposit USDC tab, choose the chain your USDC is on, enter an amount, and press Deposit USDC.
Your wallet asks you to sign twice: once to approve the bridge to move your USDC, then once for the deposit itself. That is normal for any token on Ethereum. Both cost gas.
3 · Swap wUSDC for MNA
Open the wUSDC → MNA tab, enter an amount, and press Swap to MNA.
Your MNA balance updates once the swap is included in a block, usually a couple of seconds. That is the whole process — you now hold MNA.
Going the other way
The same window reverses it. MNA → wUSDC converts back at the same rate, and Withdraw burns your wUSDC and releases real USDC to your address on Ethereum, usually within a minute.
Unlike the swap in, both of these are ordinary transactions, so keep a little MNA back to pay the fee. The wallet tells you the most you can convert if you try to use your whole balance.
If something looks wrong
- wUSDC has not arrived. Give it a few minutes. The bridge waits for confirmations on the source chain before crediting.
- Your wallet shows an error with no explanation. Try once more, and if it persists use Rabby, which reports the actual reason.
- You cannot see your MNA. Check the network selector — wallets show one chain at a time, and MNA only exists on Intertrain.
CLI @intertrain-network/cli
Send MNA. Amounts are whole units and both address forms are accepted.
inter transfer mna1q8nlmzn2hr9ux6n867gjqwxcgmcdm3eulcvhxzka 1.5
inter transfer 0x1af13cCFbA8B48f0A7E3C68768a313789e05B6Fc 1.5 --memo "invoice 12"The command waits for the transaction to be included in a block before it prints the hash. A queued transaction is not an applied one, and a tool that reports success at submission will eventually report a success that did not happen.
Tokens
Issue a token, and get back the ERC-20 address it answers on so it can be added to MetaMask directly.
inter token create --name "Example Coin" --symbol EXC --supply 1000000
inter token send EXC mna1q8nlmzn2hr9ux6n867gjqwxcgmcdm3eulcvhxzka 250
inter token list
inter token address EXCRecover a key
Passed through the environment rather than as an argument, so the phrase never lands in shell history.
INTER_PHRASE='word word …' inter keygen recoverAll commands
| Command | Does |
|---|---|
| inter config get|set | Show or change the network and keypair path |
| inter keygen new|pubkey|recover | Create, show, or restore a key |
| inter address [--evm] | Print your address in either form |
| inter balance [address] | MNA and token balances |
| inter transfer <to> <amount> | Send MNA |
| inter token create|send|list|address | Token operations |
| inter block [height] | Inspect a block |
SDK @intertrain-network/sdk
Runs in Node, in a browser, and under React Native. Two objects: a Client that reads, and a Wallet that signs.
import { Client, Wallet } from '@intertrain-network/sdk';
const client = new Client('mainnet');
const wallet = Wallet.fromMnemonic(process.env.PHRASE, client);
await wallet.balance(); // '12.5'
await wallet.transfer('mna1q8nlmzn…', '1.5'); // resolves once it is in a blockReading
await client.chainInfo();
await client.account(address); // raw: base units, nonce, assets
await client.balance(address); // whole MNA, as a string
await client.holdings(address); // tokens with symbols and whole amounts
await client.tokens();
await client.token('EXC'); // by symbol or token id
await client.tokenAddress(tokenId); // its ERC-20 address
await client.block(); // latest, or block(height)
await client.transaction(hash);Writing
await wallet.transfer(to, '1.5', { memo: 'invoice 12' });
const token = await wallet.createToken({
name: 'Example Coin',
symbol: 'EXC',
supply: '1000000',
decimals: 6,
});
token.evmAddress; // paste this into MetaMask
await wallet.transferToken('EXC', to, '250');Write methods resolve when the transaction is in a block, not when the node accepts it. Pass { wait: false } to get the hash immediately and poll yourself.
Creating an account
const { mnemonic, wallet } = Wallet.create(client);
// hand the phrase to the user once; nothing here writes it downWallet core @intertrain-network/wallet-core
No fs, no fetch, no crypto.subtle, no React. Reach for it directly when you need key handling without a network connection — a hardware signer, an offline tool, or a mobile app with its own storage. The SDK re-exports the common parts, so most applications need only one dependency.
Randomness
Node, browsers, and Hermes disagree about which crypto globals exist, so the host supplies the source and the package never guesses. In a browser the default finds crypto.getRandomValues and no setup is needed.
import { setRandomSource } from '@intertrain-network/wallet-core';
import { randomBytes } from 'node:crypto';
setRandomSource((n) => new Uint8Array(randomBytes(n)));Keys and addresses
import { generate, fromMnemonic, normalize, toEvm } from '@intertrain-network/wallet-core';
const { mnemonic, keypair } = generate();
keypair.address; // mna1q8nlmzn2hr9ux6n867gjqwxcgmcdm3eulcvhxzka
keypair.evmAddress; // 0xe7fd8a6ab8cbc36a67d7912038d846f0ddc73cfe
keypair.sign(bytes);
normalize('0xe7fd8a6a…'); // → mna1q8nlmzn…, the same accountAn address is a version byte followed by twenty bytes of a domain-separated hash of the public key. Those twenty bytes are the EVM address, so the two forms are two renderings of one account rather than a conversion between two things.
Amounts
import { toBase, fromBase } from '@intertrain-network/wallet-core';
toBase('1.5', 6); // 1500000n
fromBase(1500000n, 6); // '1.5'toBase throws on more precision than the decimals can hold rather than silently truncating an amount that cannot be taken back.
Vaults
PBKDF2-SHA256 at 210,000 rounds plus AES-GCM-256, byte-compatible with the Intertrain web wallet.
const record = seal({ mnemonic }, password);
unseal(record, password);Networks
| Name | Chain | EVM chain id | RPC |
|---|---|---|---|
| mainnet | intertrain-1 | 4683 | rpc.intertrain.online/rpc |
| devnet | worldstreet-devnet-1 | 4685 | rpc-worldstreet.watchup.space/rpc |
MNA is 6 decimals natively and 18 at the EVM boundary. Both packages handle the factor internally; it matters only if you are encoding calldata by hand.
JSON-RPC
Nothing above is required. Every read and write path is a single POST /rpc call, and the EVM layer answers standard Ethereum methods, so viem, ethers, and foundry work against it unchanged.
curl -s https://rpc.intertrain.online/rpc \
-H 'content-type: application/json' \
-d '{"jsonrpc":"2.0","id":1,"method":"chain_info","params":{}}'cast block-number --rpc-url https://rpc.intertrain.online
forge create --rpc-url https://rpc.intertrain.online src/Token.sol:Token