VYRE Docs Mainnet

TypeScript SDK

@vyrechain/sdk is a small library on top of viem: the chain definitions for VYRE Testnet and Arc Testnet, the deployed addresses and ABIs, and typed calls for the launchpad, the bridge and the faucet. It follows two rules our own apps follow: every transaction is simulated before it's sent, and approvals are for the exact amount, never unlimited.

Install

It's served from this site until it's on npm:

npm install https://vyrechain.com/sdk/vyrechain-sdk-0.7.1.tgz viem

Version 0.7.1. It's ESM with TypeScript types, for Node 18+ and browsers.

One address is one set of files: a package never changes under its name, and a version that is taken down is gone (its address answers "not found", never with another version's package). To check what you downloaded, compare it with the list of the packages this site serves:

VersionSHA-256 of the package
0.7.1744a296ad577bd1e3a5b991f76b9775b3e5bcd541f28330f91ba8675c77e8c8e
0.7.051ef2d70555a9ad56ca622c3746117a1d0892576492cdab982d2ba89db5ab8cf
0.6.028cdd51608c702b0bf54a0376c05983e5816378bce7abf39554459ab020e030d
0.5.17ebd8c378d49913effa011d7ce2436df3c2c20e00c424848bbddc206df7321227
0.5.16f4ed0eb94dabcced6b05ca7402776afe49ad85f2ce91a231e8daddb155b92dc8
0.5.15ac2854b6e0193c66c2c94663d2d3ca362719e9447f90264e2f9a017d648258ea
0.5.14ff08d378fadaf9462a962cb31370b236f5723ef338d3facc176f36e7899e949a
0.5.132001156b136f64ae5e3f073f5ba764ebf0d120e6322a6fe143ca49a86147c775
0.5.124bf20507b74e4a29afeb8a69890a5a9750ff2d94776b83c88bddd59394a89e5d
0.5.11a5509015c48344f5642df0b7773d524c573ff6a6f97eefa23b9c6a1ff772f884
0.5.105a3e441f8fae3d55146892f35121a53736a179dc2d3f9ffac3145e71be26942e
0.5.92f24da7d082819206aa59ebb3bd49f4da54f4e3678b30ca4320f37730105d989
0.5.684c6a6ccc2661f2ce382e9aed782ba3625728e5cff49e321f6b3edcad387a965
0.5.2610a65ce243655c029dd095353f89682cf7a69ac453122113ea8307e1ba8749d
0.5.170082108461dc59f44a7b089d84df5483b1ad37e414ed5f071ce7ea4ebfcac97
0.5.0c08a8ebe211d4ef8d605bc63b695a710bd4b18ef3ebe52bc73ec374103ce9778
curl -fsSLO https://vyrechain.com/sdk/vyrechain-sdk-0.7.1.tgz && sha256sum vyrechain-sdk-0.7.1.tgz

Mainnet

This version also knows VYRE mainnet: vyreMainnet (chain 3045, RPC https://rpc.vyrechain.com) and arcMainnet (its parent chain, for deposits and withdrawals). getAddresses(3045) returns its contracts, and getAddresses(7357) and the testnet's chains are as below.

import { createPublicClient } from 'viem'
import { vyreMainnet, vyreHttp, getAddresses } from '@vyrechain/sdk'

const client = createPublicClient({ chain: vyreMainnet, transport: vyreHttp(), batch: { multicall: true } })
const { pad } = getAddresses(vyreMainnet.id)

Mainnet's launch contract is VyrePadV2 (getAddresses(3045).padVersion is 2): a creator's tax of 1% to 10% a side is the only fee a trade pays, a tenth of what is paid out of it goes to the platform wallet, and there is no partner fee, no promoter share and no early-buy fee. Trades go through Uniswap's SwapRouter, so mainnet has no app router, fee splitter or referrals address (getAddresses(3045).appRouter is undefined, getPromoter gives null, getAppFeeBps gives 0). The testnet's launch contract is the first one, VyrePad (padVersion 1). buy, sell, launch, the creator's controls and the reads below work on both and tell them apart by the chain. getAddresses(3045).legacy lists mainnet's first deployment, which is not used any more.

Everything below uses the testnet's names; swap in vyreMainnet and arcMainnet for mainnet. There's no faucet on mainnet.

Connect

import { createPublicClient } from 'viem'
import { vyreTestnet, vyreHttp } from '@vyrechain/sdk'

// vyreHttp() is viem's http() with more patient retries, for the public RPC's one-request-at-a-time limit
const client = createPublicClient({ chain: vyreTestnet, transport: vyreHttp() })
console.log(await client.getBlockNumber())

The public RPC serves one request at a time per caller, so batch your reads: with batch: { multicall: true } viem sends reads made together as one call to Multicall3 (its address is in vyreTestnet):

const client = createPublicClient({ chain: vyreTestnet, transport: vyreHttp(), batch: { multicall: true } })

Read the launchpad

import { getLaunchCount, getLaunches, getLaunch } from '@vyrechain/sdk'

const count = await getLaunchCount(client)
const latest = await getLaunches(client, { count: 10 }) // newest first
const launch = await getLaunch(client, latest[0].token)
// { token, pool, creator, name, symbol, totalSupply, buyTaxBps, sellTaxBps, partner, partnerFeeBps, createdAt, metadataURI }
// (partner is null and partnerFeeBps is 0 on mainnet, whose pad has no partner fee)

A launch's trades are read in pages of 50,000 blocks (getTrades). The public RPC refuses an answer over 16 MB (answer too large), which a very busy pool's page can reach; getTrades then halves that page and reads each half (getWithdrawals does the same with its pages). For your own log queries, readLogsSplitting(read, from, to) does the same for any read(from, to) you give it (it returns the logs oldest first, and throws any other error as it is). With vyreHttp(url, { batch: true }), a batch holds at most 20 calls, the public RPC's cap (a larger batchSize is lowered to 20), and the public RPC refuses every call of a batch whose answers together are too large, so a call refused that way is asked once more on its own, and only its own refusal is final.

Trade

import { createWalletClient, parseEther } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { vyreTestnet, vyreHttp, quoteBuy, buy, quoteSell, sell } from '@vyrechain/sdk'

// a script's key from the environment (never commit it); in a browser use custom(window.ethereum)
const wallet = createWalletClient({
  account: privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`),
  chain: vyreTestnet,
  transport: vyreHttp(),
})

const token = '0x…'
const tokensOut = await quoteBuy(client, { token, usdcIn: parseEther('0.1') })
const bought = await buy(wallet, client, { token, usdcIn: parseEther('0.1') }) // accepts up to 2% less than quoted

const usdcOut = await quoteSell(client, { token, amountIn: tokensOut / 2n })
const sold = await sell(wallet, client, { token, amountIn: tokensOut / 2n }) // signs a permit, or approves the exact amount

Buys and sells use native USDC: through the app router on the testnet, through Uniswap's SwapRouter on mainnet. Set slippageBps (default 200, 2%), or give minTokensOut / minUsdcOut yourself. While a launch's early-buy fee is running, buy refuses the default minimum (nothing is sent): the quote has the fee in it, so it is a floor and not a price. Pass minTokensOut, or buy once the window has ended.

Calls like these can follow each other at once from one key (a buy, then a sell; a sale that needs an approval first): for a key in your script the SDK sends each with a nonce no lower than the one after the last transaction it saw mined, and a send the node still refuses as "nonce too low" (its count can lag a receipt by a moment) is signed again a little later, a few times, once the node says it doesn't hold the refused transaction itself. If it does, or can't say (a transport that sent the same bytes twice, such as viem's fallback after a lost answer, gets "nonce too low" for a copy the chain already took), the call throws SentButUnconfirmedError with that transaction's hash, to check before sending again, so nothing is sent twice. Your own sends from the same key outside the SDK should do the same (Network and RPC).

A trade's recipient (who gets what it buys or sells, if not the sender), and every other address that moves money or names who gets it (sendUsdc's to, tax wallets, a new creator, a partner, a promoter), must be typed exactly: all lowercase, or with its checksum, as wallets show it. A mixed-case address whose checksum doesn't match is a typo, and the SDK refuses it before anything is sent.

Launch a token

import { launch } from '@vyrechain/sdk'

const { token, pool, bought, hash } = await launch(wallet, client, {
  name: 'My Token',
  symbol: 'MINE',
  totalSupply: parseEther('1000000000'),   // 1 billion tokens
                                           // (no market cap to pick: every launch opens at $3,000)
  buyTaxBps: 100,                          // your tax on buys: 1% (mainnet: 1% to 10%; the testnet takes 0 to 10%)
  sellTaxBps: 100,                         // your tax on sells
  metadataURI: 'https://example.com/mine.json',
  firstBuyUsdc: parseEther('1'),           // your own first buy, in the same transaction
})

The limits (checked before sending) are on Launchpad. checkLaunchParams(params) checks the testnet's pad by default: on mainnet call checkLaunchParams(params, 2) (a tax under 1% and any partner are refused). launch() picks the right one from the chain itself.

Bridge and faucet

import { createWalletClient, createPublicClient, custom, http, parseEther } from 'viem'
import { arcTestnet, vyreTestnet, depositFromArc, waitForDeposit, requestTestUsdc, sendUsdc, FAUCET_ADDRESS } from '@vyrechain/sdk'

// test USDC from the faucet (2 a day)
const { tx } = await requestTestUsdc('0xYourAddress')

// send USDC from any wallet (a browser wallet, or a Face ID wallet's bundler client): here, back to the faucet, to its
// address as the SDK fixes it (never an address read from a server)
await sendUsdc(wallet, client, { to: FAUCET_ADDRESS, amount: parseEther('1') })

// or bring more in from Arc testnet (arrives in a few seconds); the wallet client needs the account it sends from
const [address] = await window.ethereum.request({ method: 'eth_requestAccounts' })
const arcWallet = createWalletClient({ account: address, chain: arcTestnet, transport: custom(window.ethereum) })
const arcClient = createPublicClient({ chain: arcTestnet, transport: http() })
const before = await client.getBalance({ address })
await depositFromArc(arcWallet, arcClient, { amount: parseEther('5') })
await waitForDeposit(client, { address, before })

USDC on Ethereum, Base or Arbitrum Sepolia reaches Arc with quoteFromChain, burnToArc and waitForArcMint (Circle's CCTP): see From another chain.

Face ID wallets

The launchpad app doesn't offer Face ID wallets for now (they're on the roadmap: a card purchase can't be delivered to a smart wallet, so the app uses plain EVM wallets, like other chains, until that's sorted out). The SDK, the bundler and the contracts below stay available for apps that want them.

This section is the testnet's: there's no bundler on mainnet, so Face ID wallets don't work there.

A Face ID wallet is a smart wallet owned by a passkey (Face ID, a fingerprint or the computer's own lock), with no app and no seed phrase. The passkey stays in the device's secure chip and syncs with the person's Apple or Google account; VYRE checks its signatures on chain. Every call above takes a Face ID wallet where it takes a wallet client:

import {
  createFaceIdPasskey, signInWithPasskey, getFaceIdWalletAddress, faceIdWallet, faceIdBundler, buy, sell,
} from '@vyrechain/sdk'

// a new wallet: Face ID asks, and the address follows from the passkey (fund it before its first operation)
const passkey = await createFaceIdPasskey()
const address = await getFaceIdWalletAddress(client, passkey.publicKey)

// or, on a new phone, sign in with a passkey synced there (found from the signature itself)
const found = await signInWithPasskey(client)

// send: each call is one operation, signed with Face ID and sent through VYRE's bundler
const account = await faceIdWallet({ client, passkey })
const wallet = faceIdBundler({ client, account })
await buy(wallet, client, { token, usdcIn: parseEther('1') })
await sell(wallet, client, { token, amountIn }) // the exact approval rides in the same operation

The wallet is Coinbase's open-source Smart Wallet (v1.1) behind ERC-4337's EntryPoint v0.6 (addresses on Contracts); it pays its own gas in USDC, and the bundler is paid back in the same transaction. Passkeys work on the site that made them, so an app on its own domain makes its own. The bundler accepts only these wallets (Bundler API).

An operation is not signed if it could cost more than 0.05 USDC in gas (FeeTooHighError); pass maxCost to faceIdWallet to raise the cap. A token launch is about 8.6 million gas in all, so it passes that cap once the base fee is above roughly 5.8 gwei: raise maxCost with the base fee.

Addresses and ABIs

import { getAddresses, vyrePadAbi, vyreAppRouterAbi } from '@vyrechain/sdk'

const { pad, appRouter, quoter, wusdc } = getAddresses(vyreTestnet.id)

Until the testnet is redeployed, its contracts are from an earlier build than the contracts' current code, which the SDK's ABIs (vyrePadAbi and the others) follow: VyrePad there lacks OPENING_MARKET_CAP and still has MAX_STARTING_MARKET_CAP and MIN_STARTING_MARKET_CAP; VyreAppRouter there lacks GasInfoChanged, GasRefund, MAX_REFUND_CALLDATA, REFUND_BASE_GAS, REFUND_MARGIN_BPS, REFUND_OVERHEAD_GAS, gasInfo and setGasInfo; VyrePool there lacks LaunchFee, launchFeeConfig and launchFees. Calls to the functions they lack revert there. The testnet's deployed contracts' own ABIs are on API reference. Mainnet's launch contract has its own ABI, vyrePadV2Abi (also at /docs/abi/VyrePadV2.json), and swapRouterAbi holds the part of Uniswap's SwapRouter that buy and sell call; on mainnet use those, and quoterV2Abi for quotes. getAddresses(chainId).legacy, where there is one, holds addresses that are not used any more.

For a local chain or fork, register your own deployment with registerDeployment(chainId, addresses).

VYRE's testnet has no value: its USDC is for testing. On mainnet, trading is risky and nothing here is advice. USDC is issued by Circle; VYRE is an independent project, not affiliated with or endorsed by Circle. Questions: team@vyrechain.com