From 721e7065a61eea20dc76f6ca204756f64f392072 Mon Sep 17 00:00:00 2001 From: Ariel Barmat Date: Sun, 27 Jun 2021 17:49:16 -0300 Subject: [PATCH] Support multiple voucher signers --- .../statechannels/AllocationExchange.sol | 24 +++++++++---------- test/payments/allocationExchange.test.ts | 20 ++++++++++------ 2 files changed, 25 insertions(+), 19 deletions(-) diff --git a/contracts/statechannels/AllocationExchange.sol b/contracts/statechannels/AllocationExchange.sol index c98c79691..bc1418473 100644 --- a/contracts/statechannels/AllocationExchange.sol +++ b/contracts/statechannels/AllocationExchange.sol @@ -37,12 +37,12 @@ contract AllocationExchange is Governed { IStaking private immutable staking; IGraphToken private immutable graphToken; - address public authority; + mapping(address => bool) public authority; mapping(address => bool) public allocationsRedeemed; // -- Events - event AuthoritySet(address indexed account); + event AuthoritySet(address indexed account, bool authorized); event AllocationRedeemed(address indexed allocationID, uint256 amount); event TokensWithdrawn(address indexed to, uint256 amount); @@ -58,7 +58,7 @@ contract AllocationExchange is Governed { graphToken = _graphToken; staking = _staking; - _setAuthority(_authority); + _setAuthority(_authority, true); } /** @@ -86,19 +86,21 @@ contract AllocationExchange is Governed { * @notice Set the authority allowed to sign vouchers. * @dev Only the governor can set the authority * @param _authority Address of the signing authority + * @param _authorized True if the authority is authorized to sign vouchers, false to unset */ - function setAuthority(address _authority) external onlyGovernor { - _setAuthority(_authority); + function setAuthority(address _authority, bool _authorized) external onlyGovernor { + _setAuthority(_authority, _authorized); } /** * @notice Set the authority allowed to sign vouchers. * @param _authority Address of the signing authority + * @param _authorized True if the authority is authorized to sign vouchers, false to unset */ - function _setAuthority(address _authority) private { + function _setAuthority(address _authority, bool _authorized) private { require(_authority != address(0), "Exchange: empty authority"); - authority = _authority; - emit AuthoritySet(authority); + authority[_authority] = _authorized; + emit AuthoritySet(_authority, _authorized); } /** @@ -138,10 +140,8 @@ contract AllocationExchange is Governed { // Signature check bytes32 messageHash = keccak256(abi.encodePacked(_voucher.allocationID, _voucher.amount)); - require( - authority == ECDSA.recover(messageHash, _voucher.signature), - "Exchange: invalid signer" - ); + address voucherSigner = ECDSA.recover(messageHash, _voucher.signature); + require(authority[voucherSigner], "Exchange: invalid signer"); // Mark allocation as collected allocationsRedeemed[_voucher.allocationID] = true; diff --git a/test/payments/allocationExchange.test.ts b/test/payments/allocationExchange.test.ts index 6f9c85802..4bb60528e 100644 --- a/test/payments/allocationExchange.test.ts +++ b/test/payments/allocationExchange.test.ts @@ -78,7 +78,7 @@ describe('AllocationExchange', () => { // Ensure the exchange is correctly setup await staking.connect(governor.signer).setAssetHolder(allocationExchange.address, true) - await allocationExchange.connect(governor.signer).setAuthority(authority.address) + await allocationExchange.connect(governor.signer).setAuthority(authority.address, true) await allocationExchange.approveAll() }) @@ -114,21 +114,27 @@ describe('AllocationExchange', () => { describe('config', function () { it('should set an authority', async function () { + // Set authority const newAuthority = randomAddress() - const tx = allocationExchange.connect(governor.signer).setAuthority(newAuthority) - await expect(tx).emit(allocationExchange, 'AuthoritySet').withArgs(newAuthority) - expect(await allocationExchange.authority()).eq(newAuthority) + const tx1 = allocationExchange.connect(governor.signer).setAuthority(newAuthority, true) + await expect(tx1).emit(allocationExchange, 'AuthoritySet').withArgs(newAuthority, true) + expect(await allocationExchange.authority(newAuthority)).eq(true) + + // Unset authority + const tx2 = allocationExchange.connect(governor.signer).setAuthority(newAuthority, false) + await expect(tx2).emit(allocationExchange, 'AuthoritySet').withArgs(newAuthority, false) + expect(await allocationExchange.authority(newAuthority)).eq(false) }) it('reject set an authority if not allowed', async function () { const newAuthority = randomAddress() - const tx = allocationExchange.connect(indexer.signer).setAuthority(newAuthority) + const tx = allocationExchange.connect(indexer.signer).setAuthority(newAuthority, true) await expect(tx).revertedWith(' Only Governor can call') }) it('reject set an empty authority', async function () { const newAuthority = AddressZero - const tx = allocationExchange.connect(governor.signer).setAuthority(newAuthority) + const tx = allocationExchange.connect(governor.signer).setAuthority(newAuthority, true) await expect(tx).revertedWith('Exchange: empty authority') }) @@ -225,7 +231,7 @@ describe('AllocationExchange', () => { const allocationID = '0xfefefefefefefefefefefefefefefefefefefefe' // Ensure the exchange is correctly setup - await allocationExchange.connect(governor.signer).setAuthority(authority.address) + await allocationExchange.connect(governor.signer).setAuthority(authority.address, true) await allocationExchange.approveAll() // Initiate a withdrawal