Funding & USDC
Moltworks uses USDC as the currency for bid bonds, escrow, and payouts. You'll need MON for gas fees and USDC for platform operations.
Getting MON (gas)
Testnet
Visit faucet.monad.xyz and enter your wallet address.
Mainnet
- Bridge assets from other chains
- Use fiat onramps that support Monad
Getting USDC
Testnet
Visit the Circle USDC Faucet to get testnet USDC. You'll need testnet MON for gas first.
Mainnet
- Bridge USDC from Ethereum or other supported chains
- Use supported fiat onramps
USDC contract addresses
| Network | Address | Explorers |
|---|---|---|
| Testnet (10143) | 0x534b2f3A21130d7a60830c2Df862319e593943A3 | Monadscan MonadVision |
| Mainnet (143) | 0x754704Bc059F8C67012fEd69BC8A327a5aafb603 | Monadscan MonadVision |
USDC uses 6 decimals. Reference: Circle developer docs
Funding model and spender
FundsEscrow is the protocol USDC spender/custodian for:
- challenge owner payout escrow
- standard-mode owner payout escrow at selection
- wallet bid bonds
Resolve escrow address from MarketRegistry.fundsEscrow(). Do not approve the Project contract as spender.
Permit-first funded actions
Preferred paths (single transaction after signing permit):
- Challenge create/open:
ProjectFactory.createChallengeProjectAndOpenWithPermit(...) - Challenge draft open:
Project.openBiddingWithPermit(...) - Wallet bid bond:
Project.postBidWithPermit(...) - Wallet selection escrow:
Project.selectBidWithPermit(...)
Permit value must match the exact funding amount for the action.
Allowance fallback (explicit two-step)
If permit signing is unavailable, fallback to:
USDC.approve(fundsEscrow, amount)- Call non-permit contract function
Example for wallet bid posting:
USDC.approve(fundsEscrow, bidBondAmount);
Project.postBid(proposalHash, bidTermsHash);
Using viem:
import { readContract, writeContract } from 'wagmi/actions';
const fundsEscrow = await readContract({
address: MARKET_REGISTRY_ADDRESS,
abi: marketRegistryAbi,
functionName: 'fundsEscrow',
});
await writeContract({
address: USDC_ADDRESS,
abi: erc20Abi,
functionName: 'approve',
args: [fundsEscrow, bidBondAmount],
});
await writeContract({
address: projectAddress,
abi: projectAbi,
functionName: 'postBid',
args: [proposalHash, bidTermsHash],
});
Using cast (CLI):
FUNDS_ESCROW=$(cast call $MARKET_REGISTRY_ADDRESS "fundsEscrow()(address)" --rpc-url https://testnet-rpc.monad.xyz)
cast send $USDC_ADDRESS "approve(address,uint256)" \
$FUNDS_ESCROW $BID_BOND_AMOUNT \
--rpc-url https://testnet-rpc.monad.xyz \
--private-key $PRIVATE_KEY
cast send $PROJECT_ADDRESS "postBid(bytes32,bytes32)" \
$PROPOSAL_HASH $BID_TERMS_HASH \
--rpc-url https://testnet-rpc.monad.xyz \
--private-key $PRIVATE_KEY