Skip to main content

Quickstart

Quickstart

Look up a creator's vault from their coin and read its state onchain, with viem or cast.

This quickstart reads a vault's live state on Base. It only reads; nothing is signed or sent. You'll use the $AKITA vault as the example.

What you need​

  • A Base RPC URL (the public https://mainnet.base.org works for testing)
  • viem for TypeScript, or Foundry's cast for the command line
AddressValue
Registry4626 (live)0x7779…4626
$AKITA creator coin0x5b67…fa75

Always use the live Registry above for lookups. Other Registry addresses on Contract addresses are for older or batcher-internal use.

1. Find the vault's contracts​

The Registry maps a creator coin to every contract in its stack.

import {createPublicClient, getContract, http, parseAbi} from 'viem';
import {base} from 'viem/chains';

// multicall batching sends parallel reads as one request, which keeps public RPCs happy.
const client = createPublicClient({chain: base, transport: http(), batch: {multicall: true}});

const AKITA = '0x5b674196812451B7cEC024FE9d22D2c0b172fa75';

const registry = getContract({
address: '0x777968CB7F302f3d02C094b119a67DCA9E0b4626',
abi: parseAbi([
'function isTokenActive(address token) view returns (bool)',
'function getVaultForToken(address token) view returns (address)',
'function getWrapperForToken(address token) view returns (address)',
'function getShareOFTForToken(address token) view returns (address)',
'function getGaugeControllerForToken(address token) view returns (address)',
'function getOracleForToken(address token) view returns (address)',
]),
client,
});

const [active, vaultAddress, wrapperAddress, shareAddress, gaugeAddress, oracleAddress] =
await Promise.all([
registry.read.isTokenActive([AKITA]),
registry.read.getVaultForToken([AKITA]),
registry.read.getWrapperForToken([AKITA]),
registry.read.getShareOFTForToken([AKITA]),
registry.read.getGaugeControllerForToken([AKITA]),
registry.read.getOracleForToken([AKITA]),
]);

The same lookups with cast:

REGISTRY=0x777968CB7F302f3d02C094b119a67DCA9E0b4626
AKITA=0x5b674196812451B7cEC024FE9d22D2c0b172fa75
RPC=https://mainnet.base.org

cast call $REGISTRY "getVaultForToken(address)(address)" $AKITA --rpc-url $RPC
cast call $REGISTRY "getShareOFTForToken(address)(address)" $AKITA --rpc-url $RPC

2. Read the vault​

CreatorOVault is an ERC-4626 vault, so the standard views work.

const vault = getContract({
address: vaultAddress,
abi: parseAbi([
'function asset() view returns (address)',
'function totalAssets() view returns (uint256)',
'function pricePerShare() view returns (uint256)',
'function convertToAssets(uint256 shares) view returns (uint256)',
]),
client,
});

const totalAssets = await vault.read.totalAssets();

// 1000 vault claims ≈ 1 creator coin at launch (decimals offset of 3).
const coinsPer1000Claims = await vault.read.convertToAssets([1000n * 10n ** 18n]);

3. Read the ShareOFT​

CreatorShareOFT is an ERC-20 (and LayerZero OFT). It also exposes convertToAssets, which prices ShareOFT in creator coins directly.

const share = getContract({
address: shareAddress,
abi: parseAbi([
'function symbol() view returns (string)',
'function totalSupply() view returns (uint256)',
'function balanceOf(address account) view returns (uint256)',
'function convertToAssets(uint256 shares) view returns (uint256)',
]),
client,
});

const [symbol, supply, coinsPerShare] = await Promise.all([
share.read.symbol(),
share.read.totalSupply(),
share.read.convertToAssets([10n ** 18n]),
]);
// symbol === '■AKITA'
Units

Vault claims and ShareOFT both use 18 decimals but are not 1:1. One ShareOFT wraps 1000 vault claims. Price ShareOFT with its own convertToAssets, not the vault's. See ERC-4626 deviations.

Next steps​