Off-Chain Injection

Pattern where compliance servers sign permission certificates off-chain that users pass into smart contracts for on-chain validation.

Off-Chain Injection is a smart contract design pattern where regulatory compliance decisions are made by trusted off-chain servers that sign cryptographic permission certificates, which users then submit as calldata when executing on-chain transactions. The smart contract validates the signature, extracts the permission parameters, and executes the operation only if the certificate is valid. This pattern balances the privacy requirements of sensitive compliance data (KYC documents, accreditation status) with the finality and auditability of on-chain execution.

The pattern is fundamental to ERC-1594 and the broader ERC-1400 security token standard, where the transferWithData function accepts a bytes data parameter specifically designed for injecting off-chain compliance proofs.

The Problem: On-Chain vs. Off-Chain Compliance

Regulated securities require compliance checks before transfers: Is the recipient KYC-verified? Are they an accredited investor? Are they in a sanctioned jurisdiction? Does this transfer violate daily volume limits?

Pure On-Chain Approach: Storing all compliance data on-chain (as in ERC-3643) provides maximum transparency and composability but raises privacy concerns. Personal identification data on a public blockchain violates GDPR and exposes users to identity theft risks.

Pure Off-Chain Approach: Keeping compliance entirely off-chain (traditional centralized systems) loses the benefits of blockchain: no atomic settlement, no transparent audit trail, counterparty risk with the compliance provider.

Off-Chain Injection: Combines both approaches. Compliance decisions happen off-chain with full access to private data, but the cryptographic proof of that decision is verified on-chain, creating an immutable record that compliance was checked without revealing the underlying data.

Technical Implementation

The pattern uses EIP-712 structured data signing for secure, human-readable permission certificates:

1// Permission certificate structure
2struct TransferPermission {
3 address from;
4 address to;
5 uint256 amount;
6 bytes32 partition;
7 uint256 nonce;
8 uint256 expiry;
9 bytes32 complianceHash; // Hash of compliance check results
10}
11
12// Domain separator for EIP-712
13bytes32 public DOMAIN_SEPARATOR;
14
15// Trusted compliance signer
16address public complianceSigner;
17
18// Nonce tracking to prevent replay
19mapping(address => uint256) public nonces;

Transfer with Off-Chain Permission:

1function transferWithData(
2 address to,
3 uint256 amount,
4 bytes calldata data
5) external returns (bool) {
6 // Decode the permission certificate
7 (TransferPermission memory permit, bytes memory signature) =
8 abi.decode(data, (TransferPermission, bytes));
9
10 // Validate certificate
11 require(permit.from == msg.sender, "Invalid sender");
12 require(permit.to == to, "Recipient mismatch");
13 require(permit.amount == amount, "Amount mismatch");
14 require(permit.expiry > block.timestamp, "Certificate expired");
15 require(permit.nonce == nonces[msg.sender]++, "Invalid nonce");
16
17 // Verify signature from trusted compliance server
18 bytes32 structHash = keccak256(abi.encode(
19 TRANSFER_PERMIT_TYPEHASH,
20 permit.from,
21 permit.to,
22 permit.amount,
23 permit.partition,
24 permit.nonce,
25 permit.expiry,
26 permit.complianceHash
27 ));
28
29 bytes32 digest = keccak256(abi.encodePacked(
30 "\x19\x01",
31 DOMAIN_SEPARATOR,
32 structHash
33 ));
34
35 address signer = ECDSA.recover(digest, signature);
36 require(signer == complianceSigner, "Invalid compliance signature");
37
38 // Execute transfer
39 _transfer(msg.sender, to, amount);
40
41 emit TransferWithCompliance(msg.sender, to, amount, permit.complianceHash);
42 return true;
43}

Off-Chain Compliance Server Flow

  1. User Requests Permission: User's wallet contacts the compliance API with transfer details (from, to, amount, partition).

  2. Compliance Check: Server queries internal databases:

    • Is sender verified (KYC complete)?
    • Is recipient verified?
    • Are both parties in allowed jurisdictions?
    • Does transfer comply with volume limits?
    • Is the partition transferable?
  3. Certificate Generation: If checks pass, server generates an EIP-712 typed data structure and signs it with its private key.

  4. Certificate Delivery: Signed certificate is returned to the user's wallet.

  5. On-Chain Submission: User calls transferWithData with the signed certificate as the data parameter.

  6. On-Chain Validation: Contract verifies signature, checks expiry/nonce, and executes transfer.

Security Considerations

Compliance Server Compromise: If the signing key is compromised, attackers can forge permission certificates for any transfer. Mitigation:

  • Use HSMs (Hardware Security Modules) for key storage
  • Implement key rotation with on-chain signer updates
  • Use multi-sig for the compliance signer role
  • Monitor for unusual certificate patterns

Replay Attacks: Without proper nonce management, a valid certificate could be reused. Mitigation:

  • Per-sender nonce tracking (as shown above)
  • Short certificate expiry windows (minutes, not days)
  • Include transfer-specific data in the signed message

Certificate Front-Running: An attacker observing the mempool could extract a valid certificate and use it before the legitimate user. Mitigation:

  • Bind certificates to msg.sender (already done above)
  • Use private mempools (Flashbots) for sensitive transfers
  • Include transaction nonce in the certificate

Expired Certificate Attacks: If expiry checking is missing or flawed, old certificates remain valid. Mitigation:

  • Always check block.timestamp < permit.expiry
  • Use reasonable expiry windows (5-30 minutes)
  • Consider block number instead of timestamp for precision

Signature Malleability: ECDSA signatures can be manipulated to produce different valid signatures for the same message. Mitigation:

  • Use OpenZeppelin's ECDSA library which handles malleability
  • Store used signatures to prevent reuse

Compliance Server Availability: If the compliance server is down, no transfers can occur. Mitigation:

  • Redundant server infrastructure
  • Emergency bypass mechanism (controller override)
  • Clear SLAs and monitoring

Comparison with On-Chain Compliance

AspectOff-Chain InjectionOn-Chain (ERC-3643)
PrivacyHigh (data stays off-chain)Lower (claims on-chain)
ComposabilityLimited (needs server)High (contracts can verify)
LatencyHigher (server round-trip)Lower (direct call)
AvailabilityServer-dependentAlways available
Audit TrailCertificate hash onlyFull claim history
Gas CostHigher (signature verification)Lower (storage reads)

Advanced Patterns

Batch Certificates: For high-volume operations, a single certificate can authorize multiple transfers:

1struct BatchPermission {
2 TransferPermission[] permits;
3 bytes32 batchHash;
4 uint256 expiry;
5}

Delegated Permissions: Allow authorized parties to request certificates on behalf of token holders:

1struct DelegatedPermission {
2 address operator; // Who can use this certificate
3 address owner; // Actual token holder
4 // ... other fields
5}

Conditional Certificates: Include conditions that must be true at execution time:

1struct ConditionalPermission {
2 // ... standard fields
3 uint256 minPrice; // Only valid if oracle price > minPrice
4 address priceOracle;
5}

Audit Checklist for Off-Chain Injection

  1. Signature Verification: Is ECDSA recovery implemented correctly?
  2. Nonce Management: Are nonces properly incremented and checked?
  3. Expiry Validation: Is certificate expiry enforced?
  4. Parameter Binding: Are all relevant parameters included in signed data?
  5. Signer Management: How is the compliance signer updated? Timelocks?
  6. Replay Prevention: Can certificates be reused across chains (chainId in domain)?
  7. Front-Running Protection: Is the certificate bound to msg.sender?
  8. Fallback Mechanism: What happens if the compliance server is unavailable?

Off-chain injection represents a pragmatic middle ground for regulated token transfers, preserving the privacy of sensitive compliance data while maintaining the auditability and finality of blockchain execution. The pattern requires careful implementation of cryptographic primitives and robust off-chain infrastructure, but enables security tokens to operate within regulatory frameworks that would be impossible with purely on-chain approaches.

Need expert guidance on Off-Chain Injection?

Our team at Zealynx has deep expertise in blockchain security and DeFi protocols. Whether you need an audit or consultation, we're here to help.

Get a Quote

oog
zealynx

Subscribe to Our Newsletter

Stay updated with our latest security insights and blog posts

© 2024 Zealynx