Skip to content

Commit 1fa0a48

Browse files
authored
Merge pull request #460 from LIT-Protocol/feat/ecdsa-validator-contracts
feat: Add ECDSA validator check when permitting an app version
2 parents e6dd0ae + ffc6931 commit 1fa0a48

19 files changed

Lines changed: 637 additions & 49 deletions

packages/libs/contracts-sdk/Makefile

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
-include .env
22

3-
.PHONY: help build test test-verbose test-match deploy-vincent deploy-vincent-datil get-abis update-facet
3+
.PHONY: help build test test-verbose test-match deploy-vincent-datil deploy-vincent-base-sepolia deploy-vincent-base-mainnet update-facet set-trusted-forwarder set-ecdsa-validator get-abis
44

55
help: ## Display this help screen
66
@grep -h -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
@@ -30,12 +30,18 @@ deploy-vincent-datil: ## Deploy the Vincent Diamond contract to Datil network on
3030
echo "Error: VINCENT_DEPLOYER_PRIVATE_KEY is not set in .env"; \
3131
exit 1; \
3232
fi
33+
@if [ -z "$(VINCENT_ECDSA_VALIDATOR_ADDRESS)" ]; then \
34+
echo "Error: VINCENT_ECDSA_VALIDATOR_ADDRESS is not set in .env"; \
35+
echo "This address is required for smart account owner verification"; \
36+
exit 1; \
37+
fi
3338
@echo "Deploying Vincent Diamond to Datil network ($(VINCENT_DEPLOYMENT_RPC_URL))..."
3439
@if [ -n "$(VINCENT_GELATO_FORWARDER_ADDRESS)" ]; then \
3540
echo "Using Gelato forwarder: $(VINCENT_GELATO_FORWARDER_ADDRESS)"; \
3641
else \
3742
echo "Gelato forwarder not set (EIP-2771 disabled)"; \
3843
fi
44+
@echo "Using ECDSA validator: $(VINCENT_ECDSA_VALIDATOR_ADDRESS)"
3945
@forge script script/DeployVincentDiamond.sol:DeployVincentDiamond --sig "deployToDatil()" -vvv \
4046
--broadcast \
4147
--private-key $(VINCENT_DEPLOYER_PRIVATE_KEY) \
@@ -50,12 +56,18 @@ deploy-vincent-base-sepolia: ## Deploy the Vincent Diamond contract to Base Sepo
5056
echo "Error: VINCENT_DEPLOYER_PRIVATE_KEY is not set in .env"; \
5157
exit 1; \
5258
fi
59+
@if [ -z "$(VINCENT_ECDSA_VALIDATOR_ADDRESS)" ]; then \
60+
echo "Error: VINCENT_ECDSA_VALIDATOR_ADDRESS is not set in .env"; \
61+
echo "This address is required for smart account owner verification"; \
62+
exit 1; \
63+
fi
5364
@echo "Deploying Vincent Diamond to Base Sepolia ($(BASE_SEPOLIA_RPC_URL))..."
5465
@if [ -n "$(VINCENT_GELATO_FORWARDER_ADDRESS)" ]; then \
5566
echo "Using Gelato forwarder: $(VINCENT_GELATO_FORWARDER_ADDRESS)"; \
5667
else \
5768
echo "Gelato forwarder not set (EIP-2771 disabled)"; \
5869
fi
70+
@echo "Using ECDSA validator: $(VINCENT_ECDSA_VALIDATOR_ADDRESS)"
5971
@forge script script/DeployVincentDiamond.sol:DeployVincentDiamond --sig "deployToBaseSepolia()" -vvv \
6072
--broadcast \
6173
--private-key $(VINCENT_DEPLOYER_PRIVATE_KEY) \
@@ -70,12 +82,18 @@ deploy-vincent-base-mainnet: ## Deploy the Vincent Diamond contract to Base Main
7082
echo "Error: VINCENT_DEPLOYER_PRIVATE_KEY is not set in .env"; \
7183
exit 1; \
7284
fi
85+
@if [ -z "$(VINCENT_ECDSA_VALIDATOR_ADDRESS)" ]; then \
86+
echo "Error: VINCENT_ECDSA_VALIDATOR_ADDRESS is not set in .env"; \
87+
echo "This address is required for smart account owner verification"; \
88+
exit 1; \
89+
fi
7390
@echo "Deploying Vincent Diamond to Base Mainnet ($(BASE_MAINNET_RPC_URL))..."
7491
@if [ -n "$(VINCENT_GELATO_FORWARDER_ADDRESS)" ]; then \
7592
echo "Using Gelato forwarder: $(VINCENT_GELATO_FORWARDER_ADDRESS)"; \
7693
else \
7794
echo "Gelato forwarder not set (EIP-2771 disabled)"; \
7895
fi
96+
@echo "Using ECDSA validator: $(VINCENT_ECDSA_VALIDATOR_ADDRESS)"
7997
@forge script script/DeployVincentDiamond.sol:DeployVincentDiamond --sig "deployToBaseMainnet()" -vvv \
8098
--broadcast \
8199
--private-key $(VINCENT_DEPLOYER_PRIVATE_KEY) \
@@ -89,7 +107,7 @@ update-facet: ## Update a specific facet in the Vincent Diamond contract. Usage:
89107
@if [ -z "$(FACET_NAME)" ]; then \
90108
echo "Error: FACET_NAME parameter is required."; \
91109
echo "Usage: make update-facet FACET_NAME=VincentAppViewFacet NETWORK=datil|base-sepolia|base-mainnet"; \
92-
echo "Available facets: VincentAppFacet, VincentAppViewFacet, VincentUserFacet, VincentUserViewFacet, VincentERC2771Facet"; \
110+
echo "Available facets: VincentAppFacet, VincentAppViewFacet, VincentUserFacet, VincentUserViewFacet, VincentERC2771Facet, VincentZeroDevConfigFacet"; \
93111
exit 1; \
94112
fi
95113
@if [ -z "$(NETWORK)" ]; then \
@@ -151,6 +169,40 @@ set-trusted-forwarder: ## Set the trusted forwarder address for EIP-2771 meta-tr
151169
--private-key $(VINCENT_DEPLOYER_PRIVATE_KEY) \
152170
--rpc-url $(RPC_URL)
153171

172+
set-ecdsa-validator: ## Set the ECDSA validator address for smart account owner verification. Usage: make set-ecdsa-validator VALIDATOR_ADDRESS=0x... NETWORK=datil|base-sepolia|base-mainnet
173+
@if [ -z "$(VINCENT_DEPLOYER_PRIVATE_KEY)" ]; then \
174+
echo "Error: VINCENT_DEPLOYER_PRIVATE_KEY is not set in .env"; \
175+
exit 1; \
176+
fi
177+
@if [ -z "$(VALIDATOR_ADDRESS)" ]; then \
178+
echo "Error: VALIDATOR_ADDRESS parameter is required."; \
179+
echo "Usage: make set-ecdsa-validator VALIDATOR_ADDRESS=0x... NETWORK=datil|base-sepolia|base-mainnet"; \
180+
exit 1; \
181+
fi
182+
@if [ -z "$(NETWORK)" ]; then \
183+
echo "Error: NETWORK parameter is required."; \
184+
echo "Usage: make set-ecdsa-validator VALIDATOR_ADDRESS=0x... NETWORK=datil|base-sepolia|base-mainnet"; \
185+
exit 1; \
186+
fi
187+
@if [ "$(NETWORK)" != "datil" ] && [ "$(NETWORK)" != "base-sepolia" ] && [ "$(NETWORK)" != "base-mainnet" ]; then \
188+
echo "Error: NETWORK must be one of: datil, base-sepolia, base-mainnet"; \
189+
exit 1; \
190+
fi
191+
@if [ -z "$(RPC_URL)" ]; then \
192+
echo "Error: RPC_URL is not set in .env"; \
193+
exit 1; \
194+
fi
195+
@if [ -z "$(VINCENT_DIAMOND_ADDRESS)" ]; then \
196+
echo "Error: VINCENT_DIAMOND_ADDRESS is not set in .env"; \
197+
exit 1; \
198+
fi
199+
@echo "Setting ECDSA validator to $(VALIDATOR_ADDRESS) on $(NETWORK)..."
200+
@echo "Using diamond address: $(VINCENT_DIAMOND_ADDRESS)"
201+
@ECDSA_VALIDATOR_ADDRESS=$(VALIDATOR_ADDRESS) VINCENT_DIAMOND_ADDRESS=$(VINCENT_DIAMOND_ADDRESS) forge script script/SetEcdsaValidatorAddress.sol:SetEcdsaValidatorAddress -vvv \
202+
--broadcast \
203+
--private-key $(VINCENT_DEPLOYER_PRIVATE_KEY) \
204+
--rpc-url $(RPC_URL)
205+
154206
get-abis: ## Get human-readable ABIs for all facets
155207
@mkdir -p abis
156208
# @echo "Getting ABI for DiamondCutFacet..."
@@ -169,6 +221,8 @@ get-abis: ## Get human-readable ABIs for all facets
169221
@forge inspect VincentUserViewFacet abi --json > abis/VincentUserViewFacet.abi.json
170222
@echo "Getting ABI for VincentERC2771Facet..."
171223
@forge inspect VincentERC2771Facet abi --json > abis/VincentERC2771Facet.abi.json
224+
@echo "Getting ABI for VincentZeroDevConfigFacet..."
225+
@forge inspect VincentZeroDevConfigFacet abi --json > abis/VincentZeroDevConfigFacet.abi.json
172226

173227
@echo "Merging facet ABIs into abis/FeeDiamond.abi.json..."
174228
@jq -s '[.[].abi] | add | unique_by(.type, .name, ((.inputs // []) | map(.type) | join(",")))' \

packages/libs/contracts-sdk/abis/VincentUserFacet.abi.json

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -363,11 +363,6 @@
363363
}
364364
]
365365
},
366-
{
367-
"type": "error",
368-
"name": "AgentNotRegisteredToUser",
369-
"inputs": []
370-
},
371366
{
372367
"type": "error",
373368
"name": "AgentRegisteredToDifferentUser",
@@ -611,6 +606,27 @@
611606
}
612607
]
613608
},
609+
{
610+
"type": "error",
611+
"name": "NotAgentOwner",
612+
"inputs": [
613+
{
614+
"name": "caller",
615+
"type": "address",
616+
"internalType": "address"
617+
},
618+
{
619+
"name": "agent",
620+
"type": "address",
621+
"internalType": "address"
622+
},
623+
{
624+
"name": "owner",
625+
"type": "address",
626+
"internalType": "address"
627+
}
628+
]
629+
},
614630
{
615631
"type": "error",
616632
"name": "NotAllRegisteredAbilitiesProvided",
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
[
2+
{
3+
"type": "function",
4+
"name": "getEcdsaValidatorAddress",
5+
"inputs": [],
6+
"outputs": [
7+
{
8+
"name": "",
9+
"type": "address",
10+
"internalType": "address"
11+
}
12+
],
13+
"stateMutability": "view"
14+
},
15+
{
16+
"type": "function",
17+
"name": "setEcdsaValidatorAddress",
18+
"inputs": [
19+
{
20+
"name": "_ecdsaValidatorAddress",
21+
"type": "address",
22+
"internalType": "address"
23+
}
24+
],
25+
"outputs": [],
26+
"stateMutability": "nonpayable"
27+
},
28+
{
29+
"type": "event",
30+
"name": "EcdsaValidatorAddressSet",
31+
"inputs": [
32+
{
33+
"name": "previousAddress",
34+
"type": "address",
35+
"indexed": true,
36+
"internalType": "address"
37+
},
38+
{
39+
"name": "newAddress",
40+
"type": "address",
41+
"indexed": true,
42+
"internalType": "address"
43+
}
44+
],
45+
"anonymous": false
46+
},
47+
{
48+
"type": "error",
49+
"name": "ZeroAddressNotAllowed",
50+
"inputs": []
51+
}
52+
]

packages/libs/contracts-sdk/contracts/LibVincentDiamondStorage.sol

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,3 +112,18 @@ library VincentUserStorage {
112112
}
113113
}
114114
}
115+
116+
library VincentZeroDevStorage {
117+
bytes32 internal constant ZERODEV_STORAGE_SLOT = keccak256("lit.vincent.zerodev.storage");
118+
119+
struct ZeroDevStorage {
120+
address ecdsaValidatorAddress;
121+
}
122+
123+
function zeroDevStorage() internal pure returns (ZeroDevStorage storage zs) {
124+
bytes32 slot = ZERODEV_STORAGE_SLOT;
125+
assembly {
126+
zs.slot := slot
127+
}
128+
}
129+
}

packages/libs/contracts-sdk/contracts/VincentDiamond.sol

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import "./facets/VincentAppViewFacet.sol";
1717
import "./facets/VincentUserFacet.sol";
1818
import "./facets/VincentUserViewFacet.sol";
1919
import "./facets/VincentERC2771Facet.sol";
20+
import "./facets/VincentZeroDevConfigFacet.sol";
2021
import "./libs/LibERC2771.sol";
2122

2223
/**
@@ -55,6 +56,8 @@ contract VincentDiamond {
5556
address vincentUserViewFacet;
5657
// The facet implementing EIP-2771 meta-transaction support
5758
address vincentERC2771Facet;
59+
// The facet implementing ZeroDev configuration
60+
address vincentZeroDevConfigFacet;
5861
}
5962

6063
/**
@@ -64,12 +67,14 @@ contract VincentDiamond {
6467
* @param _diamondCutFacet Address of the facet implementing diamond cut functionality
6568
* @param _facets Struct containing addresses of all other facets
6669
* @param _trustedForwarder Address of the Gelato trusted forwarder for EIP-2771 gasless transactions (address(0) to disable EIP-2771)
70+
* @param _ecdsaValidatorAddress Address of the ZeroDev ECDSA validator contract for smart account owner verification
6771
*/
6872
constructor(
6973
address _contractOwner,
7074
address _diamondCutFacet,
7175
FacetAddresses memory _facets,
72-
address _trustedForwarder
76+
address _trustedForwarder,
77+
address _ecdsaValidatorAddress
7378
) payable {
7479
// Validate inputs
7580
if (_diamondCutFacet == address(0)) revert InvalidFacetAddress();
@@ -79,11 +84,14 @@ contract VincentDiamond {
7984
_facets.diamondLoupeFacet == address(0) || _facets.ownershipFacet == address(0)
8085
|| _facets.vincentAppFacet == address(0) || _facets.vincentAppViewFacet == address(0)
8186
|| _facets.vincentUserFacet == address(0) || _facets.vincentUserViewFacet == address(0)
82-
|| _facets.vincentERC2771Facet == address(0)
87+
|| _facets.vincentERC2771Facet == address(0) || _facets.vincentZeroDevConfigFacet == address(0)
8388
) {
8489
revert InvalidFacetAddress();
8590
}
8691

92+
// Validate ECDSA validator address
93+
if (_ecdsaValidatorAddress == address(0)) revert InvalidFacetAddress();
94+
8795
// Set the contract owner
8896
LibDiamond.setContractOwner(_contractOwner);
8997

@@ -106,7 +114,7 @@ contract VincentDiamond {
106114
LibDiamond.diamondCut(diamondCut, address(0), "");
107115

108116
// Now add all other facets
109-
IDiamondCut.FacetCut[] memory cuts = new IDiamondCut.FacetCut[](7);
117+
IDiamondCut.FacetCut[] memory cuts = new IDiamondCut.FacetCut[](8);
110118

111119
// Add DiamondLoupeFacet
112120
cuts[0] = IDiamondCut.FacetCut({
@@ -157,12 +165,22 @@ contract VincentDiamond {
157165
functionSelectors: getVincentERC2771FacetSelectors()
158166
});
159167

168+
// Add VincentZeroDevConfigFacet
169+
cuts[7] = IDiamondCut.FacetCut({
170+
facetAddress: _facets.vincentZeroDevConfigFacet,
171+
action: IDiamondCut.FacetCutAction.Add,
172+
functionSelectors: getVincentZeroDevConfigFacetSelectors()
173+
});
174+
160175
LibDiamond.diamondCut(cuts, address(0), "");
161176

162177
// Set the trusted forwarder for EIP-2771 meta-transactions
163178
// Setting to address(0) disables EIP-2771 support
164179
VincentERC2771Storage.erc2771Storage().trustedForwarder = _trustedForwarder;
165180
emit LibERC2771.TrustedForwarderSet(_trustedForwarder);
181+
182+
// Set the ECDSA validator address for smart account owner verification
183+
VincentZeroDevStorage.zeroDevStorage().ecdsaValidatorAddress = _ecdsaValidatorAddress;
166184
}
167185

168186
/**
@@ -241,6 +259,13 @@ contract VincentDiamond {
241259
return selectors;
242260
}
243261

262+
function getVincentZeroDevConfigFacetSelectors() internal pure returns (bytes4[] memory) {
263+
bytes4[] memory selectors = new bytes4[](2);
264+
selectors[0] = VincentZeroDevConfigFacet.setEcdsaValidatorAddress.selector;
265+
selectors[1] = VincentZeroDevConfigFacet.getEcdsaValidatorAddress.selector;
266+
return selectors;
267+
}
268+
244269
/**
245270
* @notice Fallback function that forwards calls to the appropriate facet
246271
* @dev Implements diamond proxy pattern by delegating calls to the correct implementation contract

0 commit comments

Comments
 (0)