Signing a transaction for every order is fine at 8-hour horizons and unusable at 100ms ones. PrismPerp separates authorisation from execution: one session signature authorises a scoped key, and every subsequent order is a typed message the relayer can verify without touching the user wallet.
EIP712Domain( string name, // "PrismPerp" string version, // "1" uint256 chainId, // 46630 testnet · 4663 mainnet address verifyingContract ) Order( address trader, uint8 market, // 0 = C-VIX30, 1 = FR-BASIS-BTC, 2 = FR-BASIS-ETH bool isLong, address collateral, // the token margin and fee are drawn in: signed, not chosen by the relayer uint256 size, // notional, 1e18 uint256 margin, // collateral posted, 1e18 int256 limitPrice, // worst level, 1e18, signed. long fills <=, short fills >=. 0 = off uint64 leverage, uint64 nonce, uint64 deadline ) Session( address trader, address sessionKey, uint32 scope, // bits: 1 open · 2 close · 4 cancel · 8 paper collateral uint64 epoch, // the wallet's revocation counter uint64 issuedAt, uint64 expiresAt // at most 7 days after issuedAt )
- Nonces are single-use per trader: a unique index rejects a reuse at the relayer, and the contract's own nonce map rejects it again on-chain.
- An order signed by a session key settles only with the wallet's Session grant beside it, and the contract checks the grant itself: signed by the trader, naming this key, unexpired, holding the open scope, and at the wallet's current epoch.
- Each order in a batch settles on its own. One that fails — a balance withdrawn between signing and settlement, a limit the index moved through — is rejected with its reason and the rest settle; it does not burn its nonce.
- The relayer can close a position only on a signed ClosePosition from the trader or a key holding the close scope. The trader can always close from their own wallet without it.
- revokeAllSessions() bumps the wallet's epoch: one transaction ends every key it ever delegated to, whether or not the relayer cooperates.
