Walkthrough setup
The viem client, the contracts' clock and the ABIs every walkthrough imports, as the deployed contracts declare them.
On this page
The walkthroughs share two files: a viem client for Robinhood Chain with the contracts' clock, and the ABIs they call, copied from the deployed contracts. Install viem, which carries the robinhood chain, and hookr-sdk, whose CORE_STRUCTS are the pool structs a market and a launch are built from.
The tokenizer's address is 0xfb3c1501c727f30883cd7b36ec380381af7412ef: paste it into client.ts. Every other address the walkthroughs use is read from it or named on Contracts.
client.ts
import { createPublicClient, http, parseAbi, type Address } from "viem";
import { robinhood } from "viem/chains";
export const client = createPublicClient({ chain: robinhood, transport: http() });
// Paste the tokenizer's address from the Contracts page.
export const TOKENIZER: Address = "0x…";
// The contracts' clock: Ethereum's block number, which is `block.number` inside a contract on Robinhood Chain.
export function parentBlock() {
return client.readContract({
address: robinhood.contracts.multicall3.address,
abi: parseAbi(["function getBlockNumber() view returns (uint256)"]),
functionName: "getBlockNumber",
});
}
// For good: the largest uint64, as a term or an unlock block.
export const FOREVER = 2n ** 64n - 1n;parentBlock() is the block number a family's term is counted in, Ethereum's; eth_blockNumber is the rollup's own and far higher. Two block numbers says which figures use which.
abis.ts
import { parseAbi } from "viem";
import { CORE_STRUCTS } from "hookr-sdk"; // PoolKey, PoolConfig, RulesConfig, RecaptureConfig, Token, Member and the rest
export const tokenizerAbi = parseAbi([
...CORE_STRUCTS,
"struct DevBuy { uint8 member; uint128 quoteIn; uint128 minSubjectOut; uint32 lockBlocks; }",
"struct MemberKnobs { uint16 subjectWeightBps; uint16 dynamicFeeLiquidityDivisor; uint64 lockEndBlock; uint16 windowSeconds; uint16 resetSeconds; uint16 carryBps; uint24 moveTicks; uint8 snipeCurve; }",
"struct OpeningCheck { uint16 toleranceBps; PoolKey[] references; }",
"struct LaunchParams { Token token; address root; Member[] members; MemberKnobs[] knobs; bytes[] advisoryConfigs; DevBuy[] buys; uint16 maxRetainedBps; OpeningCheck opening; uint256 deadline; string tagline; string logoURI; }",
"struct TokenTerms { string name; string symbol; uint256 supply; uint32 streamSeconds; uint16 tipBps; address[] extraAssets; address[] recipients; uint256[] amounts; bytes32 termsHash; }",
"struct LockTerms { uint64 unlockBlock; }",
"struct PositionPermit { bool forAll; uint256 tokenId; uint256 deadline; uint256 nonce; bytes signature; }",
"struct PositionTerms { uint256[] tokenIds; uint64 unlockAt; PositionPermit[] permits; }",
"struct MarketTerms { bool open; uint256 seed; int24 tickSpacing; uint160 sqrtPriceX96; int24 tickLower; int24 tickUpper; uint128 liquidity; PoolConfig config; RulesConfig rules; RecaptureConfig recapture; uint16 bridgeBps; uint128 bridgeMaxPerDrip; uint32 bridgeMinBlocks; uint16 bridgeTipBps; uint16 bridgeMaxJumpBps; }",
"struct FeebSource { address vault; uint256 tokenId; }",
"struct V3PositionPermit { uint256 tokenId; uint256 deadline; uint8 v; bytes32 r; bytes32 s; }",
"struct StreamParams { bytes launchParams; FeebSource[] feebs; uint256[] positionIds; PositionPermit[] positionPermits; uint256[] v3PositionIds; V3PositionPermit[] v3Permits; address[] sources; uint64 unlockAt; }",
"struct Tokenization { address creator; uint8 way; address forwarder; address adapter; address door; bytes32 familyId; bytes32 marketFamilyId; uint64 unlockBlock; uint16 legBps; }",
"struct StreamRecord { uint8 kind; address target; bytes32 id; uint8 endKind; uint64 end; }",
"function launcher() view returns (address)",
"function collector() view returns (address)",
"function positionManager() view returns (address)",
"function doorFactory() view returns (address)",
"function positionManagerV3() view returns (address)",
"function v3DoorFactory() view returns (address)",
"function admittedVaults() view returns (address[])",
"function tokenCount() view returns (uint256)",
"function tokenAt(uint256 i) view returns (address)",
"function tokenizations(address token) view returns (Tokenization)",
"function streamsOf(address token) view returns (StreamRecord[])",
"function HOOKR_LEG_BPS_OUTSIDE() view returns (uint16)",
"function HOOKR_LEG_BPS_HOOKR() view returns (uint16)",
"function defaultMarket(uint160 sqrtPriceX96, uint256 seed) view returns (MarketTerms)",
"function previewPositions(uint256[] tokenIds, address[] extraAssets) view returns (uint16 legBps, address[] assets, bool[] hookrPool, bool[] hookCanBlockCollection)",
"function predictRevenueToken(address creator, LaunchParams p, TokenTerms t) view returns (address)",
"function predictStreamToken(address creator, TokenTerms t) view returns (address)",
"function launchAndTokenize(LaunchParams p, TokenTerms t, LockTerms l, MarketTerms m) payable returns (address token, address forwarder, bytes32 familyId, bytes32 marketFamilyId, address subject, uint256 subjectOut)",
"function tokenizeFeeb(address vault, uint256 tokenId, TokenTerms t, LockTerms l, MarketTerms m) payable returns (address token, address adapter, address forwarder, bytes32 marketFamilyId)",
"function tokenizePositions(PositionTerms p, TokenTerms t, LockTerms l, MarketTerms m) payable returns (address token, address door, address forwarder, bytes32 marketFamilyId)",
"function tokenizeStreams(StreamParams p, TokenTerms t, LockTerms l, MarketTerms m) payable returns (address token)",
"event Tokenized(address indexed token, address indexed creator, uint8 way, address forwarder, address adapter, address door, bytes32 familyId, bytes32 marketFamilyId, uint256 supply, uint64 unlockBlock, uint16 legBps)",
"event MarketOpened(address indexed token, bytes32 indexed familyId, bytes32 indexed poolId, uint256 seed, address bridge, uint16 bridgeBps)",
"event StreamAdded(address indexed token, uint256 index, uint8 kind, address indexed target, bytes32 id, uint8 endKind, uint64 end)",
// The tokenizer's own refusals, so a simulation names them with their figures.
"error InvalidConfig()", "error InvalidTerms()", "error TermTooShort(uint64 given, uint64 minimum)", "error InvalidMarket()",
"error TooManyAssets(uint256 count)", "error RulesNotAdmitted(address rules)", "error VaultNotAdmitted(address vault)",
"error NotNftOwner(address vault, uint256 tokenId, address owner)", "error MintMismatch(uint256 sum, uint256 expected)",
"error InvalidFunding()", "error Reentered()", "error DoorMismatch(address door)", "error AdvisoryRecipientMismatch(address advisory)",
"error TooManyDoors(uint256 count)", "error NothingToTokenize()", "error InvalidSource(address source)", "error SourceNotBound(address source)",
"error SourceRevocationPending(address source, uint64 effectiveAt)", "error SyncTooExpensive(uint256 total)", "error AssetNotListed(address currency)",
]);
export const tokenAbi = parseAbi([
"struct Asset { address currency; uint256 index; uint256 carry; uint128 received; uint128 paid; uint128 pendingStream; uint64 streamEnd; uint64 lastRelease; }",
"struct Door { uint8 kind; address target; uint32 gas; }",
"function name() view returns (string)",
"function symbol() view returns (string)",
"function decimals() view returns (uint8)",
"function totalSupply() view returns (uint256)",
"function balanceOf(address account) view returns (uint256)",
"function earns(address account) view returns (bool)",
"function earningSupply() view returns (uint256)",
"function streamSeconds() view returns (uint32)",
"function tipBps() view returns (uint16)",
"function bridge() view returns (address)",
"function bridgeBps() view returns (uint16)",
"function assetCount() view returns (uint256)",
"function assetAt(uint256 i) view returns (Asset)",
"function releasable(uint256 asset) view returns (uint256)",
"function claimable(address account, uint256 asset) view returns (uint256)",
"function claim(uint256 asset, address to) returns (uint256 amount)",
"function claimAll(address to) returns (uint256[] amounts)",
"function claimWithSig(address holder, uint256 asset, address to, bytes32 nonce, uint256 deadline, bytes signature) returns (uint256 amount)",
"function claimAllWithSig(address holder, address to, bytes32 nonce, uint256 deadline, bytes signature) returns (uint256[] amounts)",
"function doorCount() view returns (uint256)",
"function doorAt(uint256 i) view returns (Door)",
"function sync() returns (uint256 tip)",
"function syncSome(uint256[] doors) returns (uint256 tip)",
"function dropBox() view returns (address)",
"event Synced(address indexed by, uint256 pulledEth, uint256 tip, uint256 bridged)",
"error InvalidConfig()", "error InvalidAsset(address currency)", "error UnknownAsset(uint256 asset)", "error InvalidDoor(uint256 door)",
"error InvalidRecipient(address to)", "error InvalidAmount(uint256 amount)", "error NothingToClaim()", "error NotLive()", "error AlreadyLive()",
"error Unauthorized(address caller)", "error SyncStarved(uint256 door, uint256 needed)", "error SyncTooExpensive(uint256 total)",
"error InexactTransfer()", "error NativeNotAccepted()", "error InvalidSigner()", "error SignatureExpired(uint256 deadline)",
"error AuthorizationNotYetValid(uint256 validAfter)", "error NonceAlreadyUsed(bytes32 nonce)", "error CallerIsNotPayee(address caller)",
]);
export const dropBoxAbi = parseAbi([
"struct Drop { address asset; uint48 snapshotBlock; uint256 amount; uint256 earningSupply; uint256 paid; }",
"function dropCount() view returns (uint256)",
"function dropAt(uint256 dropId) view returns (Drop)",
"function claimable(uint256 dropId, address holder) view returns (uint256)",
"function claim(uint256[] dropIds, address to) returns (uint256[] amounts)",
"function claimWithSig(address holder, uint256[] dropIds, address to, bytes32 nonce, uint256 deadline, bytes signature) returns (uint256[] amounts)",
"error RefusedAsset(address asset)", "error InexactValue(uint256 expected, uint256 sent)", "error NativeNotAccepted()", "error NothingReceived()",
"error NoEarningSupply(uint48 snapshotBlock)", "error UnknownDrop(uint256 dropId)", "error AlreadyClaimed(uint256 dropId)",
"error NothingToClaim(uint256 dropId)", "error InvalidRecipient(address to)", "error PaymentFailed(address to)", "error Reentered()",
"error InvalidSigner()", "error SignatureExpired(uint256 deadline)", "error NonceAlreadyUsed(bytes32 nonce)",
]);
// The contracts around the tokenizer that the walkthroughs call.
export const launchFeeAbi = parseAbi(["function launchFee() view returns (uint256 fee, address treasury, uint256 pendingFee, address pendingTreasury, uint256 readyAt)"]);
export const feeNftVaultAbi = parseAbi([
"function ownerOf(uint256 tokenId) view returns (address)",
"function getApproved(uint256 tokenId) view returns (address)",
"function approve(address to, uint256 tokenId)",
"function amounts(uint256 tokenId) view returns (uint256 amount0, uint256 amount1)",
]);
export const feeNftDoorAbi = parseAbi(["function tokenId() view returns (uint256)"]);
export const feeSplitterAbi = parseAbi(["function collectFees(uint256[] tokenIds)"]);
export const positionManagerAbi = parseAbi([
"function ownerOf(uint256 tokenId) view returns (address)",
"function isApprovedForAll(address owner, address operator) view returns (bool)",
"function setApprovalForAll(address operator, bool approved)",
]);
export const ponsDoorFactoryAbi = parseAbi([
"function launchFactory() view returns (address)",
"function create(address revenueToken, address memecoin) returns (address adapter)",
]);
export const ponsLaunchFactoryAbi = parseAbi(["function transferCreatorFeeRecipient(address token, address newRecipient)"]);These are the calls, events and errors as the deployed contracts declare them, with their argument names, types and order. Each contract's full ABI is on Sourcify.
Running them
- The walkthroughs simulate their mints, claims and syncs with
simulateContractbefore sending them. A call the tokenizer, a token or a drop box would refuse comes back as the errorabis.tsnames, with its figures, before anything is spent; a refusal from another contract the call reaches, such as a vault, comes back as its selector. - The walkthroughs sign with a key from the environment. In an app, use the connected wallet's client instead; the calls are the same.
- A walkthrough that names an address with
"0x…"is waiting for one of yours.