Für Entwickler / SENDIT
Spot-, pUSD- und Copy-Contracts
Jeder davon ist ein Venue der Bank oder ein Konto in der Bank: Das Geld kommt von accountOf(msg.sender) und geht in die Bank zurück.
Kauft, verkauft und startet gestartete Tokens mit Bank-ETH, vor dem bestehenden PepperLauncher, sodass die Tokens in der Bank liegen, wo ein Schlüssel sie verkaufen kann. Er ist der einzige begrenzte Venue der Bank. launch salzt die Token-Adresse mit dem Konto, sodass jedes Konto seinen eigenen Salt-Raum hat; predictToken(account, ...) nennt Ihnen die Adresse vorab. Der Launcher sieht den Router als Creator; der Router speichert das Konto in creatorOf, und collect(token) leitet die Creator-Gebühren (WETH und den Token) an die Wallet dieses Kontos weiter. Verwenden Sie die whyNot-Views vor dem Senden.
Launched tokens bought, sold and launched with bank money, in front of the existing PepperLauncher. A capped venue: a key's ETH spent here counts against the account's caps. It holds nothing between calls.
Trading
| Function | What it does |
|---|
| buy(address token, uint256 ethIn, uint256 minTokensOut) returns (uint256 tokensOut) | Spends ethIn of the account's bank ETH; tokens and any unused ETH land in its bank balance. |
|---|
| sell(address token, uint256 amountIn, uint256 minEthOut) returns (uint256 ethOut) | Sells bank-held tokens; the ETH lands in the bank balance. |
|---|
| launch((string name, string symbol, bytes32 imageHash, string description, bytes32 salt, uint256 minTokensOut) a, uint256 ethIn) returns (address token, uint256 tokensOut) | Launches with bank ETH (the launch fee, then the creator's first buy). The account is recorded as the creator. |
|---|
| collect(address token) returns (uint256 wethOut, uint256 tokensOut) | Permissionless: a router-launched token's creator fees, forwarded to the creator's wallet. |
|---|
| forwardStrayWeth(address token, uint256 amount) | The bank's operator: WETH a direct launcher collect left here, to that token's creator and nowhere else. |
|---|
Reading
| Function | What it does |
|---|
| whyNotBuy(address account, address token, uint256 ethIn) view returns (string) | Why buy would fail, or "": "paused", the launcher's reason, "balance" or "cap". |
|---|
| whyNotSell(address account, address token, uint256 amountIn) view returns (string) | Why sell would fail, or "". |
|---|
| whyNotLaunch(address account, LaunchArgs a, uint256 ethIn) view returns (string) | Why launch would fail, or "". |
|---|
| predictToken(address creator, string name, string symbol, bytes32 imageHash, bytes32 salt) view returns (address) | Where launch by this account deploys the token. |
|---|
| creatorOf(address token) view returns (address creator) | The account that launched a token through the router. |
|---|
| launcher() view returns (address) | PepperLauncher. |
|---|
| bank() view returns (address) | SenditBank. |
|---|
| weth() view returns (address) | WETH. |
|---|
| VERSION() view returns (uint256) | 1. |
|---|
Events
| Event | What it does |
|---|
| SpotBought(address indexed account, address indexed token, uint256 ethIn, uint256 tokensOut, uint256 ethRefunded) | A buy, naming the account. |
|---|
| SpotSold(address indexed account, address indexed token, uint256 tokensIn, uint256 ethOut) | A sell. |
|---|
| LaunchedFor(address indexed token, address indexed creator, uint256 ethIn, uint256 tokensOut) | A launch; creator is the account. |
|---|
| CreatorFeesForwarded(address indexed token, address indexed creator, uint256 weth, uint256 tokens) | Creator fees sent on to the creator's wallet. |
|---|
pUSD gegen ETH zu einem Dollar, bepreist über die ETH/USD-Runde des Orakels, genau so gelesen, wie die Perps-Engine sie liest: pusdOut = ethIn x answer / 10^(18 + decimals - 6), abgerundet. Keine Gebühr. Zwei Türen: buyWithEth (Wallet-ETH, seit dem Deployment offen) und buy (Bank-ETH, per Schlüssel signiert), das darauf wartet, dass die Exchange ein Venue der Bank wird: whyNotBuy antwortet "soon", und venueActiveAt() sagt, wann. Die Reserve ist das eigene Bankguthaben der Exchange, sodass jeder Verkauf ein send innerhalb der Bank an den Käufer ist. maxPerTx beträgt beim Deployment 10.000 pUSD und ist vom Owner einstellbar.
pUSD for ETH at exactly one dollar, priced by the oracle's ETH/USD. One direction, no fee. The pUSD always lands in the buyer's SENDIT balance; the ETH goes to the treasury.
Buying
| Function | What it does |
|---|
| buyWithEth(uint256 minPusdOut) payable returns (uint256 pusdOut) | The wallet's own ETH (msg.value). Refused for a registered key ("key"): the wallet sends it. |
|---|
| buy(uint256 ethIn, uint256 minPusdOut) returns (uint256 pusdOut) | From the SENDIT balance's ETH, key- or wallet-signed. Needs the exchange to be an active bank venue: "soon" until its 24-hour delay has passed. |
|---|
| topUp() returns (uint256 amount) | Permissionless: deposits loose pUSD the exchange holds into its reserve. |
|---|
| sweep() returns (uint256 amount) | Permissionless: ETH a failed treasury payment left here, to the treasury. |
|---|
Reading
| Function | What it does |
|---|
| quote(uint256 ethIn) view returns (uint256 pusdOut, uint256 price, uint256 updatedAt) | What ethIn buys at the latest ETH/USD round, whether or not a buy may use it now. |
|---|
| whyNotBuy(address sender, uint256 ethIn) view returns (string) | "paused", "soon", "venue", "stale", "min", "max", "reserve", "balance", or "". |
|---|
| whyNotBuyWithEth(address sender, uint256 ethIn) view returns (string) | "paused", "key", "stale", "min", "max", "reserve", or "". |
|---|
| reserve() view returns (uint256) | pUSD for sale: the exchange's own bank balance plus loose pUSD. |
|---|
| venueActiveAt() view returns (uint256) | When the balance door opens (unix time), 0 once active. |
|---|
| priceDecimals() view returns (uint8) | The ETH/USD feed's decimals, 8 on Pickle. |
|---|
| maxPerTx() view returns (uint256) | The most pUSD one buy may get. Owner-set; DEFAULT_MAX_PER_TX at deploy. |
|---|
| paused() view returns (bool) | The exchange's own pause. The bank's pause stops it too. |
|---|
| treasury() view returns (address) | Where the ETH goes. |
|---|
| owner() view returns (address) | The owner. |
|---|
| bank() view returns (address) | SenditBank. |
|---|
| pusd() view returns (address) | pUSD. |
|---|
| oracle() view returns (address) | The price feeds. |
|---|
| ethUsdFeedId() view returns (bytes32) | The ETH/USD feed id. |
|---|
| VERSION() view returns (uint256) | 1. |
|---|
| DEFAULT_MAX_PER_TX() view returns (uint256) | 10,000 pUSD. |
|---|
| IMMEDIATE_MAX_AGE() view returns (uint256) | 2 seconds: the oldest ETH/USD round a buy accepts. |
|---|
| STALE_GRACE() view returns (uint256) | 30 seconds added to another feed's heartbeat. |
|---|
| MAX_PRICE_DECIMALS() view returns (uint8) | 36. |
|---|
| TREASURY_GAS() view returns (uint256) | 50,000: the gas the treasury payment gets. |
|---|
Owner
| Function | What it does |
|---|
| setMaxPerTx(uint256 maxPerTx_) | The per-buy ceiling. |
|---|
| setTreasury(address treasury_) | Where the ETH goes. |
|---|
| setPaused(bool paused_) | Pauses both doors. |
|---|
| withdrawReserve(address to, uint256 amount) | pUSD out of the exchange's own reserve, never anybody else's balance. |
|---|
| transferOwnership(address next) | Hands ownership on. |
|---|
Events
| Event | What it does |
|---|
| Bought(address indexed account, address indexed by, uint256 ethIn, uint256 pusdOut, uint256 price) | A buy; by is the signer, price in the feed's decimals. |
|---|
| ReserveToppedUp(address indexed from, uint256 amount) | Loose pUSD deposited into the reserve. |
|---|
| ReserveWithdrawn(address indexed to, uint256 amount) | The owner took pUSD out of the reserve. |
|---|
| TreasuryPaymentHeld(address indexed treasury, uint256 amount) | The treasury refused the ETH; it waits for sweep. |
|---|
| Swept(address indexed treasury, uint256 amount) | Held ETH sent to the treasury. |
|---|
| MaxPerTxSet(uint256 maxPerTx) | The ceiling changed. |
|---|
| TreasurySet(address indexed treasury) | The treasury changed. |
|---|
| PausedSet(bool paused) | The pause switched. |
|---|
| OwnershipTransferred(address indexed previous, address indexed next) | Ownership changed. |
|---|
CopyFactory.open(leader, amount) erzeugt den CopyAccount des Kopierenden für diesen Leader (ein EIP-1167-Klon an einer CREATE2-Adresse, einer pro Paar, für immer) oder stockt ihn auf und bewegt dabei amount (mindestens $10) mit bank.move aus dem Bankguthaben des Kopierenden. Der Copy-Keeper ruft dann für jede Position des Leaders, die nach startedAt eröffnet wurde, mirrorOpen auf und übergibt den Kapitalanteil, den der Leader eingesetzt hat; das Konto prüft Markt, Seite und Hebel on chain und begrenzt den Anteil auf das, was das Guthaben des Leaders zulässt. Abhebungen zahlen 5 % des Teils oberhalb von principal, die Hälfte an den Leader und die Hälfte an den FeeRouter. Alte Kopien auf einer früheren Factory sind im Manifest unter copyFactoryPrevious aufgeführt.
Copy trading: open(leader, amount) makes or re-funds the copier's CopyAccount for that leader (one clone per pair, for ever) and moves the deposit into it from the copier's bank balance.
Copier
| Function | What it does |
|---|
| open(address leader, uint256 amount) returns (address account) | Starts copying `leader` with amount pUSD (at least MIN_DEPOSIT), or tops up and restarts the pair's account. Key- or wallet-signed. |
|---|
Reading
| Function | What it does |
|---|
| accountOf(address, address) view returns (address) | The account of (copier, leader), or 0. |
|---|
| accountsOf(address copier) view returns (address[]) | Every account a copier opened, stopped ones included. |
|---|
| accountsByLeader(address leader) view returns (address[]) | Every account copying a leader. |
|---|
| predictAccount(address copier, address leader) view returns (address) | The CREATE2 address of a pair's account. |
|---|
| copiersCount(address) view returns (uint256) | A leader's live copiers. |
|---|
| isAccount(address) view returns (bool) | Whether an address is one of this factory's accounts. |
|---|
| keepers(address) view returns (bool) | Whether an address may mirror. |
|---|
| feeRouter() view returns (address) | Where the router's half of the copy fee goes. |
|---|
| implementation() view returns (address) | The CopyAccount clones copy. |
|---|
| perps() view returns (address) | The engine. |
|---|
| orders() view returns (address) | The orders book. |
|---|
| pusd() view returns (address) | pUSD. |
|---|
| bank() view returns (address) | SenditBank. |
|---|
| owner() view returns (address) | The owner. |
|---|
| VERSION() view returns (uint256) | 3. |
|---|
| FEE_BPS() view returns (uint256) | 500: 5% of withdrawn gains. |
|---|
| LEADER_SHARE_BPS() view returns (uint256) | 5000: half the fee to the leader. |
|---|
| MIN_DEPOSIT() view returns (uint256) | 10e6: ten dollars. |
|---|
Accounts and owner
| Function | What it does |
|---|
| onStopped() | Called by an account when it stops: the leader's copier count drops. |
|---|
| onRestarted() | Called by an account when it restarts. |
|---|
| setKeeper(address keeper, bool allowed) | Owner: adds or removes a copy keeper. |
|---|
| setFeeRouter(address next) | Owner: the FeeRouter that receives half the fee. |
|---|
| transferOwnership(address next) | Owner: hands ownership on. |
|---|
Events
| Event | What it does |
|---|
| CopyOpened(address indexed copier, address indexed leader, address indexed account, uint256 amount) | A copy started or topped up. |
|---|
| KeeperSet(address indexed keeper, bool allowed) | A keeper added or removed. |
|---|
| FeeRouterSet(address indexed feeRouter) | The FeeRouter changed. |
|---|
| OwnershipTransferred(address indexed previous, address indexed current) | Ownership changed. |
|---|
One copier copying one leader. Holds the copier's money in its own bank balance and trades it on the engine when, where and how the leader does: same market, side and leverage, the same share of capital, and only leader positions opened after the copy started.
Copier
| Function | What it does |
|---|
| stop() | No new mirrors; every copied position closes (two-step ones by request). The money stays in the account. |
|---|
| stopAndWithdraw() returns (uint256 amount, uint256 fee) | stop, then every free pUSD to the copier's SENDIT balance, and every close that lands later is sent on too (SWEEPING). |
|---|
| withdraw(uint256 amount) returns (uint256 fee) | Free pUSD to the copier's SENDIT balance, less the fee on the part above principal. |
|---|
Keeper, copier or anyone
| Function | What it does |
|---|
| mirrorOpen(uint256 leaderPositionId, uint16 fractionBps) | Keeper only: copies a leader open with equity x fractionBps / 10000, clamped on chain to what the leader's position can be of the leader's capital. Under one dollar of margin, or no free pUSD, it is skipped. |
|---|
| resolveOpen(uint256 leaderPositionId) | Keeper or copier: records a two-step copy that filled or was cancelled. |
|---|
| mirrorClose(uint256 leaderPositionId) | Keeper or copier: closes the copy once the leader's position is gone. |
|---|
| sync() | Anyone: marks copies the engine already closed (a liquidation, say). |
|---|
| sweep() | Anyone, on a SWEEPING account: sends free pUSD to the copier under the fee rule. |
|---|
| fund(uint256 amount) | The factory only, after moving the deposit in. |
|---|
| initialize(address copier_, address leader_) | The factory only, once. |
|---|
Reading
| Function | What it does |
|---|
| equity() view returns (uint256 total) | Free pUSD plus the copied positions' value. |
|---|
| free() view returns (uint256) | The account's bank pUSD: what can be withdrawn now. |
|---|
| previewWithdraw(uint256 amount) view returns (uint256 fee, uint256 toLeader, uint256 toRouter) | The fee a withdrawal of amount would pay. |
|---|
| principal() view returns (uint256) | The copier's money still inside, which is never charged. |
|---|
| deposited() view returns (uint256) | Lifetime deposits. |
|---|
| withdrawn() view returns (uint256) | Lifetime withdrawals, fee included. |
|---|
| feesPaid() view returns (uint256) | Lifetime fees. |
|---|
| mirrors(uint256 leaderPositionId) view returns (uint256 copyPositionId, uint256 requestId, uint8 state) | A copy's state, by the leader position it follows. |
|---|
| mirrorOf(uint256 leaderPositionId) view returns (Mirror) | The full record: state, leverage, copyPositionId, openRequestId, closeRequestId, margin. |
|---|
| liveMirrors() view returns (uint256[]) | Leader position ids with a live copy. |
|---|
| liveCount() view returns (uint256) | How many, at most MAX_LIVE. |
|---|
| copier() view returns (address) | The copier's account. |
|---|
| leader() view returns (address) | The leader's account. |
|---|
| startedAt() view returns (uint64) | Leader positions opened before this are not copied. |
|---|
| stopped() view returns (bool) | Stopped. |
|---|
| sweeping() view returns (bool) | Asked for everything back. |
|---|
| factory() view returns (address) | The factory. |
|---|
| perps() view returns (address) | The engine. |
|---|
| orders() view returns (address) | The orders book. |
|---|
| pusd() view returns (address) | pUSD. |
|---|
| bank() view returns (address) | SenditBank. |
|---|
| VERSION() view returns (uint256) | 3. |
|---|
| MAX_LIVE() view returns (uint256) | 64 copied positions at once. |
|---|
| STATE_NONE() view returns (uint8) | 0: never seen. |
|---|
| STATE_PENDING() view returns (uint8) | 1: a two-step open is waiting. |
|---|
| STATE_OPEN() view returns (uint8) | 2: the copy is live. |
|---|
| STATE_CLOSING() view returns (uint8) | 3: a two-step close was sent. |
|---|
| STATE_CLOSED() view returns (uint8) | 4: over. |
|---|
| STATE_SKIPPED() view returns (uint8) | 5: never opened (too small, no free pUSD, refused, or cancelled). |
|---|
Events
| Event | What it does |
|---|
| Deposited(uint256 amount) | Money in. |
|---|
| Withdrawn(uint256 amount, uint256 fee, uint256 toLeader, uint256 toRouter) | The copier took money out. |
|---|
| Swept(uint256 amount, uint256 fee, uint256 toLeader, uint256 toRouter) | A SWEEPING account paid its copier when a close landed. |
|---|
| MirrorOpened(uint256 indexed leaderPositionId, uint256 copyPositionId, uint256 requestId, uint256 margin, uint16 leverage) | A copy opened, or requested on a two-step market. |
|---|
| MirrorResolved(uint256 indexed leaderPositionId, uint256 copyPositionId) | A two-step copy settled. |
|---|
| MirrorClosed(uint256 indexed leaderPositionId, uint256 copyPositionId, uint256 requestId) | A copy closed, or its close requested. |
|---|
| MirrorSkipped(uint256 indexed leaderPositionId, string reason) | A leader open that was not copied, and why. |
|---|
| Stopped() | Copying stopped. |
|---|
| Restarted(uint256 startedAt) | A top-up restarted a stopped account. |
|---|
| SweepArmed() | stopAndWithdraw marked the account SWEEPING. |
|---|
The test dollar: six decimals, minted by the faucet operator, not backed by anything. Trusted spenders (the bank among them) move it without an approve, so no trade needs a second signature.
ERC-20
| Function | What it does |
|---|
| transfer(address to, uint256 value) returns (bool) | Transfer. |
|---|
| transferFrom(address from, address to, uint256 value) returns (bool) | Transfer by allowance, or by a trusted spender with none. |
|---|
| approve(address spender, uint256 value) returns (bool) | Approve. |
|---|
| balanceOf(address) view returns (uint256) | Wallet balance. pUSD in SENDIT is in the bank, not here. |
|---|
| allowance(address holder, address spender) view returns (uint256) | type(uint256).max for a trusted spender. |
|---|
| totalSupply() view returns (uint256) | Supply. |
|---|
| name() view returns (string) | Name. |
|---|
| symbol() view returns (string) | "pUSD". |
|---|
| decimals() view returns (uint8) | 6. |
|---|
| trustedSpender(address) view returns (bool) | Whether an address moves pUSD with no approve. |
|---|
Minter and owner
| Function | What it does |
|---|
| mint(address to, uint256 value) | The minter (the faucet operator), at most MAX_MINT per call. |
|---|
| minter() view returns (address) | The minter. |
|---|
| owner() view returns (address) | The owner. |
|---|
| setMinter(address next) | Owner: a new minter. |
|---|
| setTrustedSpender(address spender, bool trusted) | Owner: adds or removes a trusted spender. |
|---|
| transferOwnership(address next) | Owner: hands ownership on. |
|---|
| MAX_MINT() view returns (uint256) | 100,000 dollars per mint. |
|---|
| VERSION() view returns (uint256) | The contract version. |
|---|
Events
| Event | What it does |
|---|
| Transfer(address indexed from, address indexed to, uint256 value) | Transfer. |
|---|
| Approval(address indexed owner, address indexed spender, uint256 value) | Approval. |
|---|
| MinterChanged(address indexed previous, address indexed current) | New minter. |
|---|
| TrustedSpenderSet(address indexed spender, bool trusted) | A trusted spender added or removed. |
|---|
| OwnershipTransferred(address indexed previous, address indexed current) | Ownership changed. |
|---|