Skip to content

Commit f96ec90

Browse files
Alberto GalanAlberto Galan
authored andcommitted
feat: Add campaign duplication prevention with timestamp tracking
1 parent fac1d34 commit f96ec90

File tree

2 files changed

+207
-98
lines changed

2 files changed

+207
-98
lines changed

CONTRIBUTION_PROOF_DELEGATION.md

Lines changed: 183 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -1,141 +1,228 @@
1-
# Proof Delegation Contribution
1+
# Proof Delegation System for Boundless Signal Campaign
22

3-
This contribution adds proof delegation functionality to Boundless, allowing provers to securely delegate their proof solving achievements to another address for campaign participation.
3+
## Problem Statement
44

5-
## Problem Solved
6-
7-
Users running Boundless provers face a security dilemma:
8-
- **Security**: They use dedicated wallets for proving (to avoid exposing private keys on servers)
9-
- **Campaign**: The Boundless Signal campaign requires using their main wallet to claim points
10-
- **Mismatch**: The proofs are on the prover wallet, but points need to be claimed on the main wallet
5+
Users running Boundless provers with dedicated wallets cannot claim campaign points because their prover wallet differs from their main wallet connected to social profiles. This creates a security vs. convenience trade-off where users must either:
6+
- Risk their main wallet's private key on rented servers, or
7+
- Miss out on campaign rewards
118

129
## Solution
1310

14-
A **Proof Delegation Contract** that allows provers to securely delegate their proof solving to another address using EIP-712 signatures.
15-
16-
### Key Features
17-
18-
-**Secure**: Uses EIP-712 signatures - no private key exposure required
19-
-**Simple**: Uses existing .env file from Boundless service
20-
-**Permanent**: Delegations are permanent for ease of use
21-
-**Comprehensive**: Delegates all proof solving, not specific proofs
22-
-**Fast**: Can be deployed and used immediately
23-
-**Compatible**: Works with existing Boundless infrastructure
11+
A proof delegation system that allows provers to securely delegate their proof-solving accreditation to another address using EIP-712 signatures.
2412

25-
## Files Added/Modified
13+
## Features
2614

27-
### New Files
28-
- `contracts/src/ProofDelegation.sol` - The delegation contract
29-
- `scripts/delegate-proofs.js` - User-friendly delegation script
30-
- `scripts/deploy.js` - Deployment script
15+
### Core Features
16+
- **Permanent Delegation**: One-time, unrevocable delegation for simplicity
17+
- **EIP-712 Signatures**: Secure delegation without private key exposure
18+
- **Nonce Protection**: Prevents replay attacks
19+
- **CLI Integration**: Seamless integration with existing Boundless CLI
20+
- **User-Friendly Scripts**: Easy-to-use Node.js scripts
3121

32-
### Modified Files
33-
- `crates/boundless-cli/src/bin/boundless.rs` - Added delegation CLI commands
34-
- `crates/boundless-market/src/deployments.rs` - Added delegation contract address field
22+
### Security Features
23+
- **One-Time Delegation**: Provers can only delegate once
24+
- **Signature Verification**: Cryptographic proof of delegation intent
25+
- **Deadline Protection**: Signatures expire to prevent stale delegations
3526

3627
## Usage
3728

38-
### Deploy Contract
29+
### Using the CLI
3930
```bash
40-
forge create ProofDelegation --rpc-url https://mainnet.base.org --private-key YOUR_PRIVATE_KEY
31+
# Delegate proofs to another address
32+
boundless account delegate-proofs --target-address 0x1234... --deadline 1735689600
4133
```
4234

43-
### Delegate Proof Solving
35+
### Using the Script
4436
```bash
45-
# Using the script
46-
node scripts/delegate-proofs.js delegate 0x1234...your_main_wallet
37+
# Delegate proofs
38+
node scripts/delegate-proofs.js delegate 0x1234...
4739

48-
# Using the CLI (after deployment)
49-
boundless account delegate-proofs --target-address 0x1234...your_main_wallet
40+
# Check delegation status
41+
node scripts/delegate-proofs.js check 0x1234...
5042
```
5143

52-
### Check Delegation
53-
```bash
54-
node scripts/delegate-proofs.js check 0x1234...your_main_wallet
55-
```
44+
## Contract Details
5645

57-
## Environment Variables
46+
### ProofDelegation.sol
47+
- **Deployment**: Deploy to Base mainnet
48+
- **Functions**: `delegateProofs`, `getProverTarget`, `getDelegationTimestamp`
49+
- **Events**: `ProofDelegated`, `CampaignDelegationCreated`
50+
- **Security**: EIP-712 signatures, nonce protection, one-time delegation
5851

59-
Add to your existing `.env` file (same as your Boundless service):
60-
```env
61-
PRIVATE_KEY=0x...your_prover_wallet_private_key
62-
RPC_URL=https://mainnet.base.org
63-
PROOF_DELEGATION_ADDRESS=0x...deployed_contract_address
52+
### Key Functions
53+
```solidity
54+
function delegateProofs(
55+
address prover,
56+
address target,
57+
uint256 deadline,
58+
bytes calldata signature
59+
) external
60+
61+
function getProverTarget(address prover) external view returns (address)
62+
function getDelegationTimestamp(address prover) external view returns (uint256)
6463
```
6564

66-
## Contract Details
65+
## Campaign Backend Integration
6766

68-
### ProofDelegation.sol
67+
### Preventing Duplication Exploits
68+
69+
The delegation system includes specific features to prevent users from claiming multiple rewards:
70+
71+
#### 1. Delegation Timestamp Tracking
6972
```solidity
70-
contract ProofDelegation is EIP712, Ownable {
71-
// Delegate all proof solving to target (permanent)
72-
function delegateProofs(
73-
address prover,
74-
address target,
75-
uint256 deadline,
76-
bytes calldata signature
77-
) external;
78-
79-
// Check if address has delegated proof solving
80-
function hasDelegatedProofs(address target) external view returns (bool);
73+
mapping(address => uint256) public delegationTimestamps;
74+
event CampaignDelegationCreated(
75+
address indexed prover,
76+
address indexed target,
77+
uint256 timestamp,
78+
uint256 blockNumber
79+
);
80+
```
81+
82+
#### 2. Backend Integration Strategy
83+
84+
**When a delegation is detected, the campaign backend should:**
85+
86+
1. **Check Delegation Timing**:
87+
```javascript
88+
const delegationTimestamp = await contract.getDelegationTimestamp(proverAddress);
89+
const campaignClaims = await getCampaignClaims(proverAddress);
90+
```
91+
92+
2. **Handle Pre-Claim Delegations**:
93+
- If prover already claimed rewards → **Disqualify prover** from future claims
94+
- If prover hasn't claimed → **Transfer eligibility** to target address
95+
96+
3. **Update Campaign Records**:
97+
```javascript
98+
function handleDelegation(proverAddress, targetAddress) {
99+
const hasClaimed = await checkIfAddressClaimed(proverAddress);
100+
101+
if (hasClaimed) {
102+
// Disqualify prover from future claims
103+
disqualifyAddress(proverAddress);
104+
} else {
105+
// Transfer claim eligibility to target
106+
transferClaimEligibility(proverAddress, targetAddress);
107+
}
108+
}
109+
```
110+
111+
#### 3. Campaign Query Integration
112+
113+
**For campaign point calculation:**
114+
```javascript
115+
function getEffectiveAddress(proverAddress) {
116+
const delegatedTarget = await contract.getProverTarget(proverAddress);
117+
return delegatedTarget || proverAddress;
81118
}
82119
```
83120

84-
### Security Features
85-
- **EIP-712 Signatures**: Secure, standardized signature format
121+
**For proof counting:**
122+
```javascript
123+
function countProofsForCampaign(address) {
124+
// Check if address has delegated proofs
125+
const delegatedProver = await contract.getDelegatedProver(address);
126+
127+
if (delegatedProver) {
128+
// Count proofs from the delegated prover
129+
return await countProofs(delegatedProver);
130+
} else {
131+
// Count proofs directly
132+
return await countProofs(address);
133+
}
134+
}
135+
```
136+
137+
### Campaign Integration Steps
138+
139+
1. **Deploy Contract**: Deploy `ProofDelegation` to Base mainnet
140+
2. **Update Campaign Backend**:
141+
- Listen for `CampaignDelegationCreated` events
142+
- Implement duplication prevention logic
143+
- Update proof counting to use `getEffectiveAddress()`
144+
3. **Update Frontend**: Show delegation status in campaign UI
145+
4. **Documentation**: Update campaign docs to explain delegation
146+
147+
## Security Considerations
148+
149+
### Delegation Security
150+
- **EIP-712 Signatures**: Cryptographically secure delegation
86151
- **Nonce Protection**: Prevents replay attacks
87-
- **Deadline Support**: Time-limited signatures
88-
- **Permanent Delegations**: Once delegated, cannot be revoked for simplicity
89-
- **One-Time Only**: Each prover can only delegate once
152+
- **Deadline Protection**: Signatures expire automatically
153+
- **One-Time Delegation**: Prevents multiple delegations
90154

91-
## Integration with Campaign System
155+
### Campaign Security
156+
- **Timestamp Tracking**: Prevents retroactive delegation exploits
157+
- **Backend Validation**: Server-side verification of delegation status
158+
- **Claim Tracking**: Prevents double-claiming through delegation
92159

93-
The campaign system needs to be updated to check for delegated proof solving:
160+
## Integration with Existing Systems
94161

95-
```javascript
96-
// Check for delegated proof solving
97-
const delegationContract = new ethers.Contract(DELEGATION_ADDRESS, ABI, provider);
98-
const hasDelegated = await delegationContract.hasDelegatedProofs(userAddress);
99-
100-
if (hasDelegated) {
101-
const proverAddress = await delegationContract.getDelegatedProver(userAddress);
102-
const delegatedProofs = await getProofDeliveredEvents(proverAddress, provider);
103-
// Include delegated proofs in point calculation
104-
}
162+
### Boundless CLI
163+
- New `delegate-proofs` subcommand under `account`
164+
- Uses existing `.env` configuration
165+
- Integrates with current CLI architecture
166+
167+
### Campaign System
168+
- **Event Listening**: Monitor `CampaignDelegationCreated` events
169+
- **Proof Counting**: Use `getEffectiveAddress()` for accurate counts
170+
- **Claim Validation**: Check delegation status before allowing claims
171+
172+
## Deployment
173+
174+
### Contract Deployment
175+
```bash
176+
# Using Foundry
177+
forge script scripts/DeployProofDelegation.s.sol --rpc-url $RPC_URL --broadcast
105178
```
106179

180+
### Backend Integration
181+
1. Add delegation contract address to campaign configuration
182+
2. Implement event listener for `CampaignDelegationCreated`
183+
3. Update proof counting logic to use delegation
184+
4. Add duplication prevention logic
185+
107186
## Testing
108187

109-
### Local Testing
188+
### Contract Testing
110189
```bash
111-
# Start local node
112-
anvil
190+
# Run Foundry tests
191+
forge test --match-contract ProofDelegation
192+
```
113193

114-
# Deploy to local network
115-
forge create ProofDelegation --rpc-url http://localhost:8545 --private-key 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
194+
### Integration Testing
195+
```bash
196+
# Test CLI integration
197+
boundless account delegate-proofs --target-address 0x1234...
116198

117-
# Test delegation
118-
PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 \
119-
RPC_URL=http://localhost:8545 \
120-
PROOF_DELEGATION_ADDRESS=0x... \
121-
node scripts/delegate-proofs.js delegate 0x70997970C51812dc3A010C7d01b50e0d17dc79C8
199+
# Test script functionality
200+
node scripts/delegate-proofs.js delegate 0x1234...
122201
```
123202

124-
## Backward Compatibility
203+
## Files Modified
125204

126-
All changes are **backward compatible**:
127-
- ✅ Optional delegation contract address in deployments
128-
- ✅ Existing CLI commands continue to work
129-
- ✅ No breaking changes to existing functionality
130-
- ✅ Existing deployments work without modification
205+
### New Files
206+
- `contracts/src/ProofDelegation.sol` - Core delegation contract
207+
- `scripts/delegate-proofs.js` - User-friendly delegation script
208+
- `scripts/deploy.js` - Deployment script
209+
- `CONTRIBUTION_PROOF_DELEGATION.md` - This documentation
131210

132-
## Security Considerations
211+
### Modified Files
212+
- `crates/boundless-cli/src/bin/boundless.rs` - Added delegation CLI commands
213+
- `crates/boundless-market/src/deployments.rs` - Added optional delegation contract address
214+
215+
## Next Steps
133216

134-
1. **Private Key Security**: Script requires prover's private key, but only for signing delegation
135-
2. **Signature Verification**: Contract verifies EIP-712 signatures to ensure only the prover can delegate
136-
3. **Nonce Protection**: Each delegation uses a unique nonce to prevent replay attacks
137-
4. **Permanent Delegations**: Once delegated, cannot be revoked for simplicity
217+
1. **Review & Merge**: Submit PR to Boundless repository
218+
2. **Deploy Contract**: Deploy to Base mainnet
219+
3. **Update Campaign**: Integrate delegation into campaign backend
220+
4. **User Documentation**: Update campaign docs with delegation instructions
221+
5. **Monitoring**: Monitor delegation usage and campaign integration
138222

139-
## License
223+
## Support
140224

141-
This contribution follows the same license as the Boundless project.
225+
For questions or issues with the delegation system:
226+
- Open an issue in the Boundless repository
227+
- Check the campaign documentation for integration details
228+
- Review the contract code for technical implementation

contracts/src/ProofDelegation.sol

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,22 @@ contract ProofDelegation is EIP712, Ownable {
2424
// Mapping from prover address to target address
2525
mapping(address => address) public proverTargets;
2626

27+
// Mapping to track delegation timestamps for campaign integration
28+
mapping(address => uint256) public delegationTimestamps;
29+
2730
// Nonce tracking for replay protection
2831
mapping(address => uint256) public nonces;
2932

3033
// Events
31-
event ProofDelegated(address indexed prover, address indexed target, uint256 nonce);
34+
event ProofDelegated(address indexed prover, address indexed target, uint256 nonce, uint256 timestamp);
35+
36+
// Campaign-specific event for backend integration
37+
event CampaignDelegationCreated(
38+
address indexed prover,
39+
address indexed target,
40+
uint256 timestamp,
41+
uint256 blockNumber
42+
);
3243

3344
constructor() EIP712("ProofDelegation", "1") Ownable(msg.sender) {}
3445

@@ -64,8 +75,10 @@ contract ProofDelegation is EIP712, Ownable {
6475

6576
delegatedProvers[target] = prover;
6677
proverTargets[prover] = target;
78+
delegationTimestamps[prover] = block.timestamp;
6779

68-
emit ProofDelegated(prover, target, nonce);
80+
emit ProofDelegated(prover, target, nonce, block.timestamp);
81+
emit CampaignDelegationCreated(prover, target, block.timestamp, block.number);
6982
}
7083

7184
/**
@@ -103,4 +116,13 @@ contract ProofDelegation is EIP712, Ownable {
103116
function hasDelegatedProofs(address target) external view returns (bool) {
104117
return delegatedProvers[target] != address(0);
105118
}
119+
120+
/**
121+
* @notice Get the timestamp when a prover delegated their proofs
122+
* @param prover The prover address
123+
* @return The delegation timestamp, 0 if not delegated
124+
*/
125+
function getDelegationTimestamp(address prover) external view returns (uint256) {
126+
return delegationTimestamps[prover];
127+
}
106128
}

0 commit comments

Comments
 (0)