Task 3: Batching Transactions & Signatures Design
Objective
Reduce the number of user interactions (wallet popups) required for trading, specifically for:
- Batch Execution: Performing multiple actions (e.g., buying multiple outcomes) in a single transaction.
- Batch Creation: Placing multiple limit orders without signing each one individually.
Proposed Solution
1. Batch Execution (Transactions) using Multicall
Problem: If a user wants to buy YES shares in 3 different markets, they currently send 3 transactions.
Solution: Implement Multicall in the CTFExchange contract.
Contract Changes (nostra-contracts):
- Inherit from
@openzeppelin/contracts/utils/Multicall.solinCTFExchange. - This adds the
multicall(bytes[] calldata data)function. - Users can bundle calls to
fillOrder,matchOrders,cancelOrder,deposit, etc.
Frontend Changes (web):
- Use
multicallwhen the user performs a "Batch Action" (e.g., "Bet on All" or "Hedge").
2. Batch Creation (Signatures) using Session Keys
Problem: Creating multiple limit orders requires signing an EIP-712 message for each order. Solution: Implement Session Keys (Delegates). The user approves a temporary key (Session Key) to sign orders on their behalf.
Contract Changes (nostra-contracts):
- New Mixin:
contracts/exchange/mixins/Delegates.sol(or add toAuth.sol).mapping(address => mapping(address => bool)) public delegates; event DelegateUpdated(address indexed user, address indexed delegate, bool status); function setDelegate(address delegate, bool status) external { delegates[msg.sender][delegate] = status; emit DelegateUpdated(msg.sender, delegate, status); } - Update
Signatures.sol:- Modify
verifyEOASignature:function verifyEOASignature(address signer, address maker, bytes32 structHash, bytes memory signature) internal view returns (bool) { // Allow if signer is maker OR signer is a delegate of maker if (signer != maker && !delegates[maker][signer]) return false; return verifyECDSASignature(signer, structHash, signature); } - Note:
validateOrderSignatureneeds to beview(it is), butdelegatesmapping access is fine. - Important:
Signaturesmixin currently doesn't have access todelegates. We need to exposedelegatesvia an interface or inheritDelegatesinSignatures(orCTFExchangeoverridesvalidateOrderSignatureand checks delegates). - Better Approach:
CTFExchangeinheritsDelegates.CTFExchangeoverridesvalidateOrderSignature(which is virtual inSignatures).
- Modify
Frontend Changes (web):
- Generate a local key pair (Session Key) in the browser.
- Prompt user to
setDelegate(sessionKeyAddress, true)(One transaction). - Store Session Key securely (e.g., session storage).
- When placing orders, sign with Session Key. No wallet popup required.
Implementation Roadmap
Phase 1: Multicall (Immediate)
- Add
Multicallinheritance toCTFExchange. - Redeploy.
- Update Frontend to use
multicallfor batch trades.
Phase 2: Session Keys (Future Scope)
Note: To be implemented in a later iteration to further reduce signature fatigue.
- Implement
Delegateslogic in contracts. - Update
validateOrderSignature. - Redeploy.
- Implement Session Key management in Frontend.
Considerations
- Security: Session keys should have an expiration or scope. However, for MVP, a simple boolean delegate is sufficient (User can revoke).
- Gas:
Multicalladds slight overhead but saves significant gas compared to multiple txs. - Complexity: Session Keys require careful frontend state management.