EIP-712 signing
The two typed messages a member signs: the intent to join a round and the approval of one exact plan.
Domain
ts
const domain = {
name: "Sama",
version: "1",
chainId: 56,
verifyingContract: "0x7811a30D29d6c2Ca95Aeb4EE9D896cE44Cb72AC8",
};Both messages use the same domain, so a signature for another chain or another contract never verifies here.
PortfolioIntent
Signed when you join a round. It is verified offchain by the API and never sent to the contract. Assets are listed in address order.
@sama/settlement
const types = {
AssetDeltaLimit: [
{ name: "token", type: "address" },
{ name: "maxOut", type: "uint256" }, // most you send, raw units
{ name: "maxIn", type: "uint256" }, // most you receive, raw units
],
PortfolioIntent: [
{ name: "owner", type: "address" },
{ name: "agent", type: "address" },
{ name: "circleId", type: "bytes32" },
{ name: "roundId", type: "bytes32" },
{ name: "valuationSnapshotHash", type: "bytes32" },
{ name: "policyHash", type: "bytes32" },
{ name: "assets", type: "AssetDeltaLimit[]" },
{ name: "nonce", type: "uint256" },
{ name: "validAfter", type: "uint64" },
{ name: "validUntil", type: "uint64" },
],
};valuationSnapshotHashbinds the intent to the round's prices.policyHashbinds your cost cap and leftover style.- The API accepts a signature from the owner or the owner's declared agent.
PlanApproval
Signed when you approve a match. The contract recomputes it on-chain, so it must match hashPlan exactly.
text
PlanApproval(address participant,uint256 nonce,SettlementPlan plan)
SettlementPlan(bytes32 roundId,bytes32 planId,bytes32 valuationSnapshotHash,uint64 validAfter,uint64 validUntil,address[] participants,Leg[] legs)
Leg(address token,address from,address to,uint256 amount)Approval nonces
Nonces are unordered, so one wallet can be in several rounds at once. Sama derives each nonce from the plan and the participant, which makes it unique per plan:
ts
nonce = BigInt(keccak256(encodeAbiParameters(
[{ type: "bytes32" }, { type: "address" }],
[planHash, participant],
)));