Skip to Content
solidondocs

Contracts

Every public method of the Solidon factory and meme contracts on NEAR, with arguments, deposits, callers, effects and emitted events.

Solidon is two Rust contracts on NEAR (near-sdk), in one cargo workspace under contracts/:

CrateAccountRole
factorysolidon.testnetDeploys each meme as <symbol>.solidon.testnet. Fixes USDC, oracle, treasury chains and stock list at init. No owner.
meme<symbol>.solidon.testnetNEP-141 token, internal meme/USDC pool, mNAV engine, multichain treasury via Chain Signatures. No owner, no setter.
mock-ftusdc.solidon.testnetTestnet USDC stand-in (NEP-141, 6 decimals, open mint).
mock-pythpyth.solidon.testnetTestnet oracle with the Pyth read interface and an open set_price.

Conventions used on this page:

  • U128 values are JSON strings ("1000000"). USDC amounts are raw units with 6 decimals; meme amounts are raw units with 18 decimals.
  • Prices returned by the pool (spot_price, twap_price, nav) are USDC raw units per meme raw unit, scaled by 1e30.
  • chain is a name from the factory's chains config: base, robinhood or solana.
  • Ratios are basis points: 10000 = 100% = 1.0x.
  • "Anyone" means any NEAR account. Who calls does not change the outcome; the contract checks every input.

No admin

Neither contract has an owner method. Every parameter is fixed at new and readable through views. See Security.

Factory

Change methods

MethodArgsDepositCallerEffect
newusdc: AccountId, oracle: AccountId, chains: ChainsConfig, stocks: Stock[]nonedeployer, once (#[init])Stores the immutable config. Requires at least one stock.
create_memename: string, symbol: string, thesis_stock: string, icon: string | nullat least launch_cost() yoctoNEARanyoneCreates <symbol lowercased>.<factory>, transfers the whole deposit to it, deploys the meme code and calls its new. symbol must be 2 to 10 ASCII letters or digits and not yet launched; thesis_stock must be a listed ticker. On failure the deposit is refunded to the caller.
on_creatememe, creator, depositnonefactory only (#[private])Callback. On success records the meme and emits launch; otherwise refunds the deposit.

View methods

MethodArgsReturns
launch_costnoneU128: storage cost of the meme code plus 20,000 bytes of state. Live value: 4459990000000000000000000 (4.46 NEAR).
get_memesfrom_index?: u32 (default 0), limit?: u32 (default 50)AccountId[] in launch order
get_usdcnoneUSDC token account
get_oraclenoneOracle account
get_chainsnoneChainsConfig
get_stocksnoneStock[]

Config types

Prop

Type

EvmChain: {name, chain_id, usdc, usdc_decimals, swap_router, pool_fee, max_fee_per_gas, max_priority_fee_per_gas, max_swap_usdc, proof}. proof is {"Mpc": {"foreign_chain": "Base", "finality": "Latest" | "Safe" | "Finalized"}} or "Relayer".

SolanaChain: {name, usdc_mint, usdc_token_program, stock_token_program, clmm_program, amm_config, max_swap_usdc}. The USDC program must be SPL Token and the stock program Token-2022; max_swap_usdc must fit a u64.

Stock: {ticker, price_id, venues: [{chain, token, decimals, solana}]}. price_id is 64 lowercase hex characters. One venue per chain; solana is {pool, usdc_vault, stock_vault, observation, bitmap_extension} on the Solana venue and null elsewhere. decimals at most 18.

The live config is on the Deployments page.

Meme: token and pool

The meme is a standard NEP-141 token (ft_transfer, ft_transfer_call, ft_total_supply, ft_balance_of, ft_metadata) with NEP-145 storage management (storage_deposit, storage_withdraw, storage_unregister, storage_balance_bounds, storage_balance_of). Decimals: 18. At new, 1,000,000,000 tokens are minted to the meme contract itself as pool inventory.

Register first

A buyer must be registered on the meme (storage_deposit) before a buy, or the transfer of meme tokens panics and the USDC is refunded. The meme must be registered on the USDC contract before any USDC can be sent to it.

Buying and seeding: ft_transfer_call on USDC

USDC enters through ft_transfer_call on the USDC contract with receiver_id = the meme. The meme's ft_on_transfer accepts only the factory-fixed USDC and parses msg:

msgCallerEffect
{"action":"seed"}the creator, onceSets the USDC reserve to the full amount. Panics if already seeded or amount is 0. Emits seed.
{"action":"buy","min_out":"<u128>"}anyoneTakes the 1% fee on the USDC side (0.8% to treasury cash, 0.2% claimable by the creator), swaps the rest on x * y = k, sends meme tokens to the sender. Panics if output is 0 or below min_out. Emits buy.

Any panic refunds the full USDC amount through ft_resolve_transfer. Attach 1 yoctoNEAR; the web app uses 150 TGas.

near contract call-function as-transaction usdc.solidon.testnet ft_transfer_call \
  json-args '{"receiver_id":"honey.solidon.testnet","amount":"10000000","msg":"{\"action\":\"buy\",\"min_out\":\"1\"}"}' \
  prepaid-gas '150.0 Tgas' attached-deposit '1 yoctoNEAR' \
  sign-as <you>.testnet network-config testnet sign-with-keychain send

Change methods

MethodArgsDepositCallerEffect
sellamount: U128, min_out: U1281 yoctoNEARholderSells amount meme into the pool. Fee taken from the USDC output (same split as a buy). Panics if net output is 0 or below min_out. Emits sell, then pays USDC; a failed payout becomes claimable (payout_failed).
claim_usdcnonenoneany account with a claimable balanceWithdraws USDC credited to the caller: creator fees, rebalance tips, failed payouts. Panics with Nothing to claim.

View methods

MethodArgsReturns
get_poolnone{meme_reserve, usdc_reserve, treasury_usdc, spot_price, twap_price}. twap_price is null while the pool is younger than the 30-minute window.
quote_buyusdc_in: U128Meme out after fees
quote_sellmeme_in: U128USDC out after fees
claimable_ofaccount_idU128 USDC claimable
get_paramsnoneParams (below)
get_infonone{creator, usdc, oracle, stock}

Locked parameters (get_params)

FieldValueMeaning
pool_fee_bps1001% fee on every trade, USDC side
treasury_fee_bps80Of which 0.8% to treasury cash
creator_fee_bps20Of which 0.2% claimable by the creator
issuance_mnav_bps20000Issue new tokens above mNAV 2.0
max_issuance_bps_per_epoch100At most 1% of circulating supply per epoch
epoch_secs86400Epoch: 24 h
buyback_mnav_bps10000Buy back and burn below mNAV 1.0
redemption_mnav_bps9000Redemption window opens below mNAV 0.9
cash_buffer_bps200020% of treasury value kept as cash on NEAR
cash_refill_bps1000Refill threshold, 10%
twap_window_secs180030-minute TWAP
oracle_max_age_secs900Price older than 15 minutes is stale
rebalance_cooldown_secs3600One rebalance per hour
caller_tip_bps50.05% of the rebalance amount to the caller
target_leverage_bps100001.0x

Meme: mNAV engine

MethodArgsDepositCallerEffect
rebalancenonenoneanyone, once per cooldownAttach 100 TGas. Reads the oracle (get_price_no_older_than, 900 s), then evaluates mNAV = TWAP / NAV: above 2.0 issues tokens into the pool (capped by the epoch, only if accretive), below 1.0 buys back and burns with cash above the 20% buffer, and sets the redemption window (open below 0.9). Credits the 0.05% tip to the caller. Emits rebalance. Panics if the cooldown has not ended.
redeemamount: U128, min_usdc: U1281 yoctoNEARholder, while the window is openAttach 100 TGas (the web app uses 150). Burns amount, reads a fresh price, pays NAV per token in USDC from treasury cash. Refunds the tokens on a stale price, on min_usdc not met, or on insufficient cash. Emits redeem or redeem_refunded.
get_treasurynoneviewanyone{stock_units, treasury_usdc, circulating, redemption_open, last_rebalance, next_rebalance, last_nav, last_mnav_bps, epoch_cap, epoch_issued}

rebalance returns an Outcome: "cooldown", "stale_price" (no state change, cooldown not consumed), "no_market" (pool younger than the TWAP window or nothing circulating, cooldown not consumed), {"issued": {meme, usdc}}, {"bought_back": {meme, usdc}}, or "no_action".

See mNAV for the formulas and Rebalance and Redeem for walkthroughs.

Meme: treasury

Each meme owns one EVM address (MPC path evm-treasury, secp256k1 domain 0), shared by Base and Robinhood Chain, and one Solana address (path solana-treasury, EdDSA domain 1). One signature is in flight at a time across all chains. See Treasuries.

The Gas column is the prepaid gas the contract's doc comment asks for, or what the keeper attaches.

Setup

MethodArgsCallerGasEffect
init_treasurynoneanyone, once100 TGasReads derived_public_key from the MPC and stores the EVM treasury address. Emits treasury with evm_address.
init_solana_treasurynoneanyone, once100 TGasReads the derived EdDSA key and stores the Solana treasury address. Emits treasury with solana_address.
approve_routerchain: stringanyone, once per EVM chain300 TGasMPC-signs approve(swap_router, max) on that chain's USDC. Emits evm_tx_signed (or evm_tx_rejected).
set_solana_accountsusdc_account_bump: u8, stock_account_bump: u8relayer only (may correct)30 TGasStores the treasury's USDC (SPL Token) and stock (Token-2022) associated token accounts. Emits solana_accounts.

Cash flow

MethodArgsCallerGasEffect
fund_chainchain: stringanyone100 TGasReads a fresh price, then sends NEAR cash above the 20% buffer, at most max_swap_usdc, to the factory's bridge with memo solidon fund <chain> <treasury>. Booked as in_transit (still counted in NAV). Emits cash_sent or fund_chain_skipped; a failed transfer returns the cash (cash_returned).
credit_cashchain: string, tx_hash: string, log_index: u64, log: {block_hash, block_number, transaction_index, address, topics, data}anyone, chains with proof: Mpc (Base)300 TGasChecks the log is a USDC Transfer to the treasury, then calls verify_foreign_transaction (domain 3) on the MPC. On success moves min(value, in_transit) into the chain's USDC ledger. Once per log. Emits cash_credited (proof: "mpc") or cash_rejected.
report_cashchain: string, tx_hash: string, amount: U128relayer only, chains with proof: Relayer (Robinhood) and Solana30 TGasSame credit, capped by in_transit, once per tx_hash. amount is in the chain's raw USDC units. On Solana tx_hash is the base58 transaction signature. Emits cash_credited (proof: "relayer").

Stock buys

MethodArgsCallerGasEffect
buy_stockchain: stringanyone, EVM chain with a venue, router approved300 TGasFresh price, then MPC-signs a Uniswap v3 SwapRouter02 exactInputSingle of up to max_swap_usdc of the chain's USDC into the thesis stock, minOut = oracle value minus 1%. The ledger books minOut at signing. Emits evm_tx_signed, or buy_stock_skipped on a stale price.
buy_stock_solanablockhash: string, tick_arrays: [i32, u8][]anyone300 TGasFresh price, then MPC-signs (EdDSA) a Raydium CLMM swap_v2 of up to max_swap_usdc USDC into the stock, minOut = oracle value minus 1%. blockhash: recent, base58. tick_arrays: 1 to 3 [start_index, bump] pairs in the swap direction, nearest first. Emits solana_tx_signed.
resign_solanablockhash: string, tick_arrays: [i32, u8][]anyone, 200 NEAR blocks after the last Solana signature300 TGasSigns the last Solana buy again with the same amounts and a new blockhash. The ledger is not touched.
clear_stuck_signaturenoneanyone, 300 blocks after a requestdefaultFrees a signing slot whose callback never completed. The nonce is not consumed. Emits signature_cleared.

Treasury views

MethodArgsReturns
get_treasury_chainsnone{address, mpc, signing, chains: [{config, venue, nonce, approved, usdc, stock, in_transit}], solana: {config, venue, address, usdc_account, stock_account, seq, usdc, stock, in_transit, last_buy} | null}. usdc and stock are raw units of the chain's tokens; in_transit is 6-decimal USDC.
get_signed_txchain: string, nonce: u64Signed raw transaction or null: 0x hex on EVM chains, base64 on Solana (ready for sendTransaction with encoding: base64).

Anyone can broadcast a signed transaction; the keeper's broadcaster does it automatically. See Keeper.

Internal callbacks

These are #[private] and can only be called by the contract itself: on_payout, on_rebalance_price, on_redeem_price, on_fund_price, on_funded, on_cash_verified, on_treasury_key, on_solana_treasury_key, on_buy_price, on_solana_buy_price, on_signed, ft_resolve_transfer.

Read-only calls

All views work with near-cli-rs and no account:

NET="network-config testnet"
near contract call-function as-read-only solidon.testnet get_memes json-args '{}' $NET now
near contract call-function as-read-only solidon.testnet launch_cost json-args '{}' $NET now
near contract call-function as-read-only solidon.testnet get_chains json-args '{}' $NET now
near contract call-function as-read-only honey.solidon.testnet get_pool json-args '{}' $NET now
near contract call-function as-read-only honey.solidon.testnet get_treasury json-args '{}' $NET now
near contract call-function as-read-only honey.solidon.testnet get_treasury_chains json-args '{}' $NET now
near contract call-function as-read-only honey.solidon.testnet quote_buy json-args '{"usdc_in":"10000000"}' $NET now
near contract call-function as-read-only honey.solidon.testnet get_signed_tx json-args '{"chain":"base","nonce":0}' $NET now

Example get_treasury of floor.solidon.testnet:

{
  "circulating": "497487437185929648241206030",
  "epoch_cap": "0",
  "epoch_issued": "0",
  "last_mnav_bps": "0",
  "last_nav": "0",
  "last_rebalance": 0,
  "next_rebalance": 3600,
  "redemption_open": false,
  "stock_units": "0",
  "treasury_usdc": "800000"
}

Events

Every event is a NEP-297 log line EVENT_JSON:{"standard":"solidon","version":"1.0.0","event":"<name>","data":[{...}]}. The meme also emits standard NEP-141 events (ft_mint at launch and on issuance, ft_burn on buyback and redemption, ft_transfer).

EventEmitterdata fields
launchfactorymeme, creator
seedmemeaccount, usdc_in
buymemeaccount, usdc_in, meme_out
sellmemeaccount, meme_in, usdc_out
payout_failedmemeaccount, amount
rebalancememecaller, mnav_bps, nav, twap, redemption_open, outcome, tip
redeemmemeaccount, meme_in, usdc_out
redeem_refundedmemeaccount, meme
treasurymemeevm_address or solana_address
solana_accountsmemeusdc_account, stock_account
cash_sentmemechain, amount, bridge, to
fund_chain_skippedmemechain, reason
cash_returnedmemechain, amount
cash_creditedmemechain, tx_hash, amount, proof (mpc adds log_index)
cash_rejectedmemechain, tx_hash, log_index
buy_stock_skippedmemechain, reason
evm_tx_signedmemechain, nonce, kind, raw
evm_tx_rejectedmemechain, nonce
solana_tx_signedmemechain, seq, kind, tx (base64)
solana_tx_rejectedmemechain, seq
signature_clearedmemechain, nonce

kind is "Approve", {"Swap": {"usdc_in", "min_stock_out"}} or "Resign".

Example rebalance event, as served by the read API:

{
  "event": "rebalance",
  "standard": "solidon",
  "version": "1.0.0",
  "data": {
    "caller": "keeper.solidon.testnet",
    "mnav_bps": "291610",
    "nav": "406123708214",
    "twap": "11843000782134",
    "redemption_open": false,
    "outcome": "no_action",
    "tip": "0"
  }
}

Testnet helpers

ContractMethodArgsNote
usdc.solidon.testnet (mock-ft)mintaccount_id, amountOpen to anyone; registers the account if needed. Plus NEP-141 and NEP-145.
pyth.solidon.testnet (mock-pyth)set_priceprice_id, price: I64, expo: i32, publish_time?: i64Open to anyone; the keeper pushes Chainlink prices.
pyth.solidon.testnetget_price_no_older_thanprice_id, age: u64Returns {price, conf, expo, publish_time} or null
pyth.solidon.testnetget_price_unsafeprice_identifierSame, without the age check

On this page