diff --git a/source/delegate/contracts/Delegate.sol b/source/delegate/contracts/Delegate.sol index 42e3d35e8..80a2022f1 100644 --- a/source/delegate/contracts/Delegate.sol +++ b/source/delegate/contracts/Delegate.sol @@ -133,22 +133,21 @@ contract Delegate is IDelegate, Ownable { bytes32 _s ) external { Rule storage rule = rules[_senderWallet][_senderToken][_signerToken]; - // Ensure the signer amount is valid - if ( - _signerAmount < - (rule.signerAmount * (rule.senderAmount - rule.senderFilledAmount)) / - rule.senderAmount - ) { - revert SignerAmountInvalid(); - } - // Ensure the rule has not expired - if (rule.expiry < block.timestamp) revert RuleExpired(); + // Ensure the expiry is not passed + if (rule.expiry <= block.timestamp) revert RuleExpiredOrDoesNotExist(); // Ensure the sender amount is valid if (_senderAmount > (rule.senderAmount - rule.senderFilledAmount)) { revert SenderAmountInvalid(); } + // Ensure the signer amount is valid + if ( + rule.signerAmount * _senderAmount != rule.senderAmount * _signerAmount + ) { + revert SignerAmountInvalid(); + } + // Transfer the sender token to this contract SafeTransferLib.safeTransferFrom( _senderToken, diff --git a/source/delegate/contracts/interfaces/IDelegate.sol b/source/delegate/contracts/interfaces/IDelegate.sol index 7f1cb0c3f..bd0412ba4 100644 --- a/source/delegate/contracts/interfaces/IDelegate.sol +++ b/source/delegate/contracts/interfaces/IDelegate.sol @@ -33,7 +33,7 @@ interface IDelegate { ); error AddressInvalid(); - error RuleExpired(); + error RuleExpiredOrDoesNotExist(); error SenderAmountInvalid(); error SignerAmountInvalid(); error SenderInvalid(); diff --git a/source/delegate/test/Delegate.js b/source/delegate/test/Delegate.js index d2a8ea79a..c80d4dcda 100644 --- a/source/delegate/test/Delegate.js +++ b/source/delegate/test/Delegate.js @@ -13,7 +13,7 @@ const { } = require('@airswap/utils') const CHAIN_ID = 31337 const DEFAULT_BALANCE = '100000' -const DEFAULT_SENDER_AMOUNT = '10000' +const DEFAULT_SENDER_AMOUNT = '5000' const DEFAULT_SIGNER_AMOUNT = '10000' const PROTOCOL_FEE = '5' const REBATE_SCALE = '10' @@ -456,13 +456,41 @@ describe('Delegate Unit', () => { .withArgs(delegate.address) .returns(DEFAULT_SIGNER_AMOUNT) - await expect(delegate.connect(signer).swap(sender.address, ...order)).to - .be.reverted + await expect( + delegate.connect(signer).swap(sender.address, ...order) + ).to.be.revertedWith('RuleExpiredOrDoesNotExist') }) - it('fails to swap with insufficient remaining sender amount on Rule', async () => { + it('fails to swap with a rule expired', async () => { + await delegate + .connect(sender) + .setRule( + sender.address, + senderToken.address, + DEFAULT_SENDER_AMOUNT, + signerToken.address, + DEFAULT_SIGNER_AMOUNT, + Math.round(Date.now() / 1000) - 10 + ) + + const order = await createSignedOrderERC20({}, signer) + + await setUpAllowances( + sender.address, + DEFAULT_SENDER_AMOUNT, + signer.address, + DEFAULT_SIGNER_AMOUNT + PROTOCOL_FEE + ) + await setUpBalances(signer.address, sender.address) + + await expect( + delegate.connect(signer).swap(sender.address, ...order) + ).to.be.revertedWith('RuleExpiredOrDoesNotExist') + }) + + it('fails to swap with sender amount above rule sender amount', async () => { await senderToken.mock.approve - .withArgs(delegate.address, DEFAULT_SENDER_AMOUNT - 1) + .withArgs(delegate.address, DEFAULT_SENDER_AMOUNT / 2) .returns(true) await delegate @@ -470,9 +498,9 @@ describe('Delegate Unit', () => { .setRule( sender.address, senderToken.address, - DEFAULT_SENDER_AMOUNT - 1, + DEFAULT_SENDER_AMOUNT / 2, signerToken.address, - DEFAULT_SIGNER_AMOUNT, + DEFAULT_SIGNER_AMOUNT / 2, RULE_EXPIRY ) @@ -488,16 +516,16 @@ describe('Delegate Unit', () => { await signerToken.mock.balanceOf .withArgs(signer.address) - .returns(DEFAULT_SIGNER_AMOUNT - 1) + .returns(DEFAULT_SIGNER_AMOUNT) await expect( delegate.connect(signer).swap(sender.address, ...order) ).to.be.revertedWith('SenderAmountInvalid') }) - it('fails to swap with insufficient signer amount on Rule', async () => { + it('fails to swap with sender amount above remaining rule sender amount', async () => { await senderToken.mock.approve - .withArgs(delegate.address, DEFAULT_SENDER_AMOUNT - 1) + .withArgs(delegate.address, DEFAULT_SENDER_AMOUNT / 2) .returns(true) await delegate @@ -511,12 +539,7 @@ describe('Delegate Unit', () => { RULE_EXPIRY ) - const order = await createSignedOrderERC20( - { - signerAmount: DEFAULT_SIGNER_AMOUNT - 1, - }, - signer - ) + const order = await createSignedOrderERC20({}, signer) await setUpAllowances( sender.address, @@ -528,14 +551,24 @@ describe('Delegate Unit', () => { await signerToken.mock.balanceOf .withArgs(signer.address) - .returns(DEFAULT_SIGNER_AMOUNT - 1) + .returns(DEFAULT_SIGNER_AMOUNT) await expect( delegate.connect(signer).swap(sender.address, ...order) - ).to.be.revertedWith('SignerAmountInvalid') + ).to.emit(delegate, 'DelegateSwap') + + const order2 = await createSignedOrderERC20({}, signer) + + await expect( + delegate.connect(signer).swap(sender.address, ...order2) + ).to.be.revertedWith('SenderAmountInvalid') }) - it('fails to swap with a rule expired', async () => { + it('fails to swap with insufficient signer amount on Rule', async () => { + await senderToken.mock.approve + .withArgs(delegate.address, DEFAULT_SENDER_AMOUNT - 1) + .returns(true) + await delegate .connect(sender) .setRule( @@ -544,10 +577,16 @@ describe('Delegate Unit', () => { DEFAULT_SENDER_AMOUNT, signerToken.address, DEFAULT_SIGNER_AMOUNT, - 0 + RULE_EXPIRY ) - const order = await createSignedOrderERC20({}, signer) + const order = await createSignedOrderERC20( + { + senderAmount: DEFAULT_SENDER_AMOUNT, + signerAmount: DEFAULT_SIGNER_AMOUNT / 4, + }, + signer + ) await setUpAllowances( sender.address, @@ -557,9 +596,13 @@ describe('Delegate Unit', () => { ) await setUpBalances(signer.address, sender.address) + await signerToken.mock.balanceOf + .withArgs(signer.address) + .returns(DEFAULT_SIGNER_AMOUNT - 1) + await expect( delegate.connect(signer).swap(sender.address, ...order) - ).to.revertedWith('RuleExpired') + ).to.be.revertedWith('SignerAmountInvalid') }) }) })