From a876c5480df2a526fb902898f111ff3948635851 Mon Sep 17 00:00:00 2001 From: Entreprenerd Date: Fri, 5 Aug 2022 19:03:27 +0200 Subject: [PATCH 01/17] feat: initial test + try catch fix --- contracts/AuraBribesProcessor.sol | 20 ++++++-- tests/aura_processor/test_real_life_revert.py | 50 +++++++++++++++++++ 2 files changed, 66 insertions(+), 4 deletions(-) create mode 100644 tests/aura_processor/test_real_life_revert.py diff --git a/contracts/AuraBribesProcessor.sol b/contracts/AuraBribesProcessor.sol index 0770fe3..f1663d3 100644 --- a/contracts/AuraBribesProcessor.sol +++ b/contracts/AuraBribesProcessor.sol @@ -202,13 +202,25 @@ contract AuraBribesProcessor is CowSwapSeller { swaps[0] = batchSwapStep; // Amount out is positive amount of second asset delta - int256[] memory assetDeltas = BALANCER_VAULT.queryBatchSwap( + uint256 fromPurchase; + + try BALANCER_VAULT.queryBatchSwap( IBalancerVault.SwapKind.GIVEN_IN, swaps, assets, fundManagement - ); - uint256 fromPurchase = uint256(-assetDeltas[1]); + ) returns (int256[] memory assetDeltas) { + // Try + if(-assetDeltas[1] > 0) { + fromPurchase = uint256(-assetDeltas[1]); + } + } catch { + // Catch clause + // Revert + // 0 is acceptable as vault would never quote 0 unless balance is ininitely greater + // Even in that case we would prob rather deposit in the vault + fromPurchase = 0; + } // Check math from vault // from Vault code shares = (_amount.mul(totalSupply())).div(_pool); @@ -216,7 +228,7 @@ contract AuraBribesProcessor is CowSwapSeller { uint256 ops_fee; uint256 toEmit; - if(fromDeposit > fromPurchase) { + if(fromDeposit >= fromPurchase) { // Costs less to deposit // ops_fee = int(total / (1 - BADGER_SHARE) * OPS_FEE), adapted to solidity for precision diff --git a/tests/aura_processor/test_real_life_revert.py b/tests/aura_processor/test_real_life_revert.py new file mode 100644 index 0000000..851b9c8 --- /dev/null +++ b/tests/aura_processor/test_real_life_revert.py @@ -0,0 +1,50 @@ +import brownie +from brownie import * +import pytest + +LIVE_PROCESSOR = "0xC66C9F87d847dDc964724B789D3113885b08efCF" + +@pytest.fixture +def reverting_contract(): + return AuraBribesProcessor.at(LIVE_PROCESSOR) + + +@pytest.fixture +def live_pricer(reverting_contract): + return reverting_contract.pricer() + +@pytest.fixture +def fixed_contract(live_pricer, reverting_contract, manager, aura, aura_whale): + + ## Deploy + p = AuraBribesProcessor.deploy(live_pricer, {"from": manager}) + + + amount_to_test = aura.balanceOf(reverting_contract) + + ## Send some aura + aura.transfer(p, amount_to_test, {"from": aura_whale}) + + return p + + + +def test_compare_live_to_fix(reverting_contract, fixed_contract, manager, aura, bve_aura, aura_whale): + live_manager = accounts.at(reverting_contract.manager(), force=True) + + with brownie.reverts(): + reverting_contract.swapAURATobveAURAAndEmit({"from": live_manager}) + + tree = fixed_contract.BADGER_TREE() + prev_bal = bve_aura.balanceOf(tree) + + assert aura.balanceOf(fixed_contract) > 0 + + fixed_contract.swapAURATobveAURAAndEmit({"from": manager}) + after_bal = bve_aura.balanceOf(tree) + + ## Net increase + assert after_bal > prev_bal + + ## TODO: Proper exact math to make sure no value was leaked + From a83aeddb14d025613be87c8a1efdba54e7de29bc Mon Sep 17 00:00:00 2001 From: Entreprenerd Date: Sun, 7 Aug 2022 18:14:08 +0200 Subject: [PATCH 02/17] feat: test precision to the wei --- tests/aura_processor/test_real_life_revert.py | 35 +++++++++++++++---- 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/tests/aura_processor/test_real_life_revert.py b/tests/aura_processor/test_real_life_revert.py index 851b9c8..9f0eaad 100644 --- a/tests/aura_processor/test_real_life_revert.py +++ b/tests/aura_processor/test_real_life_revert.py @@ -29,22 +29,45 @@ def fixed_contract(live_pricer, reverting_contract, manager, aura, aura_whale): -def test_compare_live_to_fix(reverting_contract, fixed_contract, manager, aura, bve_aura, aura_whale): +def test_compare_live_to_fix(reverting_contract, fixed_contract, manager, aura, bve_aura): + """ + Demonstrate revert in old code + Shows new code won't revert + Proves math equivalence via exact amount sent to tree + """ live_manager = accounts.at(reverting_contract.manager(), force=True) - with brownie.reverts(): - reverting_contract.swapAURATobveAURAAndEmit({"from": live_manager}) - + ## Setup tree = fixed_contract.BADGER_TREE() prev_bal = bve_aura.balanceOf(tree) - assert aura.balanceOf(fixed_contract) > 0 + bve_sett = interface.ISettV4(fixed_contract.BVE_AURA()) + + ## Math for expected number of tokens out from vault + prev_bal = bve_aura.balanceOf(tree) + + aura_to_process = aura.balanceOf(fixed_contract) + + assert aura_to_process > 0 + + ops_fee = aura_to_process * fixed_contract.OPS_FEE() // (fixed_contract.MAX_BPS() - fixed_contract.BADGER_SHARE()) + + expected_bve_aura_to_tree = (aura_to_process - ops_fee) * bve_sett.totalSupply() // bve_sett.balance() + + + ## Show revert on live ## NOTE: This may stop reverting for external reasons + with brownie.reverts(): + reverting_contract.swapAURATobveAURAAndEmit({"from": live_manager}) + + + ## Run fixed and check fixed_contract.swapAURATobveAURAAndEmit({"from": manager}) after_bal = bve_aura.balanceOf(tree) ## Net increase assert after_bal > prev_bal - ## TODO: Proper exact math to make sure no value was leaked + ## Proper exact math to make sure no value was leaked + assert after_bal - prev_bal == expected_bve_aura_to_tree From fe472207a58ff71e4434c96741201f95de9ac5d2 Mon Sep 17 00:00:00 2001 From: Entreprenerd Date: Mon, 8 Aug 2022 02:53:33 +0200 Subject: [PATCH 03/17] feat: INCOMPLETE sketch of new step 3 --- contracts/AuraBribesProcessor.sol | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/contracts/AuraBribesProcessor.sol b/contracts/AuraBribesProcessor.sol index f1663d3..81e3d08 100644 --- a/contracts/AuraBribesProcessor.sol +++ b/contracts/AuraBribesProcessor.sol @@ -59,9 +59,9 @@ contract AuraBribesProcessor is CowSwapSeller { IVault public constant BVE_AURA = IVault(0xBA485b556399123261a5F9c95d413B4f93107407); - /// BVE_AURA, WETH, AURA + /// BVE_AURA, WETH, AURABal /// https://app.balancer.fi/#/pool/0xa3283e3470d3cd1f18c074e3f2d3965f6d62fff2000100000000000000000267 - bytes32 public constant BVE_AURA_WETH_AURA_POOL = 0xa3283e3470d3cd1f18c074e3f2d3965f6d62fff2000100000000000000000267; + bytes32 public constant BVE_AURA_WETH_AURABAL_POOL = 0xa3283e3470d3cd1f18c074e3f2d3965f6d62fff2000100000000000000000267; IBalancerVault public constant BALANCER_VAULT = IBalancerVault(0xBA12222222228d8Ba445958a75a0704d566BF2C8); @@ -154,18 +154,21 @@ contract AuraBribesProcessor is CowSwapSeller { /// @dev /// Step 2.b - /// Swap WETH -> AURA + /// Swap WETH -> graviAURA or WETH -> AURA function swapWethForAURA(Data calldata orderData, bytes memory orderUid) external { require(orderData.sellToken == WETH); // Must Sell WETH - require(orderData.buyToken == AURA); // Must buy AURA + require(orderData.buyToken == AURA || orderData.buyToken == BVE_AURA); // Must buy AURA or BVE_AURA /// NOTE: checks for msg.sender == manager _doCowswapOrder(orderData, orderUid); } + /// AURA -> graviAURA -> Always Deposit in vault, unless direct pool + /// @dev /// Step 3 Emit the Aura /// Takes all the Aura, takes fee, locks and emits it + // TODO: REDO MATH to handle case of AURA / graviAURA already in this contract function swapAURATobveAURAAndEmit() external nonReentrant { // Will take all the Aura left, // swap it for bveAura if cheaper, or deposit it directly @@ -191,7 +194,7 @@ contract AuraBribesProcessor is CowSwapSeller { bytes memory emptyBytes = new bytes(0); IBalancerVault.BatchSwapStep memory batchSwapStep = IBalancerVault.BatchSwapStep({ - poolId: BVE_AURA_WETH_AURA_POOL, + poolId: BVE_AURA_WETH_AURABAL_POOL, // NOTE: This pool should be substituted with a graviAURA / AURA Pool assetInIndex: 0, assetOutIndex: 1, amount: totalAURA, @@ -256,7 +259,7 @@ contract AuraBribesProcessor is CowSwapSeller { AURA.safeApprove(address(BALANCER_VAULT), totalAURA); IBalancerVault.SingleSwap memory singleSwap = IBalancerVault.SingleSwap({ - poolId: BVE_AURA_WETH_AURA_POOL, + poolId: BVE_AURA_WETH_AURABAL_POOL, kind: IBalancerVault.SwapKind.GIVEN_IN, assetIn: IAsset(address(AURA)), assetOut: IAsset(address(BVE_AURA)), From d52ce5c0345097fa47f795b7971af35c9b2b16ad Mon Sep 17 00:00:00 2001 From: Entreprenerd Date: Mon, 8 Aug 2022 15:55:45 +0200 Subject: [PATCH 04/17] feat: rewritten Step 3 to handle AURA and BVE_AURA --- contracts/AuraBribesProcessor.sol | 120 +++++------------------------- 1 file changed, 20 insertions(+), 100 deletions(-) diff --git a/contracts/AuraBribesProcessor.sol b/contracts/AuraBribesProcessor.sol index 81e3d08..ef82865 100644 --- a/contracts/AuraBribesProcessor.sol +++ b/contracts/AuraBribesProcessor.sol @@ -59,10 +59,6 @@ contract AuraBribesProcessor is CowSwapSeller { IVault public constant BVE_AURA = IVault(0xBA485b556399123261a5F9c95d413B4f93107407); - /// BVE_AURA, WETH, AURABal - /// https://app.balancer.fi/#/pool/0xa3283e3470d3cd1f18c074e3f2d3965f6d62fff2000100000000000000000267 - bytes32 public constant BVE_AURA_WETH_AURABAL_POOL = 0xa3283e3470d3cd1f18c074e3f2d3965f6d62fff2000100000000000000000267; - IBalancerVault public constant BALANCER_VAULT = IBalancerVault(0xBA12222222228d8Ba445958a75a0704d566BF2C8); // We send tokens to emit here @@ -157,7 +153,10 @@ contract AuraBribesProcessor is CowSwapSeller { /// Swap WETH -> graviAURA or WETH -> AURA function swapWethForAURA(Data calldata orderData, bytes memory orderUid) external { require(orderData.sellToken == WETH); // Must Sell WETH - require(orderData.buyToken == AURA || orderData.buyToken == BVE_AURA); // Must buy AURA or BVE_AURA + require( + orderData.buyToken == AURA || + orderData.buyToken == IERC20(address(BVE_AURA)) + ); // Must buy AURA or BVE_AURA /// NOTE: checks for msg.sender == manager _doCowswapOrder(orderData, orderUid); @@ -176,109 +175,30 @@ contract AuraBribesProcessor is CowSwapSeller { require(msg.sender == manager); uint256 totalAURA = AURA.balanceOf(address(this)); - require(totalAURA > 0); require(HARVEST_FORWARDER.badger_tree() == BADGER_TREE); - - // Get quote from balancer pool using queryBatchSwap - IBalancerVault.FundManagement memory fundManagement = IBalancerVault.FundManagement({ - sender: address(this), - fromInternalBalance: false, - recipient: payable(address(this)), - toInternalBalance: false - }); - - IAsset[] memory assets = new IAsset[](2); - assets[0] = IAsset(address(AURA)); - assets[1] = IAsset(address(BVE_AURA)); - - bytes memory emptyBytes = new bytes(0); - - IBalancerVault.BatchSwapStep memory batchSwapStep = IBalancerVault.BatchSwapStep({ - poolId: BVE_AURA_WETH_AURABAL_POOL, // NOTE: This pool should be substituted with a graviAURA / AURA Pool - assetInIndex: 0, - assetOutIndex: 1, - amount: totalAURA, - userData: emptyBytes - }); - - IBalancerVault.BatchSwapStep[] memory swaps = new IBalancerVault.BatchSwapStep[](1); - swaps[0] = batchSwapStep; - - // Amount out is positive amount of second asset delta - uint256 fromPurchase; - try BALANCER_VAULT.queryBatchSwap( - IBalancerVault.SwapKind.GIVEN_IN, - swaps, - assets, - fundManagement - ) returns (int256[] memory assetDeltas) { - // Try - if(-assetDeltas[1] > 0) { - fromPurchase = uint256(-assetDeltas[1]); - } - } catch { - // Catch clause - // Revert - // 0 is acceptable as vault would never quote 0 unless balance is ininitely greater - // Even in that case we would prob rather deposit in the vault - fromPurchase = 0; + // === Handling of AURA === // + if(totalAURA > 0) { + // We'll also deposit the AURA + AURA.safeIncreaseAllowance(address(BVE_AURA), totalAURA); + // Deposit to address(this) + BVE_AURA.deposit(totalAURA); + + // NOTE: Can be re-extended to use xyz stable pool (just use try/catch and expect long term failure) } - // Check math from vault - // from Vault code shares = (_amount.mul(totalSupply())).div(_pool); - uint256 fromDeposit = totalAURA * BVE_AURA.totalSupply() / BVE_AURA.balance(); - - uint256 ops_fee; - uint256 toEmit; - if(fromDeposit >= fromPurchase) { - // Costs less to deposit - // ops_fee = int(total / (1 - BADGER_SHARE) * OPS_FEE), adapted to solidity for precision - ops_fee = totalAURA * OPS_FEE / (MAX_BPS - BADGER_SHARE); + // === Emit bveAURA === // + uint256 totalBveAURA = BVE_AURA.balanceOf(address(this)); - toEmit = totalAURA - ops_fee; - AURA.safeApprove(address(BVE_AURA), totalAURA); - uint256 treasuryPrevBalance = BVE_AURA.balanceOf(TREASURY); + uint256 ops_fee = totalBveAURA * OPS_FEE / (MAX_BPS - BADGER_SHARE); + IERC20(address(BVE_AURA)).safeTransfer(TREASURY, ops_fee); - // If we don't swap - - // Take the fee - BVE_AURA.depositFor(TREASURY, ops_fee); - - // Deposit and emit rest - uint256 initialBveAURABalance = BVE_AURA.balanceOf((address(this))); - BVE_AURA.deposit(toEmit); - - // Update vars as we emit event with them - ops_fee = BVE_AURA.balanceOf(TREASURY) - treasuryPrevBalance; - toEmit = BVE_AURA.balanceOf(address(this)) - initialBveAURABalance; - } else { - // Buy from pool using singleSwap - - AURA.safeApprove(address(BALANCER_VAULT), totalAURA); - - IBalancerVault.SingleSwap memory singleSwap = IBalancerVault.SingleSwap({ - poolId: BVE_AURA_WETH_AURABAL_POOL, - kind: IBalancerVault.SwapKind.GIVEN_IN, - assetIn: IAsset(address(AURA)), - assetOut: IAsset(address(BVE_AURA)), - amount: totalAURA, - userData: emptyBytes - }); - - uint256 totalBveAURA = BALANCER_VAULT.swap(singleSwap, fundManagement, fromPurchase, block.timestamp); - - ops_fee = totalBveAURA * OPS_FEE / (MAX_BPS - BADGER_SHARE); - - toEmit = totalBveAURA - ops_fee; - - // Take fee - IERC20(address(BVE_AURA)).safeTransfer(TREASURY, ops_fee); - } + // Subtraction to avoid dust + uint256 toEmit = totalBveAURA - ops_fee; - // Emit token - IERC20(address(BVE_AURA)).safeApprove(address(HARVEST_FORWARDER), toEmit); + // Emit token to tree via HARVEST_FORWARDER + IERC20(address(BVE_AURA)).safeIncreaseAllowance(address(HARVEST_FORWARDER), toEmit); HARVEST_FORWARDER.distribute(address(BVE_AURA), toEmit, address(BVE_AURA)); emit PerformanceFeeGovernance(address(BVE_AURA), ops_fee); From fd6014e8d2f108c039211abb3b15ae96de4e1ac8 Mon Sep 17 00:00:00 2001 From: Entreprenerd Date: Mon, 8 Aug 2022 16:00:22 +0200 Subject: [PATCH 05/17] feat: revert if no op --- contracts/AuraBribesProcessor.sol | 1 + 1 file changed, 1 insertion(+) diff --git a/contracts/AuraBribesProcessor.sol b/contracts/AuraBribesProcessor.sol index ef82865..8960850 100644 --- a/contracts/AuraBribesProcessor.sol +++ b/contracts/AuraBribesProcessor.sol @@ -190,6 +190,7 @@ contract AuraBribesProcessor is CowSwapSeller { // === Emit bveAURA === // uint256 totalBveAURA = BVE_AURA.balanceOf(address(this)); + require(totalBveAURA > 0); uint256 ops_fee = totalBveAURA * OPS_FEE / (MAX_BPS - BADGER_SHARE); IERC20(address(BVE_AURA)).safeTransfer(TREASURY, ops_fee); From f0c241aacbdb979f0a0d8f7dfac138200f598591 Mon Sep 17 00:00:00 2001 From: Entreprenerd Date: Mon, 8 Aug 2022 16:24:26 +0200 Subject: [PATCH 06/17] fix: fail early --- contracts/AuraBribesProcessor.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/AuraBribesProcessor.sol b/contracts/AuraBribesProcessor.sol index 8960850..1cd9400 100644 --- a/contracts/AuraBribesProcessor.sol +++ b/contracts/AuraBribesProcessor.sol @@ -173,9 +173,9 @@ contract AuraBribesProcessor is CowSwapSeller { // swap it for bveAura if cheaper, or deposit it directly // and then emit it require(msg.sender == manager); + require(HARVEST_FORWARDER.badger_tree() == BADGER_TREE); uint256 totalAURA = AURA.balanceOf(address(this)); - require(HARVEST_FORWARDER.badger_tree() == BADGER_TREE); // === Handling of AURA === // if(totalAURA > 0) { From 3c2b72490580a637a3672b7d966ba109a1cd46de Mon Sep 17 00:00:00 2001 From: Entreprenerd Date: Mon, 8 Aug 2022 16:24:37 +0200 Subject: [PATCH 07/17] chore: space --- contracts/AuraBribesProcessor.sol | 1 - 1 file changed, 1 deletion(-) diff --git a/contracts/AuraBribesProcessor.sol b/contracts/AuraBribesProcessor.sol index 1cd9400..411a076 100644 --- a/contracts/AuraBribesProcessor.sol +++ b/contracts/AuraBribesProcessor.sol @@ -187,7 +187,6 @@ contract AuraBribesProcessor is CowSwapSeller { // NOTE: Can be re-extended to use xyz stable pool (just use try/catch and expect long term failure) } - // === Emit bveAURA === // uint256 totalBveAURA = BVE_AURA.balanceOf(address(this)); require(totalBveAURA > 0); From 0b143125abc23f7a8576c9a6ee24aea8be86ed6e Mon Sep 17 00:00:00 2001 From: Entreprenerd Date: Mon, 8 Aug 2022 18:03:19 +0200 Subject: [PATCH 08/17] feat: 5% fee everywhere + cleanup --- contracts/AuraBribesProcessor.sol | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/contracts/AuraBribesProcessor.sol b/contracts/AuraBribesProcessor.sol index 411a076..dadc6ae 100644 --- a/contracts/AuraBribesProcessor.sol +++ b/contracts/AuraBribesProcessor.sol @@ -47,11 +47,8 @@ contract AuraBribesProcessor is CowSwapSeller { // Source: https://badger.com/graviaura uint256 public constant MAX_BPS = 10_000; - uint256 public constant BADGER_SHARE = 2500; //25.00% - // A 5% fee will be charged on all bribes processed. uint256 public constant OPS_FEE = 500; // 5% - // uint256 public constant LP_FEE = 0; // Not used /// `treasury_voter_multisig` /// https://github.com/Badger-Finance/badger-multisig/blob/6cd8f42ae0313d0da33a208d452370343e7599ba/helpers/addresses.py#L52 @@ -191,7 +188,7 @@ contract AuraBribesProcessor is CowSwapSeller { uint256 totalBveAURA = BVE_AURA.balanceOf(address(this)); require(totalBveAURA > 0); - uint256 ops_fee = totalBveAURA * OPS_FEE / (MAX_BPS - BADGER_SHARE); + uint256 ops_fee = totalBveAURA * OPS_FEE / MAX_BPS; IERC20(address(BVE_AURA)).safeTransfer(TREASURY, ops_fee); // Subtraction to avoid dust @@ -213,10 +210,14 @@ contract AuraBribesProcessor is CowSwapSeller { // Sends Badger to the Tree // Emits custom event for it - uint256 toEmitTotal = BADGER.balanceOf(address(this)); - require(toEmitTotal > 0); + uint256 totalBadger = BADGER.balanceOf(address(this)); + require(totalBadger > 0); + + uint256 ops_fee = totalBadger * OPS_FEE / MAX_BPS; + IERC20(address(BADGER)).safeTransfer(TREASURY, ops_fee); - BADGER.safeApprove(address(HARVEST_FORWARDER), toEmitTotal); + uint256 toEmitTotal = totalBadger - ops_fee; + BADGER.safeIncreaseAllowance(address(HARVEST_FORWARDER), toEmitTotal); HARVEST_FORWARDER.distribute(address(BADGER), toEmitTotal, address(BVE_AURA)); emit BribeEmission(address(BADGER), address(BVE_AURA), toEmitTotal); From bf92959a02f767662e684cc5a5eccb1ab9fd216e Mon Sep 17 00:00:00 2001 From: Entreprenerd Date: Mon, 8 Aug 2022 18:03:55 +0200 Subject: [PATCH 09/17] chore: removed unused --- contracts/AuraBribesProcessor.sol | 2 -- 1 file changed, 2 deletions(-) diff --git a/contracts/AuraBribesProcessor.sol b/contracts/AuraBribesProcessor.sol index dadc6ae..884da85 100644 --- a/contracts/AuraBribesProcessor.sol +++ b/contracts/AuraBribesProcessor.sol @@ -56,8 +56,6 @@ contract AuraBribesProcessor is CowSwapSeller { IVault public constant BVE_AURA = IVault(0xBA485b556399123261a5F9c95d413B4f93107407); - IBalancerVault public constant BALANCER_VAULT = IBalancerVault(0xBA12222222228d8Ba445958a75a0704d566BF2C8); - // We send tokens to emit here IHarvestForwarder public constant HARVEST_FORWARDER = IHarvestForwarder(0xA84B663837D94ec41B0f99903f37e1d69af9Ed3E); From 44df0a4aa4c57e66b7d39eccd2577d3684b1d630 Mon Sep 17 00:00:00 2001 From: Entreprenerd Date: Mon, 8 Aug 2022 18:11:37 +0200 Subject: [PATCH 10/17] fix: test revert --- tests/aura_processor/test_real_life_revert.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/aura_processor/test_real_life_revert.py b/tests/aura_processor/test_real_life_revert.py index 9f0eaad..6dacb43 100644 --- a/tests/aura_processor/test_real_life_revert.py +++ b/tests/aura_processor/test_real_life_revert.py @@ -50,7 +50,7 @@ def test_compare_live_to_fix(reverting_contract, fixed_contract, manager, aura, assert aura_to_process > 0 - ops_fee = aura_to_process * fixed_contract.OPS_FEE() // (fixed_contract.MAX_BPS() - fixed_contract.BADGER_SHARE()) + ops_fee = aura_to_process * fixed_contract.OPS_FEE() // fixed_contract.MAX_BPS() expected_bve_aura_to_tree = (aura_to_process - ops_fee) * bve_sett.totalSupply() // bve_sett.balance() From 667f462b84ab475e52dba0f27c6e544d983b8ef0 Mon Sep 17 00:00:00 2001 From: Entreprenerd Date: Mon, 8 Aug 2022 18:32:32 +0200 Subject: [PATCH 11/17] fix: fee for Badger --- contracts/AuraBribesProcessor.sol | 1 + 1 file changed, 1 insertion(+) diff --git a/contracts/AuraBribesProcessor.sol b/contracts/AuraBribesProcessor.sol index 884da85..041409d 100644 --- a/contracts/AuraBribesProcessor.sol +++ b/contracts/AuraBribesProcessor.sol @@ -218,6 +218,7 @@ contract AuraBribesProcessor is CowSwapSeller { BADGER.safeIncreaseAllowance(address(HARVEST_FORWARDER), toEmitTotal); HARVEST_FORWARDER.distribute(address(BADGER), toEmitTotal, address(BVE_AURA)); + emit PerformanceFeeGovernance(address(BADGER), ops_fee); emit BribeEmission(address(BADGER), address(BVE_AURA), toEmitTotal); } From 2d1e0bede60b44c25abffc7faad2c0a6dd060a45 Mon Sep 17 00:00:00 2001 From: Entreprenerd Date: Mon, 8 Aug 2022 18:44:30 +0200 Subject: [PATCH 12/17] fix: remove needles cast --- contracts/AuraBribesProcessor.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/AuraBribesProcessor.sol b/contracts/AuraBribesProcessor.sol index 041409d..0a556b8 100644 --- a/contracts/AuraBribesProcessor.sol +++ b/contracts/AuraBribesProcessor.sol @@ -212,7 +212,7 @@ contract AuraBribesProcessor is CowSwapSeller { require(totalBadger > 0); uint256 ops_fee = totalBadger * OPS_FEE / MAX_BPS; - IERC20(address(BADGER)).safeTransfer(TREASURY, ops_fee); + BADGER.safeTransfer(TREASURY, ops_fee); uint256 toEmitTotal = totalBadger - ops_fee; BADGER.safeIncreaseAllowance(address(HARVEST_FORWARDER), toEmitTotal); From 33621f75885ebbec3e08a5b78aa11c9a8759d163 Mon Sep 17 00:00:00 2001 From: sajanrajdev Date: Mon, 8 Aug 2022 14:09:31 -0400 Subject: [PATCH 13/17] test: swap weth for graviaura --- .../aura_processor/test_swap_weth_badger_aura.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/tests/aura_processor/test_swap_weth_badger_aura.py b/tests/aura_processor/test_swap_weth_badger_aura.py index a015b27..85c8809 100644 --- a/tests/aura_processor/test_swap_weth_badger_aura.py +++ b/tests/aura_processor/test_swap_weth_badger_aura.py @@ -60,7 +60,7 @@ def test_swap_weth_for_badger_must_be_weth_badger(setup_aura_processor, weth, ba -### Swap Weth for AURA +### Swap Weth for AURA or graviAURA def test_swap_weth_for_aura(setup_aura_processor, weth, aura, manager, settlement): sell_amount = 100000000000000000000 @@ -74,7 +74,19 @@ def test_swap_weth_for_aura(setup_aura_processor, weth, aura, manager, settlemen assert settlement.preSignature(uid) > 0 -def test_swap_weth_for_aura_must_be_weth_aura(setup_aura_processor, weth, badger, usdc, aura, manager, settlement): +def test_swap_weth_for_graviaura(setup_aura_processor, weth, bve_aura, manager, settlement): + sell_amount = 10000000000000000000 # 10 wETH since there is lower liquidity for graviAURA (fails with 100 wETH) + + order_details = get_cowswap_order(setup_aura_processor, weth, bve_aura, sell_amount) + + data = order_details.order_data + uid = order_details.order_uid + + setup_aura_processor.swapWethForAURA(data, uid, {"from": manager}) + + assert settlement.preSignature(uid) > 0 + +def test_swap_weth_for_aura_must_be_weth_aura(setup_aura_processor, weth, badger, usdc, aura, manager): ## Fail if opposite swap sell_amount = 100000000000000000000 From eb1fabf26864966678862d8271e69603d96fa185 Mon Sep 17 00:00:00 2001 From: sajanrajdev Date: Mon, 8 Aug 2022 14:51:16 -0400 Subject: [PATCH 14/17] test: improved emit aura test --- helpers/utils.py | 9 ++++ tests/aura_processor/test_emit_aura.py | 73 ++++++++++++++++---------- 2 files changed, 53 insertions(+), 29 deletions(-) create mode 100644 helpers/utils.py diff --git a/helpers/utils.py b/helpers/utils.py new file mode 100644 index 0000000..6f334f0 --- /dev/null +++ b/helpers/utils.py @@ -0,0 +1,9 @@ + +# Assert approximate integer +def approx(actual, expected, percentage_threshold): + print(actual, expected, percentage_threshold) + diff = int(abs(actual - expected)) + # 0 diff should automtically be a match + if diff == 0: + return True + return diff < (actual * percentage_threshold // 100) \ No newline at end of file diff --git a/tests/aura_processor/test_emit_aura.py b/tests/aura_processor/test_emit_aura.py index 79d0731..964a665 100644 --- a/tests/aura_processor/test_emit_aura.py +++ b/tests/aura_processor/test_emit_aura.py @@ -1,5 +1,6 @@ import brownie -from brownie import * +from brownie import a +from helpers.utils import approx """ swapAuraToBveAuraAndEmit @@ -11,42 +12,56 @@ Emits event """ -def test_swap_aura_and_emit_with_swap(setup_aura_processor, manager, aura, bve_aura, make_aura_pool_profitable): - # Make pool swap more proftiable - - bve_balance_before = bve_aura.balanceOf(setup_aura_processor.BADGER_TREE()) - assert aura.balanceOf(setup_aura_processor) > 0 +OPS_FEE = 0.05 # Hardcoded in contract - tx = setup_aura_processor.swapAURATobveAURAAndEmit({"from": manager}) +def test_swap_aura_and_emit(setup_aura_processor, manager, aura, bve_aura): + bve_tree_balance_before = bve_aura.balanceOf(setup_aura_processor.BADGER_TREE()) + bve_processor_balance_before = bve_aura.balanceOf(setup_aura_processor.address) # There could be gravi beforehand + bve_treasury_balance_before = bve_aura.balanceOf(setup_aura_processor.TREASURY()) + assert aura.balanceOf(setup_aura_processor) > 0 bve_supply = bve_aura.totalSupply() - assert bve_aura.balanceOf(setup_aura_processor.BADGER_TREE()) > bve_balance_before - assert aura.balanceOf(setup_aura_processor.BADGER_TREE()) == 0 ## All aura has been emitted - - ## We did not increase supply because we bought instead of minting - assert bve_supply == bve_aura.totalSupply() - - - ## Reverts if called a second time + # Only manager can call with brownie.reverts(): - setup_aura_processor.swapAURATobveAURAAndEmit({"from": manager}) - + setup_aura_processor.swapAURATobveAURAAndEmit({"from": a[9]}) -def test_swap_aura_and_emit_with_deposit(setup_aura_processor, manager, aura, bve_aura, make_aura_pool_unprofitable): - # Make pool swap less profitable - bve_balance_before = bve_aura.balanceOf(setup_aura_processor.BADGER_TREE()) - assert aura.balanceOf(setup_aura_processor) > 0 - - bve_supply = bve_aura.totalSupply() - tx = setup_aura_processor.swapAURATobveAURAAndEmit({"from": manager}) - assert bve_aura.balanceOf(setup_aura_processor.BADGER_TREE()) > bve_balance_before - assert aura.balanceOf(setup_aura_processor.BADGER_TREE()) == 0 ## All aura has been emitted - - ## Because we deposited, totalSupply has increased - assert bve_aura.totalSupply() > bve_supply + assert bve_aura.balanceOf(setup_aura_processor.BADGER_TREE()) > bve_tree_balance_before + assert aura.balanceOf(setup_aura_processor.address) == 0 ## All aura has been emitted + + ## graviAURA supply increased due to deposit + graviaura_acquird = bve_aura.totalSupply() - bve_supply + graviaura_total = graviaura_acquird + bve_processor_balance_before + assert graviaura_acquird > 0 + + # Confirm math + ops_fee = int(graviaura_total) * OPS_FEE + # 1% approximation due to Brownie rounding + assert approx(ops_fee, bve_aura.balanceOf(setup_aura_processor.TREASURY()) - bve_treasury_balance_before, 1) + + to_emit = graviaura_total - ops_fee + + # Confirm events + # Tree Distribution + assert len(tx.events["TreeDistribution"]) == 1 + event = tx.events["TreeDistribution"][0] + assert event["token"] == bve_aura.address + assert approx(event["amount"], to_emit, 1) + assert event["beneficiary"] == bve_aura.address + + # Performance Fee Governance + assert len(tx.events["PerformanceFeeGovernance"]) == 1 + event = tx.events["PerformanceFeeGovernance"][0] + assert event["token"] == bve_aura.address + assert approx(event["amount"], ops_fee, 1) + + # BribesEmission + assert len(tx.events["BribeEmission"]) == 1 + event = tx.events["BribeEmission"][0] + assert event["token"] == bve_aura.address + assert approx(event["amount"], to_emit, 1) ## Reverts if called a second time with brownie.reverts(): From f1b900641545e56bcfd78689930082f07ae22756 Mon Sep 17 00:00:00 2001 From: sajanrajdev Date: Mon, 8 Aug 2022 15:41:52 -0400 Subject: [PATCH 15/17] test: improved emit badger test --- tests/aura_processor/test_emit_aura.py | 43 +++++++++++++++++++++++--- 1 file changed, 38 insertions(+), 5 deletions(-) diff --git a/tests/aura_processor/test_emit_aura.py b/tests/aura_processor/test_emit_aura.py index 964a665..734d54b 100644 --- a/tests/aura_processor/test_emit_aura.py +++ b/tests/aura_processor/test_emit_aura.py @@ -68,15 +68,48 @@ def test_swap_aura_and_emit(setup_aura_processor, manager, aura, bve_aura): setup_aura_processor.swapAURATobveAURAAndEmit({"from": manager}) -def test_emit_badger(setup_aura_processor, manager, badger): - badger_balance_before = badger.balanceOf(setup_aura_processor.BADGER_TREE()) - assert badger.balanceOf(setup_aura_processor) > 0 +def test_emit_badger(setup_aura_processor, manager, badger, bve_aura): + badger_tree_balance_before = badger.balanceOf(setup_aura_processor.BADGER_TREE()) + badger_processor_balance_before = badger.balanceOf(setup_aura_processor) + badger_treasury_balance_before = badger.balanceOf(setup_aura_processor.TREASURY()) + assert badger_processor_balance_before > 0 - setup_aura_processor.emitBadger({"from": manager}) + # Only manager can call + with brownie.reverts(): + setup_aura_processor.emitBadger({"from": a[9]}) + + tx = setup_aura_processor.emitBadger({"from": manager}) - assert badger.balanceOf(setup_aura_processor.BADGER_TREE()) > badger_balance_before + assert badger.balanceOf(setup_aura_processor.BADGER_TREE()) > badger_tree_balance_before assert badger.balanceOf(setup_aura_processor) == 0 ## All badger emitted + # Confirm math + ops_fee = int(badger_processor_balance_before) * OPS_FEE + # 1% approximation due to Brownie rounding + assert approx(ops_fee, badger.balanceOf(setup_aura_processor.TREASURY()) - badger_treasury_balance_before, 1) + + to_emit = badger_processor_balance_before - ops_fee + + # Confirm events + # Tree Distribution + assert len(tx.events["TreeDistribution"]) == 1 + event = tx.events["TreeDistribution"][0] + assert event["token"] == badger.address + assert approx(event["amount"], to_emit, 1) + assert event["beneficiary"] == bve_aura.address + + # Performance Fee Governance + assert len(tx.events["PerformanceFeeGovernance"]) == 1 + event = tx.events["PerformanceFeeGovernance"][0] + assert event["token"] == badger.address + assert approx(event["amount"], ops_fee, 1) + + # BribesEmission + assert len(tx.events["BribeEmission"]) == 1 + event = tx.events["BribeEmission"][0] + assert event["token"] == badger.address + assert approx(event["amount"], to_emit, 1) + ## Reverts if called a second time with brownie.reverts(): setup_aura_processor.emitBadger({"from": manager}) \ No newline at end of file From 870809cb3796492667ef45945653fa3b2e1fdee2 Mon Sep 17 00:00:00 2001 From: Alex The Entreprenerd Date: Wed, 10 Aug 2022 15:13:19 +0200 Subject: [PATCH 16/17] Update contracts/AuraBribesProcessor.sol Co-authored-by: Ayush Shukla --- contracts/AuraBribesProcessor.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/AuraBribesProcessor.sol b/contracts/AuraBribesProcessor.sol index 0a556b8..cae8abd 100644 --- a/contracts/AuraBribesProcessor.sol +++ b/contracts/AuraBribesProcessor.sol @@ -146,7 +146,7 @@ contract AuraBribesProcessor is CowSwapSeller { /// @dev /// Step 2.b /// Swap WETH -> graviAURA or WETH -> AURA - function swapWethForAURA(Data calldata orderData, bytes memory orderUid) external { + function swapWethForAuraOrBveAura(Data calldata orderData, bytes memory orderUid) external { require(orderData.sellToken == WETH); // Must Sell WETH require( orderData.buyToken == AURA || From 18f262f43beb156c79466c0e4d9e54a8f3174fc1 Mon Sep 17 00:00:00 2001 From: Entreprenerd Date: Wed, 10 Aug 2022 15:46:05 +0200 Subject: [PATCH 17/17] fix: back to old name --- contracts/AuraBribesProcessor.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/AuraBribesProcessor.sol b/contracts/AuraBribesProcessor.sol index cae8abd..0a556b8 100644 --- a/contracts/AuraBribesProcessor.sol +++ b/contracts/AuraBribesProcessor.sol @@ -146,7 +146,7 @@ contract AuraBribesProcessor is CowSwapSeller { /// @dev /// Step 2.b /// Swap WETH -> graviAURA or WETH -> AURA - function swapWethForAuraOrBveAura(Data calldata orderData, bytes memory orderUid) external { + function swapWethForAURA(Data calldata orderData, bytes memory orderUid) external { require(orderData.sellToken == WETH); // Must Sell WETH require( orderData.buyToken == AURA ||