diff --git a/interface/IEscrow.sol b/interface/IEscrow.sol index dcefe3df..08e479c8 100644 --- a/interface/IEscrow.sol +++ b/interface/IEscrow.sol @@ -37,6 +37,7 @@ interface IEscrow { event TokenWhitelisted (address indexed token); event TokenRemovedFromWhitelist(address indexed token); event BatchDeposited (uint indexed batchId, uint repoId, uint timestamp, uint[] depositIds); + event SignerSet (address indexed newSigner); /** * @notice Deposits tokens into the escrow on behalf of a specified sender and recipient. diff --git a/libraries/Params.sol b/libraries/Params.sol index 47802884..f1f3b3ae 100644 --- a/libraries/Params.sol +++ b/libraries/Params.sol @@ -4,6 +4,7 @@ pragma solidity =0.8.26; library Params { address constant MAINNET_USDC = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48; address constant OWNER = 0x9d8A62f656a8d1615C1294fd71e9CFb3E4855A4F; + address constant SIGNER = 0x9d8A62f656a8d1615C1294fd71e9CFb3E4855A4F; // BASE address constant BASE_WETH = 0x4200000000000000000000000000000000000006; diff --git a/script/Deploy.Base.s.sol b/script/Deploy.Base.s.sol index 0d013fd2..92b8bd5b 100644 --- a/script/Deploy.Base.s.sol +++ b/script/Deploy.Base.s.sol @@ -11,6 +11,6 @@ contract DeployBase is Deploy { address[] memory initialWhitelistedTokens = new address[](1); initialWhitelistedTokens[0] = Params.BASE_USDC; - escrow = deploy(Params.OWNER, initialWhitelistedTokens, Params.BASE_FEE_BPS); + escrow = deploy(Params.OWNER, Params.SIGNER, initialWhitelistedTokens, Params.BASE_FEE_BPS); } } \ No newline at end of file diff --git a/script/Deploy.BaseSepolia.s.sol b/script/Deploy.BaseSepolia.s.sol index b5fa699c..f26be07f 100644 --- a/script/Deploy.BaseSepolia.s.sol +++ b/script/Deploy.BaseSepolia.s.sol @@ -18,7 +18,8 @@ contract DeployBaseSepolia is DeployTestBase { testers, Params.BASESEPOLIA_WETH, Params.BASESEPOLIA_USDC, - Params.OWNER + Params.OWNER, + Params.SIGNER ); createTestPayments( diff --git a/script/Deploy.Sepolia.sol b/script/Deploy.Sepolia.sol index 5474ded6..efbae7c4 100644 --- a/script/Deploy.Sepolia.sol +++ b/script/Deploy.Sepolia.sol @@ -18,7 +18,8 @@ contract DeploySepolia is DeployTestBase { testers, Params.SEPOLIA_WETH, Params.SEPOLIA_USDC, - Params.OWNER + Params.OWNER, + Params.SIGNER ); createTestPayments( diff --git a/script/Deploy.Test.Base.s.sol b/script/Deploy.Test.Base.s.sol index 396ad305..f0d7e7a8 100644 --- a/script/Deploy.Test.Base.s.sol +++ b/script/Deploy.Test.Base.s.sol @@ -18,7 +18,8 @@ abstract contract DeployTestBase is Deploy { address[] memory testers, address weth, address usdc, - address owner + address owner, + address signer ) internal { vm.startBroadcast(); @@ -34,7 +35,7 @@ abstract contract DeployTestBase is Deploy { initialWhitelistedTokens[1] = usdc; initialWhitelistedTokens[2] = address(mockUSDC); - escrow = deploy(owner, initialWhitelistedTokens, 0); + escrow = deploy(owner, signer, initialWhitelistedTokens, 0); } function createTestPayments( diff --git a/script/Deploy.s.sol b/script/Deploy.s.sol index 7f5f3754..801af1fd 100644 --- a/script/Deploy.s.sol +++ b/script/Deploy.s.sol @@ -8,6 +8,7 @@ import {Script} from "forge-std/Script.sol"; contract Deploy is Script { function deploy( address owner, + address signer, address[] memory initialWhitelistedTokens, uint feeBps ) @@ -18,6 +19,7 @@ contract Deploy is Script { escrow = new Escrow( owner, + signer, initialWhitelistedTokens, feeBps ); diff --git a/script/utils/Gas.s.sol b/script/utils/Gas.s.sol index 8e0eacfc..d329dad4 100644 --- a/script/utils/Gas.s.sol +++ b/script/utils/Gas.s.sol @@ -20,7 +20,7 @@ contract DeploySepolia is Script { address[] memory initialWhitelistedTokens = new address[](1); initialWhitelistedTokens[0] = address(mockUSDC); - Escrow escrow = new Deploy().deploy(Params.OWNER, initialWhitelistedTokens, 0); + Escrow escrow = new Deploy().deploy(Params.OWNER, Params.SIGNER, initialWhitelistedTokens, 0); for (uint256 j = 0; j < NUM_DEPOSITS.length; j++) { uint256 numDeposits = NUM_DEPOSITS[j]; diff --git a/src/Escrow.sol b/src/Escrow.sol index 78592bee..2b880a73 100644 --- a/src/Escrow.sol +++ b/src/Escrow.sol @@ -27,6 +27,8 @@ contract Escrow is Owned, IEscrow { mapping(address => bool) public canClaim; mapping(address => uint) public recipientNonces; + address public signer; + struct Deposit { uint amount; ERC20 token; @@ -47,6 +49,7 @@ contract Escrow is Owned, IEscrow { constructor( address _owner, + address _signer, address[] memory _initialWhitelistedTokens, uint _initialFeeBps ) Owned(_owner) { @@ -55,6 +58,7 @@ contract Escrow is Owned, IEscrow { protocolFeeBps = _initialFeeBps; CLAIM_INITIAL_CHAIN_ID = block.chainid; CLAIM_INITIAL_DOMAIN_SEPARATOR = _computeClaimDomainSeparator(); + signer = _signer; for (uint256 i = 0; i < _initialWhitelistedTokens.length; i++) { _whitelistedTokens.add(_initialWhitelistedTokens[i]); @@ -240,8 +244,8 @@ contract Escrow is Owned, IEscrow { abi.encodePacked("\x19\x01", CLAIM_DOMAIN_SEPARATOR(), structHash) ); - address signer = ECDSA.recover(digest, v, r, s); - require(signer == owner, Errors.INVALID_SIGNATURE); + address recoveredSigner = ECDSA.recover(digest, v, r, s); + require(recoveredSigner == signer, Errors.INVALID_SIGNATURE); recipientNonces[recipient]++; @@ -324,4 +328,12 @@ contract Escrow is Owned, IEscrow { emit FeeRecipientSet(_newFeeRecipient); } + /*////////////////////////////////////////////////////////////// + SIGNER MANAGEMENT (Owner Only) + //////////////////////////////////////////////////////////////*/ + function setSigner(address _newSigner) external onlyOwner { + require(_newSigner != address(0), Errors.INVALID_ADDRESS); + signer = _newSigner; + emit SignerSet(_newSigner); + } } diff --git a/test/Deploy.t.sol b/test/Deploy.t.sol index e8c5654d..3edd2e81 100644 --- a/test/Deploy.t.sol +++ b/test/Deploy.t.sol @@ -20,6 +20,7 @@ contract Deploy_Test is Test { assertTrue(address(escrow) != address(0), "Escrow not deployed"); assertTrue(escrow.isTokenWhitelisted(Params.BASE_USDC), "WETH not whitelisted"); assertEq (escrow.owner(), Params.OWNER, "Incorrect owner"); + assertEq (escrow.signer(), Params.SIGNER, "Incorrect signer"); assertEq (escrow.feeRecipient(), Params.OWNER, "Incorrect fee recipient"); assertEq (escrow.protocolFeeBps(), Params.BASE_FEE_BPS, "Incorrect fee"); } diff --git a/test/Escrow.t.sol b/test/Escrow.t.sol index e4458cab..c45ccec9 100644 --- a/test/Escrow.t.sol +++ b/test/Escrow.t.sol @@ -26,7 +26,7 @@ contract Base_Test is Test { function setUp() public { address[] memory initialWhitelistedTokens = new address[](1); initialWhitelistedTokens[0] = address(wETH); - escrow = new Deploy().deploy(owner, initialWhitelistedTokens, 0); + escrow = new Deploy().deploy(owner, owner, initialWhitelistedTokens, 0); alice = makeAddr("alice"); bob = makeAddr("bob"); diff --git a/test/EscrowWithFee.t.sol b/test/EscrowWithFee.t.sol index e88ef817..7897ca6e 100644 --- a/test/EscrowWithFee.t.sol +++ b/test/EscrowWithFee.t.sol @@ -29,7 +29,7 @@ contract Base_Test is Test { function setUp() public { address[] memory initialWhitelistedTokens = new address[](1); initialWhitelistedTokens[0] = address(wETH); - escrow = new Deploy().deploy(owner, initialWhitelistedTokens, Params.BASE_FEE_BPS); + escrow = new Deploy().deploy(owner, owner, initialWhitelistedTokens, Params.BASE_FEE_BPS); alice = makeAddr("alice"); bob = makeAddr("bob");