Skip to content

Add EIP-712 signature-based delegation system to ThanksToken (ERC-2612, ERC-3009 compatible) #415

@yu23ki14

Description

@yu23ki14

Add EIP-712 Signature-Based Delegation System to ThanksToken

Overview

Enable Discord Bots and other external services to mint ThanksTokens on behalf of users through EIP-712 signature-based delegation, while maintaining compatibility with ERC-2612 and ERC-3009 standards.

Motivation

Current Problem

  • Users can only mint ThanksTokens directly through the Toban interface
  • Discord Bot integration requires users to sign every transaction → Poor UX
  • No standardized way for third-party services to interact with ThanksToken

Proposed Solution

  • Users sign a delegation once (valid for 30 days, up to 1000 ThanksToken, etc.)
  • Discord Bot caches the signature
  • Bot executes mints on behalf of users without requiring signatures each time
  • On-chain state tracks cumulative usage to prevent Bot abuse

Technical Design

1. EIP-712 Domain & Type Hash

// Domain Separator
bytes32 public DOMAIN_SEPARATOR;

// Type Hash for mint delegation
bytes32 public constant MINT_DELEGATION_TYPEHASH = keccak256(
    "MintDelegation(address delegator,address delegate,uint256 allowance,uint256 validAfter,uint256 validBefore,bytes32 nonce)"
);

2. Minimal On-Chain State (Semi-Stateless Design)

// Track cumulative usage per delegation
// delegator => delegate => nonce => cumulativeUsed
mapping(address => mapping(address => mapping(bytes32 => uint256))) 
    private _cumulativeUsed;

Why on-chain state is necessary:

  • Prevents Bot from exceeding user-signed allowance
  • Provides transparency (users can verify remaining balance)
  • Auditable on blockchain

3. Core Function: mintWithDelegation

function mintWithDelegation(
    address delegator,      // User who signed the delegation
    address to,             // Mint recipient
    uint256 amount,         // Amount to mint
    RelatedRole[] memory relatedRoles,
    bytes memory data,
    uint256 allowance,      // Total delegation amount (from signature)
    uint256 validAfter,     // Delegation valid start time
    uint256 validBefore,    // Delegation expiry time
    bytes32 nonce,          // Unique delegation identifier (can be reused)
    uint8 v, bytes32 r, bytes32 s  // Signature
) external returns (bool);

Execution Flow:

  1. First call: Verify EIP-712 signature
  2. Subsequent calls: Skip signature verification (cached in Bot)
  3. Every call: Check _cumulativeUsed[delegator][delegate][nonce] + amount <= allowance
  4. Update cumulative usage: _cumulativeUsed[delegator][delegate][nonce] += amount
  5. Execute mint with existing mintableAmount checks

4. Supporting Functions

// View remaining delegation balance
function getDelegationUsed(
    address delegator,
    address delegate,
    bytes32 nonce
) external view returns (uint256);

// User revokes delegation
function revokeDelegation(
    address delegate,
    bytes32 nonce
) external;

5. Events

event MintDelegationUsed(
    address indexed delegator,
    address indexed delegate,
    address indexed to,
    uint256 amount,
    bytes32 nonce
);

event MintDelegationRevoked(
    address indexed delegator,
    address indexed delegate,
    bytes32 nonce
);

Standard Compatibility

ERC-2612 (permit)

  • Concept: Gasless approve via signature
  • For ThanksToken: Not directly applicable since ThanksToken uses mint instead of transfer
  • Compatibility: Can implement permit() interface for standard tooling, but delegate to mintWithDelegation internally

ERC-3009 (transferWithAuthorization)

  • Concept: Gasless transfer via signature
  • For ThanksToken: Similar philosophy but for mint operations
  • Compatibility: mintWithDelegation follows ERC-3009 patterns (validAfter/validBefore, nonce-based)

Proposed Approach

Implement both standard interfaces for maximum compatibility:

// ERC-2612 compatible (delegates to mintWithDelegation)
function permit(
    address owner,
    address spender,
    uint256 value,
    uint256 deadline,
    uint8 v, bytes32 r, bytes32 s
) external;

// ERC-3009 compatible (direct mapping)
function mintWithAuthorization(
    address from,
    address to,
    uint256 value,
    uint256 validAfter,
    uint256 validBefore,
    bytes32 nonce,
    uint8 v, bytes32 r, bytes32 s
) external;

// ThanksToken-specific (full feature set)
function mintWithDelegation(
    // ... as defined above
) external;

User Experience

Initial Setup (One-time)

  1. User runs /setup in Discord
  2. Bot presents signature request via WalletConnect/MetaMask
    • Delegate: Discord Bot address
    • Allowance: 1000 ThanksToken
    • Valid for: 30 days
  3. User signs (no gas cost)
  4. Bot caches signature in database

Daily Usage (No signatures required)

Discord:
User: /thanks @Alice 10 Great work on the PR!

Bot:  ✅ Sent 10 ThanksToken to Alice!
      💬 "Great work on the PR!"
      📊 Remaining delegation: 90 ThanksToken
      🔗 0x1234...abcd

Security

  • Users can revoke delegation anytime via Toban UI
  • Delegation expires automatically after 30 days
  • Protected by mintableAmount checks (dual protection)
  • On-chain usage tracking prevents Bot abuse

Implementation Plan

Phase 1: Core Contract

  • Add EIP-712 domain separator (lazy initialization for Clone pattern)
  • Implement _cumulativeUsed mapping
  • Implement mintWithDelegation() function
  • Implement getDelegationUsed() view function
  • Implement revokeDelegation() function
  • Add events: MintDelegationUsed, MintDelegationRevoked
  • Update IThanksToken interface

Phase 2: Standard Compatibility (Optional)

  • Implement ERC-2612 permit() interface
  • Implement ERC-3009 compatible mintWithAuthorization()
  • Add nonces() view function (ERC-2612 requirement)
  • Add DOMAIN_SEPARATOR() view function

Phase 3: Testing

  • Unit tests for signature verification
  • Test cumulative usage tracking
  • Test delegation revocation
  • Test edge cases (expired, exceeded allowance, etc.)
  • Gas optimization tests

Phase 4: Integration

  • Discord Bot signature caching implementation
  • Toban UI delegation management screen
  • Documentation and examples

Security Considerations

Multi-Layer Defense

  1. Signature verification: EIP-712 ensures only delegator can authorize
  2. Time limits: validAfter / validBefore enforce expiry
  3. On-chain allowance: _cumulativeUsed prevents Bot from exceeding limits
  4. mintableAmount check: Existing logic prevents minting beyond earned amount
  5. User revocation: Users can invalidate delegation at any time

Potential Risks & Mitigations

Risk Mitigation
Bot private key compromise User revokes delegation; Bot wallet can be rotated
Signature replay Nonce tracking prevents reuse across different contexts
Allowance exhaustion Bot warns user; user creates new delegation
Expired delegation Bot detects expiry; prompts user to renew

Alternatives Considered

❌ Bot Registry System

  • Rejected: Too complex, requires Owner to manage Bot list
  • Issue: Not flexible for new integrations

❌ Per-Transaction Signatures

  • Rejected: Poor UX, requires signature every time
  • Issue: Defeats purpose of Bot integration

❌ Off-Chain Allowance Only

  • Rejected: Bot could be compromised and mint unlimited tokens
  • Issue: No transparency or auditability

✅ Chosen: EIP-712 + On-Chain Cumulative Usage

  • Simple, secure, transparent
  • Works with any Bot (Discord, Slack, Telegram, etc.)
  • Standards-compatible (ERC-2612/3009)

Success Criteria

  • Users can delegate mint authority via signature
  • Discord Bot can execute mints without per-transaction signatures
  • On-chain state accurately tracks cumulative usage
  • Users can verify remaining delegation balance
  • Users can revoke delegations
  • Compatible with ERC-2612/3009 tooling
  • Gas-efficient (minimal state updates)
  • Well-tested and secure

References

Related Files

  • pkgs/contract/contracts/thankstoken/ThanksToken.sol
  • pkgs/contract/contracts/thankstoken/IThanksToken.sol

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions