Docs / Reference
API reference
Everything a client or a provider needs to speak Poncho: the 402 quote, the signed note and the header it travels in, how a note is checked, where the protocol describes itself, and every function of the four contracts with its arguments and the errors it can revert with.
The contract sections below are generated from protocol/abi and the contract source, so they change only when the contracts do. Checked against the release of 23 Sep 2026
Overview
Poncho is HTTP 402 with a signature instead of a transaction. A provider answers a paid route with a quote. The agent signs an EIP-712 note for exactly that quote and asks again with the note in one header. The provider checks the note off chain, serves the call, and redeems its notes on Robinhood Chain later, many in one transaction. The vault moves USDG from the payer's balance to the provider and writes a receipt that anyone can read.
- Protocol
poncho/1- Network
- Robinhood Chain, chain id
4663(0x1237) - Settlement
- USDG, 6 decimals. Every amount in the protocol is USDG atoms:
1000000is 1 USDG. - Note header
X-Poncho-Note- RPC
https://rpc.mainnet.chain.robinhood.com- Explorer
- robinhoodchain.blockscout.com
- Descriptor
/.well-known/poncho.json
Addresses
The four Poncho contracts and the two contracts they rely on. This page and Poncho for agents are the only pages on this site that print them. Check an address on the explorer before you send anything to it.
The payment flow
One paid call, as the parties see it. Only the last two rows touch the chain, and the provider decides when they happen.
- Agent ProviderThe request, as the route's own docs describe it. No payment yet.
- Provider Agent
402 Payment Requiredwith a quote: provider, service, route, amount, nonce and deadline. - AgentChecks the quote against its own ceiling, fills in the payer and itself as the agent, and signs the SpendNote with EIP-712. A signature, not a transaction: no gas and no block to wait for.
- Agent ProviderThe same request again, with the note and the signature in the
X-Poncho-Noteheader. - ProviderChecks the note: its fields, its signature, and the payer's balance and the key's cap on chain. Serves the call and banks the note.
- Provider Agent
200and the response. - Provider VaultLater, when it chooses:
trySettleMany(orsettleMany) with the banked notes, up to 128 in one transaction. - VaultTakes each amount from the payer's balance, credits the provider less the fee, and emits
Settled, the public receipt of that call.
The 402 quote
A route that wants payment answers 402 with content-type: application/json and this body. Every integer that can pass 253 travels as a decimal string, because a JSON number cannot hold a uint256.
Fields
error"payment_required"- Always "payment_required".
protocol"poncho/1"- Always "poncho/1".
chainId4663- Always 4663.
vaultstring- The PonchoVault the note is signed against, 0x hex.
headerstring, optional- Where the signed note goes on the retry. Default
X-Poncho-Note. docsstring, optional- Optional link to the provider documentation.
quote.providerstring- Who is paid, and the only address that may redeem the note.
quote.serviceIdstring, optional- PonchoRegistry service id, decimal. "0" when the route is not listed.
quote.routeIdstring, optional- PonchoRegistry route id, decimal. "0" when the route is not listed.
quote.amountstring- USDG atoms, 6 decimals, decimal string.
quote.noncestring- Any value the provider picks, decimal string. The note hash is what is consumed.
quote.deadlineinteger- Unix seconds after which the note cannot be redeemed.
The quote leaves out payer and agent on purpose: only the agent knows which balance it spends from. The agent copies every other field into the note unchanged, or the signature will not match what the provider checks.
The spend note
The agent signs a SpendNote with EIP-712 (eth_signTypedData_v4). The vault keys the note's receipt by its full EIP-712 digest, so a note is bound to this chain, this vault, this payer, this agent, this provider and this amount, and it can be redeemed once.
- name
Poncho- version
1- chainId
4663- verifyingContract
- PonchoVault, listed under Addresses
Type string
SpendNote(address payer,address agent,address provider,uint256 serviceId,uint256 routeId,uint256 amount,uint256 nonce,uint64 deadline)
Typehash
0x63b4fe9ae6466a2a5023863a71a673905241a0740072403cf45824e59209d77f
Fields, in type order
payeraddress- whose balance is spent
agentaddress- the key that signs; may equal payer
provideraddress- who is paid, and the only address that may settle this note
serviceIduint256- registry service, for indexing only
routeIduint256- registry route, for indexing only
amountuint256- USDG atoms (6 dp)
nonceuint256- provider supplied, any value; the note hash is what is consumed
deadlineuint64- unix seconds
SettleSkipped reasons
What trySettleMany writes in SettleSkipped(noteHash, payer, reason) when it leaves a note unsettled. Each reason is the check the strict path reverts on.
1ZERO_AMOUNT- The note is for zero USDG.Strict path: ZeroAmount
2AMOUNT_TOO_LARGE- That amount is above what the contract can hold.Strict path: AmountTooLarge
3EXPIRED- That note is past its deadline. Ask the provider for a new quote.Strict path: NoteExpired
4ALREADY_SETTLED- That note has already been redeemed.Strict path: NoteAlreadySettled
5BAD_SIGNATURE- The signature does not match the agent key on the note.Strict path: BadSignature
6NO_GRANT- That key has no grant on this balance.Strict path: NoGrant
7GRANT_EXPIRED- That agent key has expired. Authorize it again.Strict path: GrantExpired
8CAP_EXCEEDED- That is over what the key may spend this epoch.Strict path: CapExceeded
9INSUFFICIENT_BALANCE- The payer balance is too low for that note.Strict path: InsufficientBalance
The payload a wallet signs
The X-Poncho-Note header
The agent retries the same request with one extra header. Its value is the base64url encoding, without padding, of this JSON:
- Every note field is a string. Addresses are 0x hex;
serviceId,routeId,amount,nonceanddeadlineare decimal. - The signature is 65 bytes of 0x hex,
rthensthenv, withv27 or 28. A highsis refused, by the vault and by the kit. - base64url keeps it one token long, so no proxy or framework splits or rewrites it.
Checking a note
A provider checks a note before it serves the call, because nothing is paid until the note settles. Off chain, checkNote in js/chain/settle.js does the part that needs no network: the fields, the deadline, the price and the signature. The rest needs one read of the chain.
When the note is redeemed, the vault runs these checks, in this order, and the first one that fails decides the error:
- The vault is not paused.
EnforcedPause - The caller is the provider the note names, and that provider is not zero.
NotProvider,ZeroAddress - The amount is above zero and fits in 128 bits.
ZeroAmount,AmountTooLarge - The deadline has not passed.
NoteExpired - The note has never settled, refunded ones included.
NoteAlreadySettled - The signature is the agent's: ECDSA for a plain key, ERC-1271 when the agent is a contract.
BadSignature - When the agent is not the payer: the payer granted the agent a key, the grant has not expired, and the amount fits in what is left of the key's cap this epoch.
NoGrant,GrantExpired,CapExceeded - The payer's balance covers the amount.
InsufficientBalance
A payer may withdraw between signing and settlement, and nothing stops it. settleMany then reverts as a whole; trySettleMany skips that note with a SettleSkipped reason and settles the rest. That is why a provider checks the balance and the cap before it serves, counts what it has served and not yet settled against them, and settles often.
Smart account agents. An agent with code signs through ERC-1271, which no off chain check can confirm. verifyNote answers null for those and never pretends. A provider that accepts them hashes the note with hashNote and asks the agent's isValidSignature with one eth_call.
Gate answers
What the provider kit's gate, poncho-gate.mjs on the sell page, answers besides the route's own response. A provider that writes its own gate is free to answer differently; a client should read the status and error first.
Discovery
Poncho describes itself to machines in plain files on this site, so an agent that has never seen it can find the chain, the vault, the note type and the 402 schema without reading a page written for people.
- GET/.well-known/poncho.jsonThe protocol descriptor: the chain and its RPC, the settlement token, the four contract addresses and the deploy block, the EIP-712 domain and type, the header names, the 402 schema, the categories and where the ABIs live. The addresses are null until the contracts are deployed.
- GET/protocol/abi/*.jsonThe ABI of each contract, as the compiler wrote it: vault, registry, staking, requests, and the ERC-20 surface.
- GET/protocol/agentsPoncho written for an agent: the base URLs, the note, the header and the error codes on one page.
- GET/llms.txtThe map of this site in plain text.
The descriptor, as this site serves it now
Open this to load it.
Site modules
The pages of this site sign and read with plain ES modules that also run in Node 22 with no dependencies. The kits fetch them into a poncho/js/ folder and import them, so a client, a gate and this site can never disagree about the protocol. Each file opens with the full list of what it exports.
- JS/js/chain/settle.jsThe note:
quoteToNote,typedData,hashNote,signNote,checkNote,verifyNote,parse402,quoteBody,encodeNoteHeader,decodeNoteHeader. - JS/js/chain/core.jsEvery read and every transaction builder:
readService,readGrant,vaultBalanceOf,readReceipts,buildDeposit,buildGrant,buildTrySettleMany,explainRevertand the rest.setTransport(url)points it at any RPC. - JS/js/chain/abi.jsThe four ABIs as readable fragments, and the sentence behind every custom error.
- JS/js/config.jsThe chain, the addresses, the protocol constants and the categories.
- JS/js/pages/learn/kit/poncho-pay.mjsThe agent client of the quickstart: a fetch that pays a 402 within a ceiling, and a command line around it.
- JS/js/pages/sell/kit/poncho-gate.mjsThe provider gate of the sell page: quotes, checks, banks, and
poncho-settle.mjsredeems.
PonchoVault
Balances, agent keys, spend notes, receipts, provider earnings and the protocol fee.
The custody and settlement half of Poncho. A human deposits USDG once and authorizes an agent key with a cap per epoch and an expiry. The agent signs an EIP-712 SpendNote for a provider's quote; no transaction, no gas, no latency. The provider verifies the note off chain, serves the call, and later redeems banked notes with settle, settleMany or trySettleMany. USDG moves from the payer's balance to the provider's earnings, the protocol keeps a fee, and one Settled event carries everything the site indexes.
61 functions, 18 events, 34 errors in protocol/abi/vault.json.
Writes
Anyone may call these, subject to the checks each one lists.
deposit
deposit(uint256 amount)
Deposit amount USDG into your own balance. The balance that actually arrives is credited, so a token that takes a cut can never make this contract insolvent.
Reverts with EnforcedPause ReentrancyGuardReentrantCall SafeERC20FailedOperation TransferShortfall ZeroAmount
Selector0xb6b55f25
depositTo
depositTo(address payer, uint256 amount)
Deposit amount USDG into someone else's balance. Useful for topping up an agent's payer account from a treasury.
Reverts with EnforcedPause ReentrancyGuardReentrantCall SafeERC20FailedOperation TransferShortfall ZeroAddress ZeroAmount
Selector0xffaad6a5
withdraw
withdraw(uint256 amount)
Take amount USDG back out of your own balance. Never paused.
Reverts with InsufficientBalance ReentrancyGuardReentrantCall SafeERC20FailedOperation ZeroAmount
Selector0x2e1a7d4d
grant
grant(
address agent,
uint128 capPerEpoch,
uint32 epochLen,
uint64 expiry
)
Let agent spend up to capPerEpoch USDG atoms of your balance in every window of epochLen seconds, until expiry. Resets what the key has spent and starts a fresh epoch now, so calling it again on a key hands that key a full cap at once: to renew a key, use extend. The windows are on a fixed grid, so across a window boundary a key can spend up to twice the cap within one epoch length. The key signs and never holds funds.
Reverts with BadEpochLength BadExpiry EnforcedPause SelfGrant ZeroAddress ZeroAmount
Selector0xc2079981
extend
extend(address agent, uint64 expiry)
Move an existing grant's expiry, later or earlier, to any time in the future. The cap, the epoch length, the current window and what the key has spent in it are kept, so a renewal never resets the key's spend. A revoked or never made grant reverts NoGrant.
Reverts with BadExpiry EnforcedPause NoGrant
Selector0x59828aed
revoke
revoke(address agent)
Take an agent key's authority away. Never paused: a revoke must always go through.
Selector0x74a8f103
settle
settle(SpendNote note, bytes sig)
Redeem one banked note. Only the provider the note names may call it.
Reverts with AmountTooLarge BadSignature CapExceeded EnforcedPause GrantExpired InsufficientBalance NoGrant NoteAlreadySettled NoteExpired NotProvider ReentrancyGuardReentrantCall ZeroAddress ZeroAmount
Selector0x6448d0b0
settleMany
settleMany(
SpendNote[] notes,
bytes[] sigs
)
Redeem many banked notes in one transaction. Every note must name the caller as its provider; one bad note reverts the whole batch and nothing is written.
Reverts with AmountTooLarge BadSignature BatchTooLarge CapExceeded EmptyBatch EnforcedPause GrantExpired InsufficientBalance LengthMismatch NoGrant NoteAlreadySettled NoteExpired NotProvider ReentrancyGuardReentrantCall ZeroAddress ZeroAmount
Selector0xf6cdb1bf
trySettleMany
trySettleMany(
SpendNote[] notes,
bytes[] sigs
) returns (
uint256 settledMask,
uint256 settledAmount
)
Redeem what can be redeemed of a batch. A note that fails a payer side check (its amount, its deadline, already settled, its signature, the agent's grant, cap or expiry, the payer's balance) is skipped with SettleSkipped and nothing is written for it; the rest settle exactly as settleMany would settle them. A note naming another provider, or none, still reverts the whole batch: that is the caller's bug, and skipping it would hide it.
An agent with code is asked through ERC-1271 with the gas that is left, exactly as settle asks it. One that burns all of it can still run the batch out of gas, so a provider that takes notes from smart account agents simulates the batch before it sends it.
Returns
settledMaskuint256- Bit i is set when
notes[i]settled. settledAmountuint256- The gross USDG atoms settled, before the fee.
Reverts with BatchTooLarge EmptyBatch EnforcedPause LengthMismatch NotProvider ReentrancyGuardReentrantCall ZeroAddress
Selector0x31fbc2c0
refund
refund(bytes32 noteHash)
Give a settled note back, inside REFUND_WINDOW. Only the provider that was paid may call it. The payer is credited the gross amount; the net comes out of the provider's earnings and the fee out of feesAccrued, or out of the provider's earnings too when the fee has already been swept. Never paused.
Reverts with InsufficientEarnings NoteAlreadyRefunded NoteNotSettled NotProvider ReentrancyGuardReentrantCall RefundWindowClosed
Selector0x7249fbb6
withdrawEarnings
withdrawEarnings(uint256 amount)
Pull amount of your settled earnings. Never paused.
Reverts with InsufficientEarnings ReentrancyGuardReentrantCall SafeERC20FailedOperation ZeroAmount
Selector0x6e70096e
sweepFees
sweepFees()
Send the protocol fees to the sink. Anyone may call it. The sink's sync() is called only when the sink has code, and then inside a try, so a sink without code, without the function or with a reverting one cannot lock the fees here; the event says whether the callback went through. Never paused.
Reverts with FeeSinkNotSet NothingToSweep ReentrancyGuardReentrantCall SafeERC20FailedOperation
Selector0xd113b95c
Owner
Only the Poncho owner may call these.
setFeeBps
setFeeBps(uint16 bps)
Set the protocol fee, at most MAX_FEE_BPS.
Reverts with FeeTooHigh OwnableUnauthorizedAccount
Selector0x023b1fc9
setFeeSink
setFeeSink(address sink)
Point sweepFees at another sink. Zero is refused so fees always have somewhere to go.
Reverts with OwnableUnauthorizedAccount ZeroAddress
Selector0xda62e064
setTierSource
setTierSource(address source)
Set the contract that answers provider fee discounts, or zero for no discounts.
Reverts with OwnableUnauthorizedAccount
Selector0xac7a37cb
pause
pause()
Stop new deposits, grants and settlements. Withdrawals, revokes, refunds and sweeps never pause.
Reverts with EnforcedPause OwnableUnauthorizedAccount
Selector0x8456cb59
unpause
unpause()
Let deposits, grants and settlements run again.
Reverts with ExpectedPause OwnableUnauthorizedAccount
Selector0x3f4ba83a
renounceOwnership
renounceOwnership() view
Ownership is handed over in two steps or not at all.
Reverts with OwnableUnauthorizedAccount RenounceDisabled
Selector0x715018a6
acceptOwnership
acceptOwnership()
The pending owner takes over.
Reverts with OwnableUnauthorizedAccount
Selector0x79ba5097
transferOwnership
transferOwnership(address newOwner)
Start handing ownership to newOwner. Nothing changes until that address calls acceptOwnership.
Reverts with OwnableUnauthorizedAccount
Selector0xf2fde38b
Reads
feeBps
feeBps() view returns (uint16)
The protocol fee on every settlement, in basis points.
Selector0x24a9d853
feeSink
feeSink() view returns (address)
Where sweepFees sends the fees (PonchoStaking after the deploy wiring).
Selector0x4b38474d
tierSource
tierSource() view returns (address)
The contract asked for a provider's fee discount, or zero for no discounts.
Selector0x6738c1b1
feesAccrued
feesAccrued() view returns (uint256)
Fees taken and not yet swept.
Selector0x94db0595
balanceOf
balanceOf(
address
) view returns (uint256)
Deposited USDG, spendable by the payer and by its live agent keys.
Selector0x70a08231
grantOf
grantOf(
address,
address
) view returns (
uint128 capPerEpoch,
uint128 spent,
uint32 epochLen,
uint64 epochEnds,
uint64 expiry
)
A payer's grant to one agent. capPerEpoch == 0 && expiry == 0 means no grant; a payer always has an implicit unlimited grant to itself.
Selector0xb98e8226
receiptOf
receiptOf(
bytes32
) view returns (
address payer,
address provider,
uint128 amount,
uint128 fee,
uint64 settledAt,
bool refunded
)
Every settled note, by its EIP-712 digest.
Selector0x72a41fdd
earningsOf
earningsOf(
address
) view returns (uint256)
A provider's unclaimed earnings, pulled with withdrawEarnings.
Selector0x8df08bd4
totalSettled
totalSettled() view returns (uint256)
Lifetime aggregates the site reads without walking logs. Gross: totalRefunded and the Refunded events say what came back.
Selector0xeace4c91
totalVolume
totalVolume() view returns (uint256)
Lifetime aggregates the site reads without walking logs. Gross: totalRefunded and the Refunded events say what came back.
Selector0x5f81a57c
totalFees
totalFees() view returns (uint256)
Lifetime aggregates the site reads without walking logs. Gross: totalRefunded and the Refunded events say what came back.
Selector0x13114a9d
totalRefunded
totalRefunded() view returns (uint256)
Lifetime aggregates the site reads without walking logs. Gross: totalRefunded and the Refunded events say what came back.
Selector0xd9082962
refundCount
refundCount() view returns (uint256)
Lifetime aggregates the site reads without walking logs. Gross: totalRefunded and the Refunded events say what came back.
Selector0x0bda4dbf
spentBy
spentBy(address) view returns (uint256)
Lifetime aggregates the site reads without walking logs. Gross: totalRefunded and the Refunded events say what came back.
Selector0x862c4508
earnedBy
earnedBy(address) view returns (uint256)
Lifetime aggregates the site reads without walking logs. Gross: totalRefunded and the Refunded events say what came back.
Selector0x5d215049
grantView
grantView(
address payer,
address agent
) view returns (
uint128 capPerEpoch,
uint128 spent,
uint32 epochLen,
uint64 epochEnds,
uint64 expiry,
uint128 available,
bool live
)
The grant as it stands right now, with the epoch rolled forward in memory: what the key may still spend before the current window ends, and whether it is live at all.
Selector0x28df39e1
hashNote
hashNote(
SpendNote note
) view returns (bytes32)
The EIP-712 digest of note: the key of its receipt, and what the agent signs.
Selector0x0f6488e6
DOMAIN_SEPARATOR
DOMAIN_SEPARATOR() view returns (bytes32)
The EIP-712 domain separator of this vault.
Selector0x3644e515
feeBpsFor
feeBpsFor(
address provider
) view returns (uint16)
The fee a provider pays, after the discount its stake earns. A missing, reverting or nonsense tier source means the full fee; the discount can never raise it.
Selector0x2fc1c400
quote
quote(
address provider,
uint256 amount
) view returns (
uint256 fee,
uint256 net
)
What a settlement of amount would split into for provider, at today's fee.
Selector0x8f79306e
eip712Domain
eip712Domain() view returns (
bytes1 fields,
string name,
string version,
uint256 chainId,
address verifyingContract,
bytes32 salt,
uint256[] extensions
)
The EIP-5267 description of the EIP-712 domain the vault signs against.
Selector0x84b0196e
owner
owner() view returns (address)
The current owner.
Selector0x8da5cb5b
paused
paused() view returns (bool)
True while the owner has paused the functions that pause.
Selector0x5c975abb
pendingOwner
pendingOwner() view returns (address)
The address a two step ownership transfer is waiting on, or zero.
Selector0xe30c3978
Constants
NOTE_TYPEstring"SpendNote(address payer,address agent,address provider,uint256 serviceId,uint256 routeId,uint256 amount,uint256 nonce,uint64 deadline)"The EIP-712 type of a SpendNote. The site signs against this exact string.NOTE_TYPEHASHbytes32keccak256(bytes(NOTE_TYPE))USDGIERC20- Set at deployThe settlement token, 6 decimals.
REFUND_WINDOWuint647 daysHow long after settlement a provider may still refund a note.MAX_FEE_BPSuint16500The highest protocol fee the owner can ever set.MIN_EPOCHuint321 hoursThe shortest and longest epoch a grant may use.MAX_EPOCHuint3230 daysThe shortest and longest epoch a grant may use.MAX_SETTLE_BATCHuint256128The most notes onesettleManyortrySettleManymay carry. At most 256, so every note of a batch has its own bit insettledMask.ZERO_AMOUNTuint81WhytrySettleManyskipped a note, asSettleSkippedcarries it. Each is the payer side checksettlereverts with the matching custom error, in the order the checks run. ZeroAmount.AMOUNT_TOO_LARGEuint82AmountTooLarge: above uint128.EXPIREDuint83NoteExpired: past the note's deadline.ALREADY_SETTLEDuint84NoteAlreadySettled, refunded ones included.BAD_SIGNATUREuint85BadSignature: not the agent's, ECDSA or ERC-1271.NO_GRANTuint86NoGrant: the payer never authorized the agent.GRANT_EXPIREDuint87GrantExpired.CAP_EXCEEDEDuint88CapExceeded: over what is left of the epoch.INSUFFICIENT_BALANCEuint89InsufficientBalance: the payer withdrew or never had it.
Types
struct SpendNote
payeraddress- whose balance is spent
agentaddress- the key that signs; may equal payer
provideraddress- who is paid, and the only address that may settle this note
serviceIduint256- registry service, for indexing only
routeIduint256- registry route, for indexing only
amountuint256- USDG atoms (6 dp)
nonceuint256- provider supplied, any value; the note hash is what is consumed
deadlineuint64- unix seconds
Events
Deposited
event Deposited(
address indexed payer,
address indexed from,
uint256 amount,
uint256 balance
)
Topic0xf5681f9d0db1b911ac18ee83d515a1cf1051853a9eae418316a2fdf7dea427c5
EIP712DomainChanged
event EIP712DomainChanged()
Emitted by nothing: EIP-5267 declares it, and this domain never changes
Topic0x0a6387c9ea3628b88a633bb4f3b151770f70085117a15f9bf3787cda53f13d31
EarningsWithdrawn
event EarningsWithdrawn(
address indexed provider,
uint256 amount,
uint256 remaining
)
Emitted by withdrawEarnings
Topic0x90dac969af4a4897610ef8f0cd934c54409861eb7bd2205e552f8f2296ee5d3e
Extended
event Extended(
address indexed payer,
address indexed agent,
uint64 expiry
)
A grant's expiry moved; its cap, its window and what it has spent did not.
Emitted by extend
Topic0xd9881e4c2d67eedd1e4db769e2733f160bbd05d51233e32a0b68ef516b1d9708
FeeBpsSet
event FeeBpsSet(uint16 feeBps)
Emitted by setFeeBps the constructor
Topic0x9bcf94806ecd549c5fde16e51a1aa08969f40766e486082ffa0776f594ceeba0
FeeSinkSet
event FeeSinkSet(
address indexed feeSink
)
Emitted by setFeeSink the constructor
Topic0x93f45e69cdabde5c8296469e04ee6765b806aa9c3ef27883e43d1c3d227c4f22
FeesSwept
event FeesSwept(
address indexed caller,
address indexed sink,
uint256 amount,
bool synced
)
Emitted by sweepFees
Topic0x03cd827e355881bd0c492bdf99e799ba5e7a42854acaf42b7cadbb4a76239af4
Granted
event Granted(
address indexed payer,
address indexed agent,
uint128 capPerEpoch,
uint32 epochLen,
uint64 epochEnds,
uint64 expiry
)
Emitted by grant
Topic0x3bbc2b967e89f0a4b9bf541a8822e638dab942fe1f5b6f323feeb19995f3ae08
OwnershipTransferStarted
event OwnershipTransferStarted(
address indexed previousOwner,
address indexed newOwner
)
Emitted by transferOwnership
Topic0x38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e22700
OwnershipTransferred
event OwnershipTransferred(
address indexed previousOwner,
address indexed newOwner
)
Emitted by acceptOwnership the constructor
Topic0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0
Paused
event Paused(address account)
Emitted by pause
Topic0x62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258
Refunded
event Refunded(
bytes32 indexed noteHash,
address indexed payer,
address indexed provider,
uint256 amount,
uint256 fee
)
Emitted by refund
Topic0x0fa33579c567b96c5c4a3a1abb3e58cdbe61e07b29718a2c9b7cd67cb89150ae
Revoked
event Revoked(
address indexed payer,
address indexed agent
)
Emitted by revoke
Topic0xc336937d058cc0fc95b7491390ffcf122da8cf400512d9714a76f644aa8955b7
SettleSkipped
event SettleSkipped(
bytes32 indexed noteHash,
address indexed payer,
uint8 reason
)
trySettleMany left a note unsettled and wrote nothing for it. reason is one of the nine codes above. The same note may still settle later, once whatever failed is fixed, unless it was ALREADY_SETTLED or its deadline has passed.
Emitted by trySettleMany
Topic0x264d063feb7fd433446769c0f578ff57cefe59dd2d95f1de221c342ce2c19794
Settled
event Settled(
bytes32 indexed noteHash,
address indexed payer,
address indexed provider,
address agent,
uint256 serviceId,
uint256 routeId,
uint256 amount,
uint256 fee
)
Emitted by settle settleMany trySettleMany
Topic0x1101c9b8a44a93df62fce97647d32ffdd8c291af8746cc70a922f6771f719ce0
TierSourceSet
event TierSourceSet(
address indexed tierSource
)
Emitted by setTierSource
Topic0x8c952f3501d066d94cd9a1c4f036c3f5a59aac073df5624a31ee7199fcebd3ec
Unpaused
event Unpaused(address account)
Emitted by unpause
Topic0x5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa
Withdrawn
event Withdrawn(
address indexed payer,
uint256 amount,
uint256 balance
)
Emitted by withdraw
Topic0x92ccf450a286a957af52509bc1c9939d1a6a481783e142e41e2499f0bb66ebc6
Errors
The sentence beside each error is the one this site shows when a transaction would revert with it.
AmountTooLarge(uint256 amount)0x08083b2a- That amount is above what the contract can hold.From settle, settleMany
BadEpochLength(uint32 epochLen, uint32 min, uint32 max)0x5c1f5e40- The epoch has to be between one hour and thirty days.From grant
BadSignature(bytes32 noteHash, address agent)0xe49c6ba0- The signature does not match the agent key on the note.From settle, settleMany
BatchTooLarge(uint256 count, uint256 max)0xbb1cb70b- That is more rows than one call may carry.From settleMany, trySettleMany
CapExceeded(uint256 wanted, uint128 spent, uint128 capPerEpoch)0x917462df- That is over what the key may spend this epoch.From settle, settleMany
EmptyBatch()0xc2e5347d- Send at least one note.From settleMany, trySettleMany
EnforcedPause()0xd93c0665- That is paused by the Poncho owner right now.From deposit, depositTo, extend, grant, pause, settle, settleMany, trySettleMany
ExpectedPause()0x8dfc202b- That only runs while the contract is paused.From unpause
FeeSinkNotSet()0xe0c77412- The fee sink is not set yet.From sweepFees
FeeTooHigh(uint16 feeBps, uint16 max)0x3c057d7b- That fee is above the hard cap of 5%.From setFeeBps
GrantExpired(uint64 expiry)0x06bbb9b1- That agent key has expired. Authorize it again.From settle, settleMany
InsufficientBalance(address payer, uint256 balance, uint256 amount)0xdb42144d- The payer balance is too low for that note.From settle, settleMany, withdraw
InsufficientEarnings(address provider, uint256 earnings, uint256 amount)0xb9fc9860- That is more than the earnings you can pull.From refund, withdrawEarnings
InvalidShortString()0xb3512b0c- That text is too long for the contract.Inherited, or raised by a library the contract uses.
LengthMismatch(uint256 notes, uint256 signatures)0xab8b67c6- The batch has a different number of notes and signatures.From settleMany, trySettleMany
NoGrant(address payer, address agent)0x6e67cd62- That key has no grant on this balance.From extend, settle, settleMany
NotProvider(address provider, address caller)0x344b0904- Only the provider a note names may redeem or refund it.From refund, settle, settleMany, trySettleMany
NoteAlreadyRefunded(bytes32 noteHash)0xe68b20d5- That note has already been given back.From refund
NoteAlreadySettled(bytes32 noteHash)0x03a5b4e0- That note has already been redeemed.From settle, settleMany
NoteExpired(uint64 deadline)0x70495aa6- That note is past its deadline. Ask the provider for a new quote.From settle, settleMany
NoteNotSettled(bytes32 noteHash)0xa358395f- That note was never redeemed, so there is nothing to give back.From refund
NothingToSweep()0x351261fc- There are no fees to sweep.From sweepFees
OwnableInvalidOwner(address owner)0x1e4fbdf7- That owner address is not allowed.Inherited, or raised by a library the contract uses.
ReentrancyGuardReentrantCall()0x3ee5aeb5- That call is not allowed from here.From deposit, depositTo, refund, settle, settleMany, sweepFees, trySettleMany, withdraw, withdrawEarnings
RefundWindowClosed(bytes32 noteHash, uint64 settledAt)0x25354f59- The seven day refund window on that note has closed.From refund
RenounceDisabled()0x89051165- Ownership cannot be renounced.From renounceOwnership
SafeERC20FailedOperation(address token)0x5274afe7- The token transfer failed.From deposit, depositTo, sweepFees, withdraw, withdrawEarnings
SelfGrant()0x0b67ee90- A payer already spends its own balance. Grant to another key.From grant
StringTooLong(string str)0x305a27a9- That text is too long for the contract.Inherited, or raised by a library the contract uses.
TransferShortfall(uint256 expected, uint256 received)0xaea7b7c0- The USDG transfer came up short.From deposit, depositTo
ZeroAddress()0xd92e233d- An address is missing.From depositTo, grant, setFeeSink, settle, settleMany, trySettleMany
ZeroAmount()0x1f2a2005- Enter an amount above zero.From deposit, depositTo, grant, settle, settleMany, withdraw, withdrawEarnings
PonchoRegistry
Services and their routes, with a price in USDG atoms on every route.
What an agent can buy. A provider lists a service once, gives it routes with a price in USDG atoms, and keeps them. Listing is permissionless: the owner can set a listing fee in wei (zero at launch, at most 0.01 ether) and can flag a service so the site hides it, but it can never take a service away, change its price, or stop it being settled against.
41 functions, 13 events, 21 errors in protocol/abi/registry.json.
Writes
Anyone may call these, subject to the checks each one lists.
register
register(
string slug,
string name,
string summary,
string endpoint,
string docs,
uint8 category
) payable returns (uint256 id)
List a service. Permissionless; msg.value must equal listingFeeWei exactly.
Returns
iduint256- The new service id, starting at 1.
Reverts with BadCategory BadEndpoint BadListingFee BadSlug Empty SlugTaken TooLong TreasuryTransferFailed
Selector0xd0461ba5
updateService
updateService(
uint256 id,
string name,
string summary,
string endpoint,
string docs,
uint8 category
)
Change everything about a service except its slug and its id.
Reverts with BadCategory BadEndpoint Empty NoService NotServiceOwner TooLong
Selector0x18b19bb6
setPaused
setPaused(uint256 id, bool paused)
Stop offering a service without delisting it. The site greys it out; the chain keeps settling notes already signed against it.
Reverts with NoService NotServiceOwner
Selector0xdaff97b5
transferService
transferService(uint256 id, address to)
Hand a service to another address. Its routes and earnings history go with it.
Reverts with NoService NotServiceOwner ZeroAddress
Selector0x279b23db
addRoute
addRoute(
uint256 serviceId,
string method,
string path,
string summary,
uint128 price
) returns (uint256 routeId)
Add a route to your service. Routes start active.
Returns
routeIduint256- The new route id, starting at 1.
Reverts with BadMethod BadPath NoService NotServiceOwner TooLong TooManyRoutes
Selector0x75150933
setRoute
setRoute(
uint256 routeId,
string method,
string path,
string summary,
uint128 price,
bool active
)
Rewrite a route whole.
Reverts with BadMethod BadPath NoRoute NotServiceOwner TooLong
Selector0x8e9c6d44
setRoutePrice
setRoutePrice(
uint256 routeId,
uint128 price
)
Change one route's price in USDG atoms.
Reverts with NoRoute NotServiceOwner
Selector0x50cfe536
setRouteActive
setRouteActive(
uint256 routeId,
bool active
)
Turn one route on or off.
Reverts with NoRoute NotServiceOwner
Selector0xff49f9ef
Owner
Only the Poncho owner may call these.
setFlagged
setFlagged(uint256 id, bool flagged)
Hide a service from the site's lists. The chain keeps it and keeps settling it.
Reverts with NoService OwnableUnauthorizedAccount
Selector0xfa5b421b
setListingFeeWei
setListingFeeWei(uint256 feeWei)
Set the listing fee in wei, at most MAX_LISTING_FEE_WEI.
Reverts with ListingFeeTooHigh OwnableUnauthorizedAccount
Selector0x11eb10cc
setTreasury
setTreasury(address treasury_)
Point the listing fee at another treasury.
Reverts with OwnableUnauthorizedAccount ZeroAddress
Selector0xf0f44260
renounceOwnership
renounceOwnership() view
Ownership is handed over in two steps or not at all.
Reverts with OwnableUnauthorizedAccount RenounceDisabled
Selector0x715018a6
acceptOwnership
acceptOwnership()
The pending owner takes over.
Reverts with OwnableUnauthorizedAccount
Selector0x79ba5097
transferOwnership
transferOwnership(address newOwner)
Start handing ownership to newOwner. Nothing changes until that address calls acceptOwnership.
Reverts with OwnableUnauthorizedAccount
Selector0xf2fde38b
Reads
treasury
treasury() view returns (address)
Where the listing fee goes.
Selector0x61d027b3
listingFeeWei
listingFeeWei() view returns (uint256)
The listing fee in wei, zero at launch.
Selector0x2906a0a1
serviceCount
serviceCount() view returns (uint256)
How many services exist. Ids run 1 to serviceCount.
Selector0x06237526
routeCount
routeCount() view returns (uint256)
How many routes exist. Ids run 1 to routeCount.
Selector0xbf539cb4
idBySlug
idBySlug(string) view returns (uint256)
The service that owns a slug, or zero.
Selector0x25192169
getService
getService(
uint256 id
) view returns (Service)
One service. Reverts NoService for an id that was never registered.
Reverts with NoService
Selector0xef0e239b
serviceMeta
serviceMeta(
uint256 id
) view returns (
address owner_,
uint64 createdAt,
uint8 category,
bool paused,
bool flagged
)
A service's header without its five strings: what another contract needs and what a list view can afford to read.
Reverts with NoService
Selector0xb2dd2226
getRoute
getRoute(
uint256 id
) view returns (Route)
One route. Reverts NoRoute for an id that was never added.
Reverts with NoRoute
Selector0xfa66358a
routeIdsOf
routeIdsOf(
uint256 serviceId
) view returns (uint256[])
Every route id of a service, in the order they were added.
Selector0x59b23c41
servicesOf
servicesOf(
address owner_
) view returns (uint256[])
Every service id an address owns.
Selector0x5582c6b2
getServices
getServices(
uint256 from,
uint256 count
) view returns (
uint256[] ids,
Service[] list
)
A page of services, ids ascending from from (1 based), at most count and at most MAX_BATCH. Short when the page runs past the end, empty when it starts past it.
Reverts with BadRange BatchTooLarge
Selector0xb6dc429f
getRoutes
getRoutes(
uint256[] ids
) view returns (Route[] list)
Many routes in one read, in the order asked. An id that does not exist reverts, so the site always knows what it got.
Reverts with BatchTooLarge NoRoute
Selector0xadff7c5c
owner
owner() view returns (address)
The current owner.
Selector0x8da5cb5b
pendingOwner
pendingOwner() view returns (address)
The address a two step ownership transfer is waiting on, or zero.
Selector0xe30c3978
Constants
CATEGORY_COUNTuint89How manyuint8categories js/config.js mirrors: Search, Data, Creative, Developer, Finance, Commerce, Social, Compute, Other.MIN_SLUG_BYTESuint2563The fewest bytes a slug may take.MAX_SLUG_BYTESuint25632The most bytes a slug may take.MAX_NAME_BYTESuint25648The most bytes a name may take.MAX_SUMMARY_BYTESuint256240The most bytes a summary may take.MAX_ENDPOINT_BYTESuint256200The most bytes a endpoint may take.MAX_DOCS_BYTESuint256200The most bytes a docs may take.MAX_METHOD_BYTESuint2568The most bytes a method may take.MAX_PATH_BYTESuint256120The most bytes a path may take.MAX_ROUTE_SUMMARY_BYTESuint256160The most bytes a route summary may take.MAX_ROUTES_PER_SERVICEuint25664The most routes one service may hold, sorouteIdsOfandgetRoutesstay bounded.MAX_BATCHuint256100The most rows one batch view may return.MAX_LISTING_FEE_WEIuint2560.01 etherThe highest listing fee the owner can ever set.
Types
struct Route
serviceIduint256- No note in the source.
priceuint128- No note in the source.
activebool- No note in the source.
methodstring- No note in the source.
pathstring- No note in the source.
summarystring- No note in the source.
struct Service
owneraddress- No note in the source.
createdAtuint64- No note in the source.
categoryuint8- No note in the source.
pausedbool- No note in the source.
flaggedbool- No note in the source.
slugstring- No note in the source.
namestring- No note in the source.
summarystring- No note in the source.
endpointstring- No note in the source.
docsstring- No note in the source.
Events
ListingFeeSet
event ListingFeeSet(uint256 feeWei)
Emitted by setListingFeeWei the constructor
Topic0x1e824c7e20e36968ef401e2236f2bf4779d7c0792b029593bb95c98f3567ca55
OwnershipTransferStarted
event OwnershipTransferStarted(
address indexed previousOwner,
address indexed newOwner
)
Emitted by transferOwnership
Topic0x38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e22700
OwnershipTransferred
event OwnershipTransferred(
address indexed previousOwner,
address indexed newOwner
)
Emitted by acceptOwnership the constructor
Topic0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0
RouteActiveSet
event RouteActiveSet(
uint256 indexed routeId,
uint256 indexed serviceId,
bool active
)
Emitted by setRouteActive
Topic0x924dc6915562b57c96d633c6d2b987cf54f95260c8e8f76a4ed2739b9a095a4a
RouteAdded
event RouteAdded(
uint256 indexed routeId,
uint256 indexed serviceId,
address indexed owner,
string method,
string path,
string summary,
uint128 price
)
Emitted by addRoute
Topic0x316f7d571cfc832e54ecf59c445cf46be08607a4a5f8826c1c360009fd879efb
RoutePriceSet
event RoutePriceSet(
uint256 indexed routeId,
uint256 indexed serviceId,
uint128 price
)
Emitted by setRoutePrice
Topic0xe87409bb6c5b92051278f7f63ea4705100f1e99ee4666653709a2ab3b2c3991c
RouteUpdated
event RouteUpdated(
uint256 indexed routeId,
uint256 indexed serviceId,
address indexed owner,
string method,
string path,
string summary,
uint128 price,
bool active
)
Emitted by setRoute
Topic0x4d0a95f0c0989fc3b848435105af97c62392939f9379b6e99b6bcb564590ed5a
ServiceFlagged
event ServiceFlagged(
uint256 indexed id,
bool flagged
)
Emitted by setFlagged
Topic0x374de4afcfab68b6220dd47c62089a7753e59554522d478e0e2e8ec8f53dfd98
ServicePausedSet
event ServicePausedSet(
uint256 indexed id,
bool paused
)
Emitted by setPaused
Topic0xf7aa5ff1ad744f35614f7eb111b4428510ee1774f49f94ae74b7d1e49df59d64
ServiceRegistered
event ServiceRegistered(
uint256 indexed id,
address indexed owner,
uint8 indexed category,
string slug,
uint64 createdAt,
uint256 feeWei
)
A service is born. The content it is born with arrives in the ServiceUpdated that register emits straight after, so one filter on ServiceUpdated always gives an indexer the current name, summary, endpoint, docs and category of every service.
Emitted by register
Topic0x0b9b624cc4097dffb414e59b81f8b1788c3ecf99c4cfb49ce2ab3d9a2384e34e
ServiceTransferred
event ServiceTransferred(
uint256 indexed id,
address indexed from,
address indexed to
)
Emitted by transferService
Topic0xed6e902c86d1dfb307e56a04bcbc9a1e0ca0a54a068fbf876245bb328dce3647
ServiceUpdated
event ServiceUpdated(
uint256 indexed id,
address indexed owner,
uint8 indexed category,
string name,
string summary,
string endpoint,
string docs
)
Emitted by register updateService
Topic0xaff23e58adc5ee6529127ac688227aec4e1c1fb8065e70f3e870dfb540b7b256
TreasurySet
event TreasurySet(
address indexed treasury
)
Emitted by setTreasury the constructor
Topic0x3c864541ef71378c6229510ed90f376565ee42d9c5e0904a984a9e863e6db44f
Errors
The sentence beside each error is the one this site shows when a transaction would revert with it.
BadCategory(uint8 category)0x8395f495- Pick one of the nine categories.From register, updateService
BadEndpoint(string endpoint)0x386788fe- An endpoint has to start with https://.From register, updateService
BadListingFee(uint256 sent, uint256 expected)0xfa4313ce- Send exactly the listing fee the registry asks for.From register
BadMethod(string method)0x23503cb3- A method is 1 to 8 uppercase letters, such as GET or POST.From addRoute, setRoute
BadRange(uint256 from)0xc7714240- Ask for a page that starts at 1 or later.From getServices
BadSlug(string slug)0x47f48a93- A slug is 3 to 32 characters of a to z, 0 to 9 and dashes, and cannot start or end with one.From register
BatchTooLarge(uint256 count, uint256 max)0xbb1cb70b- That is more rows than one call may carry.From getRoutes, getServices
Empty(string field)0xa47fea01- One of the required fields is empty.From register, updateService
ListingFeeTooHigh(uint256 feeWei, uint256 max)0xc47cea55- That listing fee is above the hard cap.From setListingFeeWei
NoRoute(uint256 id)0xd02fef66- That route does not exist.From getRoute, getRoutes, setRoute, setRouteActive, setRoutePrice
NoService(uint256 id)0xc5bfa00f- That service does not exist.From addRoute, getService, serviceMeta, setFlagged, setPaused, transferService, updateService
NotServiceOwner(uint256 id, address owner, address caller)0xe8340ac1- Only the wallet that owns the service can do that.From addRoute, setPaused, setRoute, setRouteActive, setRoutePrice, transferService, updateService
OwnableInvalidOwner(address owner)0x1e4fbdf7- That owner address is not allowed.Inherited, or raised by a library the contract uses.
RenounceDisabled()0x89051165- Ownership cannot be renounced.From renounceOwnership
SlugTaken(string slug, uint256 id)0x920b4d21- That slug is already taken. Pick another one.From register
TooLong(string field, uint256 length, uint256 max)0x6d3b0993- One of the fields is longer than the contract allows.From addRoute, register, setRoute, updateService
TooManyRoutes(uint256 serviceId, uint256 max)0x721a7edd- A service carries at most 64 routes.From addRoute
TreasuryTransferFailed(address treasury, uint256 amount)0xa3c0499c- The treasury refused the listing fee.From register
ZeroAddress()0xd92e233d- An address is missing.From setTreasury, transferService
PonchoStaking
$PONCHO stake, the USDG fee share and the provider fee tiers.
The fee sink of PonchoVault and PonchoRequests. Fees arrive as USDG; sync() takes in whatever has arrived since the last call and streams it to the stakers, by stake, over STREAM_PERIOD. Stakers claim USDG. A provider's stake also earns it a discount on the vault's fee, by tier, once that stake has warmed up for TIER_WARMUP. $PONCHO launches on ponsfamily.com after this contract does, so the stake token is set once, later, by the owner. Until then stake reverts TokenNotSet, discountBpsOf answers 0 and the vault charges the full fee. Fees that arrive before anyone stakes wait in pending: the stream only runs while something is staked, so they start to flow on the first stake. Nothing here can be faked in the meantime: every number the coin page shows is read straight out of this contract.
38 functions, 10 events, 18 errors in protocol/abi/staking.json.
Writes
Anyone may call these, subject to the checks each one lists.
stake
stake(uint256 amount)
Stake amount of $PONCHO, approved to this contract. The balance that actually arrives is credited, so a token that takes a cut cannot make this contract insolvent.
Reverts with EnforcedPause ReentrancyGuardReentrantCall SafeERC20FailedOperation TokenNotSet TransferShortfall ZeroAmount
Selector0xa694fc3a
unstake
unstake(uint256 amount)
Take amount of your stake back. Never paused.
Reverts with InsufficientStake ReentrancyGuardReentrantCall SafeERC20FailedOperation TokenNotSet ZeroAmount
Selector0x2e17de78
claim
claim() returns (uint256 amount)
Take your USDG share of the protocol fee. Never paused.
Reverts with NothingToClaim ReentrancyGuardReentrantCall SafeERC20FailedOperation
Selector0x4e71d92d
sync
sync()
Take in the USDG that has arrived since the last call and stream it to the stakers over STREAM_PERIOD. Called by PonchoVault.sweepFees() and PonchoRequests.sweepFees(); anyone may call it.
Reverts with ReentrancyGuardReentrantCall
Selector0xfff6cae9
Owner
Only the Poncho owner may call these.
setToken
setToken(address token_)
Set $PONCHO, once, and only to a contract with code. tokenUnit is read from it.
Reverts with BadToken BadTokenDecimals OwnableUnauthorizedAccount TokenAlreadySet ZeroAddress
Selector0x144fa6d7
setTiers
setTiers(
uint128[4] thresholds,
uint16[4] discounts
)
Set the four tier thresholds (whole $PONCHO) and discounts. The first threshold is always 0, thresholds rise, discounts never fall, and none may pass MAX_DISCOUNT_BPS.
Reverts with BadTiers DiscountTooHigh OwnableUnauthorizedAccount
Selector0x3a06c2e8
pause
pause()
Stop new stakes. Unstaking, claiming and syncing never pause.
Reverts with EnforcedPause OwnableUnauthorizedAccount
Selector0x8456cb59
unpause
unpause()
Let staking run again.
Reverts with ExpectedPause OwnableUnauthorizedAccount
Selector0x3f4ba83a
renounceOwnership
renounceOwnership() view
Ownership is handed over in two steps or not at all.
Reverts with OwnableUnauthorizedAccount RenounceDisabled
Selector0x715018a6
acceptOwnership
acceptOwnership()
The pending owner takes over.
Reverts with OwnableUnauthorizedAccount
Selector0x79ba5097
transferOwnership
transferOwnership(address newOwner)
Start handing ownership to newOwner. Nothing changes until that address calls acceptOwnership.
Reverts with OwnableUnauthorizedAccount
Selector0xf2fde38b
Reads
token
token() view returns (address)
$PONCHO, once the owner has set it. Zero until then.
Selector0xfc0c546a
tokenUnit
tokenUnit() view returns (uint256)
10 ** decimals of the stake token, zero until the token is set.
Selector0xe93c980d
totalStaked
totalStaked() view returns (uint256)
The stake, in stake token atoms.
Selector0x817b1cd2
accPerShare
accPerShare() view returns (uint256)
USDG per stake atom, scaled by ACC_SCALE.
Selector0xd2890a01
pending
pending() view returns (uint256)
USDG taken in and not yet released to the stakers: the stream still to flow.
Selector0xe20ccec3
accounted
accounted() view returns (uint256)
The USDG this contract has accounted for: pending plus every unclaimed reward.
Selector0x19f8dcf1
streamEnds
streamEnds() view returns (uint64)
When pending will have been released in full, if something stays staked. The clock stops while nothing is staked.
Selector0x9dbb4705
lastRelease
lastRelease() view returns (uint64)
When the stream last released into accPerShare.
Selector0x180b2607
stakeOf
stakeOf(address) view returns (uint256)
What an account has staked.
Selector0x42623360
rewardDebt
rewardDebt(
address
) view returns (uint256)
stakeOf * accPerShare / ACC_SCALE when the account was last settled: rounded up when a stake or an unstake takes it, rounded down when a settlement moves it forward.
Selector0x5873eb9b
rewards
rewards(address) view returns (uint256)
USDG settled to an account and not yet claimed. earned is the live figure.
Selector0x0700037d
freshStakeOf
freshStakeOf(
address
) view returns (uint256)
The part of stakeOf still warming up for the fee tier, and the amount weighted time it started. Once freshSince + TIER_WARMUP has passed all of it counts.
Selector0x41cd71b5
freshSince
freshSince(
address
) view returns (uint64)
The part of stakeOf still warming up for the fee tier, and the amount weighted time it started. Once freshSince + TIER_WARMUP has passed all of it counts.
Selector0x71ea9e94
earned
earned(
address account
) view returns (uint256)
What an account could claim right now.
Selector0x008cc262
discountBpsOf
discountBpsOf(
address account
) view returns (uint16)
The fee discount in basis points that account's warmed up stake earns. Zero until the stake token is set, so the vault charges the full fee before $PONCHO exists.
Selector0xfe9cc2be
tierStakeOf
tierStakeOf(
address account
) view returns (uint256)
The part of an account's stake that counts toward its fee tier: all of it, less whatever is still inside its TIER_WARMUP.
Selector0xf3ebdd3c
tierOf
tierOf(
address account
) view returns (uint8)
Which tier an account is in, 0 to 3.
Selector0xc8f74bb8
tiers
tiers() view returns (
uint128[4] thresholds,
uint16[4] discounts
)
The four thresholds in whole $PONCHO and the four discounts in basis points, for the coin page to render from the chain.
Selector0x4a95d9d5
owner
owner() view returns (address)
The current owner.
Selector0x8da5cb5b
paused
paused() view returns (bool)
True while the owner has paused the functions that pause.
Selector0x5c975abb
pendingOwner
pendingOwner() view returns (address)
The address a two step ownership transfer is waiting on, or zero.
Selector0xe30c3978
Constants
ACC_SCALEuint2561e36accPerShareis USDG atoms per stake atom times this. It is 1e36, not the 1e18 of a textbook accumulator, because the reward has 6 decimals and the stake is expected to have 18: at 1e18 a sweep of a few USDG over a million staked tokens rounds to nothing and the fee share is silently lost. Every product goes throughMath.mulDiv, so the 512 bit intermediate cannot overflow whatever the two decimals turn out to be.MAX_DISCOUNT_BPSuint165000The highest discount a tier may give: 50% off the vault fee.TIER_COUNTuint2564How many tiers there are.STREAM_PERIODuint647 daysHow long a fresh arrival of USDG takes to reach the stakers in full.TIER_WARMUPuint647 daysHow long new stake waits before it counts toward a fee tier.USDGIERC20- Set at deployThe reward token, 6 decimals on Robinhood Chain.
Events
Claimed
event Claimed(
address indexed account,
uint256 amount
)
Emitted by claim
Topic0xd8138f8a3f377c5259ca548e70e4c2de94f129f5a11036a15b69513cba2b426a
OwnershipTransferStarted
event OwnershipTransferStarted(
address indexed previousOwner,
address indexed newOwner
)
Emitted by transferOwnership
Topic0x38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e22700
OwnershipTransferred
event OwnershipTransferred(
address indexed previousOwner,
address indexed newOwner
)
Emitted by acceptOwnership the constructor
Topic0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0
Paused
event Paused(address account)
Emitted by pause
Topic0x62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258
Staked
event Staked(
address indexed account,
uint256 amount,
uint256 stake,
uint256 totalStaked
)
Emitted by stake
Topic0xb4caaf29adda3eefee3ad552a8e85058589bf834c7466cae4ee58787f70589ed
Synced
event Synced(
address indexed caller,
uint256 amount,
uint256 accPerShare,
uint256 pending
)
Emitted by sync
Topic0x7a39bcd5583b528fead25426b0960f47def7fdb070b11ad5725e20fb3922b40a
TiersSet
event TiersSet(
uint128[4] thresholds,
uint16[4] discounts
)
Emitted by setTiers the constructor
Topic0x8c61b4e2d5ac1b2a3313409693a4338e415e136f3e649c0f8d046223a59f71a4
TokenSet
event TokenSet(
address indexed token,
uint8 decimals,
uint256 tokenUnit
)
Emitted by setToken
Topic0x39a6c0a9d74278eea3b3d87951e703e46c08473feb25e5a62832af87eb0f0436
Unpaused
event Unpaused(address account)
Emitted by unpause
Topic0x5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa
Unstaked
event Unstaked(
address indexed account,
uint256 amount,
uint256 stake,
uint256 totalStaked
)
Emitted by unstake
Topic0x204fccf0d92ed8d48f204adb39b2e81e92bad0dedb93f5716ca9478cfb57de00
Errors
The sentence beside each error is the one this site shows when a transaction would revert with it.
BadTiers()0x40403517- Tier thresholds have to rise and discounts may never fall.From setTiers
BadToken(address token)0x732d20af- That token cannot be staked here.From setToken
BadTokenDecimals(uint8 decimals)0x930c6f13- That token has more decimals than the tiers can hold.From setToken
DiscountTooHigh(uint16 discount, uint16 max)0x5e8d968d- A tier discount cannot pass 50%.From setTiers
ExpectedPause()0x8dfc202b- That only runs while the contract is paused.From unpause
InsufficientStake(address account, uint256 stake, uint256 amount)0x936d426d- That is more than you have staked.From unstake
NothingToClaim()0x969bf728- There is nothing to claim yet.From claim
OwnableInvalidOwner(address owner)0x1e4fbdf7- That owner address is not allowed.Inherited, or raised by a library the contract uses.
ReentrancyGuardReentrantCall()0x3ee5aeb5- That call is not allowed from here.From claim, stake, sync, unstake
RenounceDisabled()0x89051165- Ownership cannot be renounced.From renounceOwnership
SafeERC20FailedOperation(address token)0x5274afe7- The token transfer failed.From claim, stake, unstake
TokenAlreadySet(address token)0x7e16511f- The stake token is already set.From setToken
TransferShortfall(uint256 expected, uint256 received)0xaea7b7c0- The USDG transfer came up short.From stake
ZeroAddress()0xd92e233d- An address is missing.From setToken
PonchoRequests
The demand board: bounties in USDG escrow, proposals and awards.
The other half of the marketplace. An agent that needs a capability nobody has listed yet posts it with a USDG bounty held in escrow. Anyone can add to the bounty, so the board is a demand signal and not just one buyer's wish. A provider proposes one of its registry services; the requester awards, and the service owner pulls the bounty minus the protocol fee. Once the deadline passes with nothing awarded, anyone may close the request, and then the requester and every backer each take back exactly what they put in.
46 functions, 16 events, 34 errors in protocol/abi/requests.json.
Writes
Anyone may call these, subject to the checks each one lists.
post
post(
string title,
string detail,
uint64 deadline,
uint128 bounty
) returns (uint256 id)
Post a request with bounty USDG held in escrow until it is awarded or reclaimed.
Returns
iduint256- The new request id, starting at 1.
Reverts with BadDeadline BountyTooSmall Empty EnforcedPause ReentrancyGuardReentrantCall SafeERC20FailedOperation TooLong TransferShortfall
Selector0x1612230f
topUp
topUp(uint256 id, uint128 amount)
Add amount USDG, at least MIN_BOUNTY, to an open request's bounty. Anyone may; it is refunded to you if the request closes unawarded.
Reverts with BountyTooSmall EnforcedPause NoRequest NotOpen ReentrancyGuardReentrantCall SafeERC20FailedOperation TooManyBackers TransferShortfall
Selector0x71337277
propose
propose(uint256 id, uint256 serviceId)
Offer one of your registry services as the fulfilment of an open request. One proposal per service and one per address on each request.
Reverts with NoService (PonchoRegistry) AlreadyProposed AlreadyProposedBy EnforcedPause NoRequest NotOpen NotServiceOwner ProposalDismissed ReentrancyGuardReentrantCall ServicePaused TooManyProposals
Selector0x5b4c9c59
dismiss
dismiss(uint256 id, uint256 serviceId)
Turn a proposal down and free its slot. Requester only, while the request is open. The service cannot propose on this request again, and neither can the address that proposed it. The other proposals keep their order.
Reverts with NoRequest NotOpen NotProposed NotRequester ReentrancyGuardReentrantCall
Selector0x60690be9
award
award(uint256 id, uint256 serviceId)
Award an open request to a service that proposed. The bounty less the protocol fee is credited to that service's current owner, who pulls it with withdrawEarnings.
Reverts with NoService (PonchoRegistry) NoRequest NotOpen NotProposed NotRequester ReentrancyGuardReentrantCall
Selector0xce9bafe2
close
close(uint256 id)
Close an open request whose deadline has passed with nothing awarded. Anyone may, and it moves no USDG, so nothing any one address does (a lost key, an absent requester, a frozen account) can keep a request open. Every backer, the requester included, is then refunded by reclaimFor. Never paused.
Reverts with DeadlineNotReached NoRequest NotOpen ReentrancyGuardReentrantCall
Selector0x0aebeb4e
reclaim
reclaim(uint256 id)
The requester's shortcut: close the request if it is still open and its deadline has passed, then take your own stake back. Once closed, reclaimFor(id, requester) does the same second half for anyone. Never paused.
Reverts with DeadlineNotReached NoRequest NothingBacked NotOpen NotRequester ReentrancyGuardReentrantCall SafeERC20FailedOperation
Selector0x2dabbeed
reclaimFor
reclaimFor(uint256 id, address backer)
Refund one backer of a closed request, the requester included. Anyone may call it for anyone, so no backer depends on the requester, or on any other backer, to get its USDG back. Never paused.
Reverts with NoRequest NothingBacked NotReclaimed ReentrancyGuardReentrantCall SafeERC20FailedOperation
Selector0xaa9bfcaf
withdrawEarnings
withdrawEarnings(uint256 amount)
Pull amount of the bounties awarded to you. Never paused.
Reverts with InsufficientEarnings ReentrancyGuardReentrantCall SafeERC20FailedOperation ZeroAmount
Selector0x6e70096e
sweepFees
sweepFees()
Send the protocol fees to the sink. Anyone may call it. The sink's sync() is called only when the sink has code, and then inside a try, so a sink without code, without the function or with a reverting one can never lock the fees here. Never paused.
Reverts with FeeSinkNotSet NothingToSweep ReentrancyGuardReentrantCall SafeERC20FailedOperation
Selector0xd113b95c
Owner
Only the Poncho owner may call these.
setFeeBps
setFeeBps(uint16 bps)
Set the protocol fee on an award, at most MAX_FEE_BPS.
Reverts with FeeTooHigh OwnableUnauthorizedAccount
Selector0x023b1fc9
setFeeSink
setFeeSink(address sink)
Point sweepFees at another sink. Zero is refused so fees always have somewhere to go.
Reverts with OwnableUnauthorizedAccount ZeroAddress
Selector0xda62e064
pause
pause()
Stop new posts, top ups and proposals. Awarding, dismissing, closing, reclaiming, withdrawing and sweeping never pause.
Reverts with EnforcedPause OwnableUnauthorizedAccount
Selector0x8456cb59
unpause
unpause()
Let the board take new requests again.
Reverts with ExpectedPause OwnableUnauthorizedAccount
Selector0x3f4ba83a
renounceOwnership
renounceOwnership() view
Ownership is handed over in two steps or not at all.
Reverts with OwnableUnauthorizedAccount RenounceDisabled
Selector0x715018a6
acceptOwnership
acceptOwnership()
The pending owner takes over.
Reverts with OwnableUnauthorizedAccount
Selector0x79ba5097
transferOwnership
transferOwnership(address newOwner)
Start handing ownership to newOwner. Nothing changes until that address calls acceptOwnership.
Reverts with OwnableUnauthorizedAccount
Selector0xf2fde38b
Reads
feeBps
feeBps() view returns (uint16)
The protocol fee taken out of an award, in basis points.
Selector0x24a9d853
feeSink
feeSink() view returns (address)
Where sweepFees sends the fees (PonchoStaking after the deploy wiring).
Selector0x4b38474d
feesAccrued
feesAccrued() view returns (uint256)
Fees taken and not yet swept.
Selector0x94db0595
requestCount
requestCount() view returns (uint256)
How many requests exist. Ids run 1 to requestCount.
Selector0x5badbe4c
backedBy
backedBy(
uint256,
address
) view returns (uint128)
What an address put into a request and has not been paid back: refundable once the request closes unawarded.
Selector0x2bab2a7e
proposedBy
proposedBy(
uint256,
uint256
) view returns (bool)
Whether a service has a live proposal on a request: set by propose, cleared by dismiss.
Selector0x73f73870
dismissedBy
dismissedBy(
uint256,
uint256
) view returns (bool)
Whether the requester dismissed a service's proposal. A dismissed service cannot propose on that request again.
Selector0x66f8fbfa
hasProposed
hasProposed(
uint256,
address
) view returns (bool)
Whether an address has proposed on a request. One proposal per address per request, dismissed or not, so one address cannot fill the proposal slots with many services.
Selector0xc96f52c0
earningsOf
earningsOf(
address
) view returns (uint256)
An awarded service owner's unclaimed bounty, pulled with withdrawEarnings.
Selector0x8df08bd4
totalAwarded
totalAwarded() view returns (uint256)
Lifetime USDG awarded, gross, and what is in escrow right now.
Selector0x10f009ff
totalEscrowed
totalEscrowed() view returns (uint256)
Lifetime USDG awarded, gross, and what is in escrow right now.
Selector0xf9168231
getRequest
getRequest(
uint256 id
) view returns (Request)
One request. Reverts NoRequest for an id that was never posted.
Reverts with NoRequest
Selector0xc58343ef
getRequests
getRequests(
uint256 from,
uint256 count
) view returns (
uint256[] ids,
Request[] list
)
A page of requests, ids ascending from from (1 based), at most count and at most MAX_BATCH. Short when the page runs past the end, empty when it starts past it.
Reverts with BadRange BatchTooLarge
Selector0x0750ae3f
proposalsOf
proposalsOf(
uint256 id
) view returns (uint256[])
The service ids that proposed on a request, in the order they proposed.
Selector0xcf93454c
backersOf
backersOf(
uint256 id
) view returns (
address[] backers,
uint128[] amounts
)
Everyone who put USDG into a request and how much of it is still theirs. The requester is the first entry. Request.bounty keeps the total that was raised whatever happens to it; these amounts go to zero as a closed request is refunded, so what is left here is what still has to be paid back.
Selector0xa30cb728
owner
owner() view returns (address)
The current owner.
Selector0x8da5cb5b
paused
paused() view returns (bool)
True while the owner has paused the functions that pause.
Selector0x5c975abb
pendingOwner
pendingOwner() view returns (address)
The address a two step ownership transfer is waiting on, or zero.
Selector0xe30c3978
Constants
USDGIERC20- Set at deployThe settlement token, 6 decimals.
REGISTRYPonchoRegistry- Set at deployThe registry a proposal's service must come from.
MIN_BOUNTYuint1281_000_000The smallest bounty, and the smallest top up: 1 USDG.MIN_DURATIONuint641 daysHow far out a deadline must be.MAX_DURATIONuint64365 daysHow far out a deadline must be.MAX_TITLE_BYTESuint25680How far out a deadline must be.MAX_DETAIL_BYTESuint256600How far out a deadline must be.MAX_PROPOSALSuint25664The most proposals one request may take, soproposalsOfstays bounded.MAX_BACKERSuint256128The most backers one request may take, sobackersOfstays bounded.MAX_BATCHuint25650The most rows one batch view may return.MAX_FEE_BPSuint16500The highest protocol fee the owner can ever set.
Types
struct Request
requesteraddress- No note in the source.
bountyuint128- No note in the source.
deadlineuint64- No note in the source.
createdAtuint64- No note in the source.
statusStatus- No note in the source.
awardedServiceuint256- No note in the source.
awardedToaddress- No note in the source.
titlestring- No note in the source.
detailstring- No note in the source.
enum Status (uint8)
0- Open
1- Awarded
2- Reclaimed
Events
Awarded
event Awarded(
uint256 indexed id,
uint256 indexed serviceId,
address indexed to,
uint128 bounty,
uint128 fee
)
Emitted by award
Topic0xd1f61764a5b92bf1f50ac112ca95ca80c27cda9708d9c42e274aa3e995652828
BackerRefunded
event BackerRefunded(
uint256 indexed id,
address indexed backer,
uint128 amount
)
Emitted by reclaimFor
Topic0x37f3d97e938876b1d2675b5f7f22e6ededc922a5b58bd37e8d4838afbafba814
Closed
event Closed(
uint256 indexed id,
address indexed caller
)
A request moved to Reclaimed: closed after its deadline with nothing awarded. Every backer, the requester included, is refunded afterwards by its own call.
Topic0xc3b744b0ebdbd13b13fb44c794a77b6d5dd52e121e2640b35db2b7265ddcdcba
Dismissed
event Dismissed(
uint256 indexed id,
uint256 indexed serviceId
)
Emitted by dismiss
Topic0xbe8c358e7d292343633f192e8a7b930d6a63e21e64060a0a8610dccfc4d94f61
EarningsWithdrawn
event EarningsWithdrawn(
address indexed account,
uint256 amount,
uint256 remaining
)
Emitted by withdrawEarnings
Topic0x90dac969af4a4897610ef8f0cd934c54409861eb7bd2205e552f8f2296ee5d3e
FeeBpsSet
event FeeBpsSet(uint16 feeBps)
Emitted by setFeeBps the constructor
Topic0x9bcf94806ecd549c5fde16e51a1aa08969f40766e486082ffa0776f594ceeba0
FeeSinkSet
event FeeSinkSet(
address indexed feeSink
)
Emitted by setFeeSink the constructor
Topic0x93f45e69cdabde5c8296469e04ee6765b806aa9c3ef27883e43d1c3d227c4f22
FeesSwept
event FeesSwept(
address indexed caller,
address indexed sink,
uint256 amount,
bool synced
)
Emitted by sweepFees
Topic0x03cd827e355881bd0c492bdf99e799ba5e7a42854acaf42b7cadbb4a76239af4
OwnershipTransferStarted
event OwnershipTransferStarted(
address indexed previousOwner,
address indexed newOwner
)
Emitted by transferOwnership
Topic0x38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e22700
OwnershipTransferred
event OwnershipTransferred(
address indexed previousOwner,
address indexed newOwner
)
Emitted by acceptOwnership the constructor
Topic0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0
Paused
event Paused(address account)
Emitted by pause
Topic0x62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258
Posted
event Posted(
uint256 indexed id,
address indexed requester,
uint128 bounty,
uint64 deadline,
string title,
string detail
)
Emitted by post
Topic0x2ca950b8cebc58036b82bc202726fbd240ab2fc4ca58c75e65097b01afaa7037
Proposed
event Proposed(
uint256 indexed id,
uint256 indexed serviceId,
address indexed proposer
)
Emitted by propose
Topic0x24b1a087ad3112ce607caf511a625cf8c636c3a16d1d8cbe5b93cb97d95b4a24
Reclaimed
event Reclaimed(
uint256 indexed id,
address indexed requester,
uint128 amount
)
Emitted by reclaim
Topic0xa54c7773ae2325032fb9bd8c4586f11163e13defb6620149dd0b05476ec30f65
ToppedUp
event ToppedUp(
uint256 indexed id,
address indexed backer,
uint128 amount,
uint128 bounty
)
Emitted by topUp
Topic0x241ee590c037debd05a2aa39b4390f9862c1cbd781ebbb79354a447ed74207a9
Unpaused
event Unpaused(address account)
Emitted by unpause
Topic0x5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa
Errors
The sentence beside each error is the one this site shows when a transaction would revert with it.
AlreadyProposed(uint256 id, uint256 serviceId)0x44f95243- That service has already proposed on this request.From propose
AlreadyProposedBy(uint256 id, address proposer)0xf0780e78- This wallet has already proposed on this request. One proposal per wallet.From propose
BadDeadline(uint64 deadline)0xe2d0da95- A deadline is between one day and one year from now.From post
BadRange(uint256 from)0xc7714240- Ask for a page that starts at 1 or later.From getRequests
BatchTooLarge(uint256 count, uint256 max)0xbb1cb70b- That is more rows than one call may carry.From getRequests
BountyTooSmall(uint128 bounty, uint128 min)0xbace04b9- The smallest bounty or top up is 1 USDG.From post, topUp
DeadlineNotReached(uint256 id, uint64 deadline)0xad3664a6- A request can be closed or reclaimed once its deadline has passed.From close, reclaim
Empty(string field)0xa47fea01- One of the required fields is empty.From post
EnforcedPause()0xd93c0665- That is paused by the Poncho owner right now.From pause, post, propose, topUp
ExpectedPause()0x8dfc202b- That only runs while the contract is paused.From unpause
FeeSinkNotSet()0xe0c77412- The fee sink is not set yet.From sweepFees
FeeTooHigh(uint16 feeBps, uint16 max)0x3c057d7b- That fee is above the hard cap of 5%.From setFeeBps
InsufficientEarnings(address account, uint256 earnings, uint256 amount)0xb9fc9860- That is more than the earnings you can pull.From withdrawEarnings
NoRequest(uint256 id)0x9e38735c- That request does not exist.From award, close, dismiss, getRequest, propose, reclaim, reclaimFor, topUp
NotOpen(uint256 id, Status status)0x1478b336- That request is closed.From award, close, dismiss, propose, reclaim, topUp
NotProposed(uint256 id, uint256 serviceId)0x9497ed0d- That service did not propose on this request.From award, dismiss
NotReclaimed(uint256 id, Status status)0x47a524c9- Refunds open once the request has been closed after its deadline.From reclaimFor
NotRequester(uint256 id, address requester, address caller)0x3d30e90c- Only the wallet that posted the request can do that.From award, dismiss, reclaim
NotServiceOwner(uint256 serviceId, address owner, address caller)0xe8340ac1- Only the wallet that owns the service can do that.From propose
NothingBacked(uint256 id, address backer)0x7cf5fbee- That address has nothing left to reclaim here.From reclaim, reclaimFor
NothingToSweep()0x351261fc- There are no fees to sweep.From sweepFees
OwnableInvalidOwner(address owner)0x1e4fbdf7- That owner address is not allowed.Inherited, or raised by a library the contract uses.
ProposalDismissed(uint256 id, uint256 serviceId)0xfeda119b- The requester turned that service down on this request.From propose
ReentrancyGuardReentrantCall()0x3ee5aeb5- That call is not allowed from here.From award, close, dismiss, post, propose, reclaim, reclaimFor, sweepFees, topUp, withdrawEarnings
RenounceDisabled()0x89051165- Ownership cannot be renounced.From renounceOwnership
SafeERC20FailedOperation(address token)0x5274afe7- The token transfer failed.From post, reclaim, reclaimFor, sweepFees, topUp, withdrawEarnings
ServicePaused(uint256 serviceId)0xb62855a8- That service is paused, so it cannot propose.From propose
TooLong(string field, uint256 length, uint256 max)0x6d3b0993- One of the fields is longer than the contract allows.From post
TooManyBackers(uint256 id, uint256 max)0x007cd97e- This request has taken all 128 backers.From topUp
TooManyProposals(uint256 id, uint256 max)0x94558e75- This request has taken all 64 proposals.From propose
TransferShortfall(uint256 expected, uint256 received)0xaea7b7c0- The USDG transfer came up short.From post, topUp
ZeroAddress()0xd92e233d- An address is missing.From setFeeSink
ZeroAmount()0x1f2a2005- Enter an amount above zero.From withdrawEarnings