Docs

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" },
  ],
};
  • valuationSnapshotHash binds the intent to the round's prices.
  • policyHash binds 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],
)));