-
Notifications
You must be signed in to change notification settings - Fork 5
Open
Description
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:
- First call: Verify EIP-712 signature
- Subsequent calls: Skip signature verification (cached in Bot)
- Every call: Check
_cumulativeUsed[delegator][delegate][nonce] + amount <= allowance - Update cumulative usage:
_cumulativeUsed[delegator][delegate][nonce] += amount - Execute mint with existing
mintableAmountchecks
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
approvevia signature - For ThanksToken: Not directly applicable since ThanksToken uses
mintinstead oftransfer - Compatibility: Can implement
permit()interface for standard tooling, but delegate tomintWithDelegationinternally
ERC-3009 (transferWithAuthorization)
- Concept: Gasless transfer via signature
- For ThanksToken: Similar philosophy but for
mintoperations - Compatibility:
mintWithDelegationfollows 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)
- User runs
/setupin Discord - Bot presents signature request via WalletConnect/MetaMask
- Delegate: Discord Bot address
- Allowance: 1000 ThanksToken
- Valid for: 30 days
- User signs (no gas cost)
- 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
mintableAmountchecks (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
_cumulativeUsedmapping - Implement
mintWithDelegation()function - Implement
getDelegationUsed()view function - Implement
revokeDelegation()function - Add events:
MintDelegationUsed,MintDelegationRevoked - Update
IThanksTokeninterface
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
- Signature verification: EIP-712 ensures only delegator can authorize
- Time limits:
validAfter/validBeforeenforce expiry - On-chain allowance:
_cumulativeUsedprevents Bot from exceeding limits - mintableAmount check: Existing logic prevents minting beyond earned amount
- 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
- EIP-2612: permit() - Gasless Approval
- EIP-3009: Transfer With Authorization
- EIP-712: Typed structured data hashing and signing
Related Files
pkgs/contract/contracts/thankstoken/ThanksToken.solpkgs/contract/contracts/thankstoken/IThanksToken.sol
Metadata
Metadata
Assignees
Labels
No labels