This page documents the signed authorization layer used by the onchain implementation. The EIP-712 payloads connect offchain agreement definitions and user authorization to onchain deployment and input submission. These signatures are what allow the execution engine to verify that a deployment or input was authorized by the correct party. For the conceptual architecture, see System Architecture. For the API-assisted deployment and operation flow, see Workflow. Use this page only when you need the exact low-level signing inputs forDocumentation Index
Fetch the complete documentation index at: https://docs.shodai.network/llms.txt
Use this file to discover all available pages before exploring further.
POST /api/v0/agreements/deploy-with-permit or POST /api/v0/agreements/{id}/input.
For normal TypeScript integrations, prefer the TypeScript client: deployAgreementWithPermit(...) signs and submits deployment permits, and submitAgreementInputWithPermit(...) signs and submits input permits. Use this reference when you are constructing typed data directly, verifying SDK helper behavior, or debugging a signing mismatch.
Deploy signing reference
The deployment permit is signed over derived on-chain parameters, not over the raw deployment request body. If you usedeployAgreementWithPermit(...), the SDK performs this derivation and signing for you.
Deploy typed data
Deploy permit nonce
Setmessage.nonce to the current value of AgreementFactory.nonces(signer) on the target chain before signing. Read it through a live publicClient/RPC connected to the same chain as domain.chainId and factoryAddress; do not hardcode 0.
A successful deploy permit consumes that factory nonce, so deploy signatures are single-use. If the signer nonce changes for any reason, including a previous successful deploy permit, the signature becomes stale and must be regenerated.
Exact derivation rules
| Array | Source | Derivation |
|---|---|---|
inputDefs | agreement.execution.inputs | Each input ID becomes keccak256(stringToHex(inputId)); each field ID becomes keccak256(stringToHex(fieldName)); issuer constraints become on-chain conditions. |
transitions | agreement.execution.transitions | fromState = keccak256(stringToHex(from)); toState = keccak256(stringToHex(to)); inputId = keccak256(stringToHex(transition.conditions[0].input)). |
initVars | Variables referenced by agreement.execution.initialize.data | Each variable ID becomes keccak256(stringToHex(variableName)); each variable value is ABI-encoded according to its field type. |
verifiers | Verifier registrations supplied for deployment | Each verifier registration binds a verifier key to the verifier contract address installed during agreement initialization. |
actions | agreement.execution.actions | fromState and inputId are hashed to bytes32; target, value, and data come from the resolved action call. |
- Do not sign against raw caller input when participant mappings change any value that is hashed or encoded into the signed message.
- Sign against the effective post-mapping values instead.
- For deploy, the safe source of truth is the normalized
variablesobject returned byPOST /v0/agreements/validatefor the exact deployment payload you plan to submit.
agreement.execution.initialize.data references participant-backed variables such as partyAEthAddress or partyBEthAddress, and those addresses are supplied through participants, the final mapped wallet addresses still need to be reflected in the initVars used for signing.
Field type encoding for initVars follows these rules:
string,dateTime,signature→abi.encode(string)address→abi.encode(address)uint256→abi.encode(uint256)bool→abi.encode(bool)bytes32,txHash→abi.encode(bytes32)
Current factory addresses
- Linea Sepolia (
chainId = 59141):0x26Ff3AdEC23fC5778f190371B1CcCadDa74e26c8 - Linea Mainnet (
chainId = 59144):0xB772Ea12546fd7153Bf1F5ED7266B8faB0dAD6C9
Signing call
signatureHex into:
r = 0x...s = 0x...v = 27or28
initValues, docUri, chain, factory address, signer nonce, or deadline changes, the signature must be regenerated.
The TypeScript client uses a one-hour default permit lifetime through computeDefaultDeadlineSeconds(). Low-level signing calls still require you to pass an explicit deadline.
Input signing reference
The input permit is signed over the hashed input ID and an ABI-encoded payload. If you usesubmitAgreementInputWithPermit(...), the SDK performs this derivation and signing for you.
Input typed data
Exact derivation rules
dataFields has this contract shape:
| Step | Derivation |
|---|---|
| Look up the input schema | Read agreement.execution.inputs[inputId].data. |
| Encode each submitted field | id = keccak256(stringToHex(fieldName)); fType = the on-chain field type mapped from the authored variable type; data = ABI-encoded field value. |
| Encode the array | ABI-encode the whole array as (bytes32 id, uint8 fType, bytes data)[]. |
Field type mapping
uint256→UINT256string→STRINGaddress→ADDRESSbool→BOOLbytes32→BYTES32signature→STRINGdateTime→STRINGtxHash→BYTES32
Field value encoding rules
STRING→abi.encode(string)ADDRESS→abi.encode(address)UINT256→abi.encode(uint256)BOOL→abi.encode(bool)BYTES32→abi.encode(bytes32)
Effective signing pipeline
Signing call
signatureHex into:
r = 0x...s = 0x...v = 27or28
inputId, values, agreement schema, agreement address, signer nonce, chain, or deadline changes, the signature must be regenerated.