From 1a8ad55caf329c0d76c95a7e7079dabb9d93589f Mon Sep 17 00:00:00 2001 From: bout3fiddy <11488427+bout3fiddy@users.noreply.github.com> Date: Tue, 20 Feb 2024 16:47:35 +0100 Subject: [PATCH] Add fixtures for mocks --- contracts/mocks/ERC20.vy | 74 +++++++++++++ contracts/mocks/ERC4626.vy | 99 ++++++++++++++++++ tests/fixtures/accounts.py | 10 ++ tests/fixtures/factories.py | 201 ++++++++++++++++++++++++++++++++++++ tests/fixtures/pools.py | 128 +++++++++++++++++++++++ tests/fixtures/tokens.py | 57 ++++++++++ 6 files changed, 569 insertions(+) create mode 100644 contracts/mocks/ERC20.vy create mode 100644 contracts/mocks/ERC4626.vy create mode 100644 tests/fixtures/pools.py create mode 100644 tests/fixtures/tokens.py diff --git a/contracts/mocks/ERC20.vy b/contracts/mocks/ERC20.vy new file mode 100644 index 0000000..614781e --- /dev/null +++ b/contracts/mocks/ERC20.vy @@ -0,0 +1,74 @@ +# pragma version 0.3.10 + +""" +@notice Mock ERC20 for testing +""" + + +event Transfer: + _from: indexed(address) + _to: indexed(address) + _value: uint256 + + +event Approval: + _owner: indexed(address) + _spender: indexed(address) + _value: uint256 + + +name: public(String[64]) +symbol: public(String[32]) +decimals: public(uint256) +balanceOf: public(HashMap[address, uint256]) +allowances: HashMap[address, HashMap[address, uint256]] +totalSupply: public(uint256) + +# asset type +asset_type: public(constant(uint8)) = 0 + + +@external +def __init__(_name: String[64], _symbol: String[32], _decimals: uint256): + self.name = _name + self.symbol = _symbol + self.decimals = _decimals + + +@external +@view +def allowance(_owner: address, _spender: address) -> uint256: + return self.allowances[_owner][_spender] + + +@external +def transfer(_to: address, _value: uint256) -> bool: + self.balanceOf[msg.sender] -= _value + self.balanceOf[_to] += _value + log Transfer(msg.sender, _to, _value) + return True + + +@external +def transferFrom(_from: address, _to: address, _value: uint256) -> bool: + self.balanceOf[_from] -= _value + self.balanceOf[_to] += _value + self.allowances[_from][msg.sender] -= _value + log Transfer(_from, _to, _value) + return True + + +@external +def approve(_spender: address, _value: uint256) -> bool: + self.allowances[msg.sender][_spender] = _value + log Approval(msg.sender, _spender, _value) + return True + + +@external +def _mint_for_testing(_target: address, _value: uint256) -> bool: + self.totalSupply += _value + self.balanceOf[_target] += _value + log Transfer(empty(address), _target, _value) + + return True diff --git a/contracts/mocks/ERC4626.vy b/contracts/mocks/ERC4626.vy new file mode 100644 index 0000000..6902595 --- /dev/null +++ b/contracts/mocks/ERC4626.vy @@ -0,0 +1,99 @@ +# pragma version 0.3.10 + +""" +@notice Mock ERC20 with oracle +@dev This is for testing only, it is NOT safe for use +""" + + +event Transfer: + _from: indexed(address) + _to: indexed(address) + _value: uint256 + + +event Approval: + _owner: indexed(address) + _spender: indexed(address) + _value: uint256 + + +name: public(String[64]) +symbol: public(String[32]) +decimals: public(uint256) +balanceOf: public(HashMap[address, uint256]) +allowances: HashMap[address, HashMap[address, uint256]] +totalSupply: public(uint256) + +exchange_rate: public(uint256) + +# asset type +asset_type: public(constant(uint8)) = 1 + + +@external +def __init__( + _name: String[64], + _symbol: String[32], + _decimals: uint256, + _exchange_rate: uint256 +): + + self.name = _name + self.symbol = _symbol + + assert _decimals == 18, "Decimals must be 18" + self.decimals = _decimals + self.exchange_rate = _exchange_rate + + +@external +@view +def allowance(_owner: address, _spender: address) -> uint256: + return self.allowances[_owner][_spender] + + +@external +def transfer(_to: address, _value: uint256) -> bool: + self.balanceOf[msg.sender] -= _value + self.balanceOf[_to] += _value + log Transfer(msg.sender, _to, _value) + return True + + +@external +def transferFrom(_from: address, _to: address, _value: uint256) -> bool: + self.balanceOf[_from] -= _value + self.balanceOf[_to] += _value + self.allowances[_from][msg.sender] -= _value + log Transfer(_from, _to, _value) + return True + + +@external +def approve(_spender: address, _value: uint256) -> bool: + self.allowances[msg.sender][_spender] = _value + log Approval(msg.sender, _spender, _value) + return True + + +@external +@view +def exchangeRate() -> uint256: + rate: uint256 = self.exchange_rate + return rate + + +@external +def set_exchange_rate(rate: uint256) -> bool: + self.exchange_rate = rate + return True + + +@external +def _mint_for_testing(_target: address, _value: uint256) -> bool: + self.totalSupply += _value + self.balanceOf[_target] += _value + log Transfer(empty(address), _target, _value) + + return True diff --git a/tests/fixtures/accounts.py b/tests/fixtures/accounts.py index 6dfef0e..5d05dcc 100644 --- a/tests/fixtures/accounts.py +++ b/tests/fixtures/accounts.py @@ -35,3 +35,13 @@ def owner(accounts): "AddressProvider", ADDRESS_PROVIDER ) return address_provider.admin() + + +@pytest.fixture(scope="module") +def ng_fee_receiver(): + return boa.env.generate_address() + + +@pytest.fixture(scope="module") +def ng_owner(): + return boa.env.generate_address() diff --git a/tests/fixtures/factories.py b/tests/fixtures/factories.py index e69de29..e8661b7 100644 --- a/tests/fixtures/factories.py +++ b/tests/fixtures/factories.py @@ -0,0 +1,201 @@ +import boa +import pytest + +# ---- Stableswap NG ---- # + + +@pytest.fixture() +def stableswap_ng_deployer(): + return boa.load_partial("contracts/amms/stableswapng/CurveStableSwapNG.vy") + + +@pytest.fixture() +def stableswap_ng_meta_deployer(): + return boa.load_partial( + "contracts/amms/stableswapng/CurveStableSwapMetaNG.vy" + ) + + +@pytest.fixture() +def stableswap_ng_implementation(stableswap_ng_deployer, deployer): + with boa.env.prank(deployer): + return stableswap_ng_deployer.deploy_as_blueprint() + + +@pytest.fixture() +def stableswap_ng_meta_implementation(stableswap_ng_meta_deployer, deployer): + with boa.env.prank(deployer): + return stableswap_ng_meta_deployer.deploy_as_blueprint() + + +@pytest.fixture() +def stableswap_ng_views_implementation(deployer): + with boa.env.prank(deployer): + return boa.load_partial( + "contracts/amms/stableswapng/CurveStableSwapNGViews.vy" + ).deploy() + + +@pytest.fixture() +def stableswap_ng_math_implementation(deployer): + with boa.env.prank(deployer): + return boa.load_partial( + "contracts/amms/stableswapng/CurveStableSwapNGMath.vy" + ).deploy() + + +@pytest.fixture() +def stableswap_ng_factory_empty( + deployer, + ng_fee_receiver, + ng_owner, + stableswap_ng_views_implementation, + stableswap_ng_math_implementation, + stableswap_ng_implementation, + stableswap_ng_meta_implementation, +): + with boa.env.prank(deployer): + factory = boa.load_partial( + "contracts/amms/stableswapng/CurveStableSwapFactoryNG.vy" + ).deploy(ng_fee_receiver, ng_owner) + + with boa.env.prank(ng_owner): + factory.set_views_implementation( + stableswap_ng_views_implementation.address + ) + factory.set_math_implementation( + stableswap_ng_math_implementation.address + ) + factory.set_pool_implementations( + 0, stableswap_ng_implementation.address + ) + factory.set_metapool_implementations( + 0, stableswap_ng_meta_implementation.address + ) + + return factory + + +@pytest.fixture() +def stableswap_ng_factory( + stableswap_ng_factory_empty, stableswap_ng_pool, base_pool_coins, ng_owner +): + stableswap_ng_factory_empty.add_base_pool( + stableswap_ng_pool.address, + stableswap_ng_pool.address, + [0] * len(base_pool_coins), + len(base_pool_coins), + sender=ng_owner, + ) + return stableswap_ng_factory_empty + + +# ---- Twocrypto NG ---- # + + +@pytest.fixture(scope="module") +def twocrypto_ng_math_contract(deployer): + with boa.env.prank(deployer): + return boa.load( + "contracts/amms/twocryptong/CurveCryptoMathOptimized2.vy" + ) + + +@pytest.fixture(scope="module") +def twocrypto_ng_amm_deployer(): + return boa.load_partial( + "contracts/amms/twocryptong/CurveTwocryptoOptimized.vy" + ) + + +@pytest.fixture(scope="module") +def twocrypto_ng_amm_implementation(deployer, twocrypto_ng_amm_deployer): + with boa.env.prank(deployer): + return twocrypto_ng_amm_deployer.deploy_as_blueprint() + + +@pytest.fixture(scope="module") +def twocrypto_ng_views_contract(deployer): + with boa.env.prank(deployer): + return boa.load( + "contracts/amms/twocryptong/CurveCryptoViews2Optimized.vy" + ) + + +@pytest.fixture(scope="module") +def twocrypto_ng_factory( + deployer, + ng_fee_receiver, + ng_owner, + twocrypto_ng_amm_implementation, + twocrypto_ng_math_contract, + twocrypto_ng_views_contract, +): + with boa.env.prank(deployer): + factory = boa.load( + "contracts/amms/twocryptong/CurveTwocryptoFactory.vy" + ) + factory.initialise_ownership(ng_fee_receiver, ng_owner) + + with boa.env.prank(ng_owner): + factory.set_pool_implementation(twocrypto_ng_amm_implementation, 0) + factory.set_views_implementation(twocrypto_ng_views_contract) + factory.set_math_implementation(twocrypto_ng_math_contract) + + return factory + + +# ---- Tricrypto NG ---- # + + +@pytest.fixture(scope="module") +def tricrypto_ng_math_contract(deployer): + with boa.env.prank(deployer): + return boa.load( + "contracts/amms/tricryptong/CurveCryptoMathOptimized3.vy" + ) + + +@pytest.fixture(scope="module") +def tricrypto_ng_amm_deployer(): + return boa.load_partial( + "contracts/amms/tricryptong/CurveTricryptoOptimized.vy" + ) + + +@pytest.fixture(scope="module") +def tricrypto_ng_amm_implementation(deployer, tricrypto_ng_amm_deployer): + with boa.env.prank(deployer): + return tricrypto_ng_amm_deployer.deploy_as_blueprint() + + +@pytest.fixture(scope="module") +def tricrypto_ng_views_contract(deployer): + with boa.env.prank(deployer): + return boa.load( + "contracts/amms/tricryptong/CurveCryptoViews3Optimized.vy" + ) + + +@pytest.fixture(scope="module") +def tricrypto_ng_factory( + deployer, + ng_fee_receiver, + ng_owner, + tricrypto_ng_amm_implementation, + tricrypto_ng_math_contract, + tricrypto_ng_views_contract, +): + with boa.env.prank(deployer): + factory = boa.load( + "contracts/amms/tricryptong/CurveTricryptoFactory.vy", + ng_fee_receiver, + ng_owner, + ) + + with boa.env.prank(ng_owner): + factory.set_pool_implementation(tricrypto_ng_amm_implementation, 0) + factory.set_views_implementation(tricrypto_ng_views_contract) + factory.set_math_implementation(tricrypto_ng_math_contract) + + return factory diff --git a/tests/fixtures/pools.py b/tests/fixtures/pools.py new file mode 100644 index 0000000..a2cf377 --- /dev/null +++ b/tests/fixtures/pools.py @@ -0,0 +1,128 @@ +import boa +import pytest +from eth.constants import ZERO_ADDRESS + + +@pytest.fixture() +def stableswap_ng_pool( + stableswap_ng_deployer, deployer, stableswap_ng_factory, base_pool_coins +): + pool_size = len(base_pool_coins) + A = 2000 + fee = 1000000 + method_ids = [b""] * pool_size + oracles = [ZERO_ADDRESS] * pool_size + A = 500 + fee = 4000000 + offpeg_fee_multiplier = 20000000000 + + with boa.env.prank(deployer): + ma_exp_time = 866 + implementation_idx = 0 + asset_types = [t.asset_type() for t in base_pool_coins] + coins = [t.address for t in base_pool_coins] + + pool = stableswap_ng_factory.deploy_plain_pool( + "ssng", + "ssng", + coins, + A, + fee, + offpeg_fee_multiplier, + ma_exp_time, + implementation_idx, + asset_types, + method_ids, + oracles, + ) + return stableswap_ng_deployer.at(pool) + + +@pytest.fixture() +def base_ng_pool(stableswap_ng_pool): + return stableswap_ng_pool + + +@pytest.fixture() +def stableswap_ng_metapool( + stableswap_ng_factory, stableswap_ng_meta_deployer, base_ng_pool, sdai +): + A = 2000 + fee = 1000000 + method_id = bytes(b"") + oracle = ZERO_ADDRESS + asset_type = 3 + A = 500 + fee = 4000000 + offpeg_fee_multiplier = 20000000000 + + pool = stableswap_ng_factory.deploy_metapool( + base_ng_pool.address, + "ssngmeta", + "ssngmeta", + sdai.address, + A, + fee, + offpeg_fee_multiplier, + 866, + 0, + asset_type, + method_id, + oracle, + ) + return stableswap_ng_meta_deployer.at(pool) + + +@pytest.fixture(scope="module") +def tricrypto_ng_pool( + tricrypto_ng_factory, + tricrypto_ng_amm_deployer, + tricrypto_ng_pool_coins, + deployer, +): + with boa.env.prank(deployer): + swap = tricrypto_ng_factory.deploy_pool( + "Curve.fi crvUSDC-BTC-ETH", + "tricryptoCRV", + [coin.address for coin in tricrypto_ng_pool_coins], + ZERO_ADDRESS, + 0, + 135 * 3**3 * 10000, + int(7e-5 * 1e18), + int(4e-4 * 1e10), + int(4e-3 * 1e10), + int(0.01 * 1e18), + 2 * 10**12, + int(0.0015 * 1e18), + 866, + [47500 * 10**18, 1500 * 10**18], + ) + + return tricrypto_ng_amm_deployer.at(swap) + + +@pytest.fixture() +def twocrypto_ng_pool( + twocrypto_ng_factory, + twocrypto_ng_amm_deployer, + twocrypto_ng_coins, + deployer, +): + with boa.env.prank(deployer): + swap = twocrypto_ng_factory.deploy_pool( + "Curve.fi crvUSD<>WETH", + "crvUSDWETH", + [coin.address for coin in twocrypto_ng_coins], + 0, + 400000, + 145000000000000, + 26000000, + 45000000, + 230000000000000, + 2000000000000, + 146000000000000, + 866, + 1777655918836068423, + ) + + return twocrypto_ng_amm_deployer.at(swap) diff --git a/tests/fixtures/tokens.py b/tests/fixtures/tokens.py new file mode 100644 index 0000000..cec1228 --- /dev/null +++ b/tests/fixtures/tokens.py @@ -0,0 +1,57 @@ +import boa +import pytest + + +@pytest.fixture(scope="session") +def erc20_deployer(): + return boa.load_partial("contracts/mocks/ERC20.vy") + + +@pytest.fixture(scope="session") +def erc4626_deployer(): + return boa.load_partial("contracts/mocks/ERC4626.vy") + + +@pytest.fixture() +def usdc(erc20_deployer): + return erc20_deployer.deploy("USDC", "USDC", 6) + + +@pytest.fixture() +def usdt(erc20_deployer): + return erc20_deployer.deploy("USDT", "USDT", 6) + + +@pytest.fixture() +def crvusd(erc20_deployer): + return erc20_deployer.deploy("crvUSD", "crvUSD", 18) + + +@pytest.fixture() +def sdai(erc4626): + return erc4626_deployer.deploy("sDAI", "sDAI", 18, 1056565529321686702) + + +@pytest.fixture() +def base_pool_coins(usdc, usdt, crvusd): + return [usdc, usdt, crvusd] + + +@pytest.fixture() +def tricrypto_ng_pool_coins(crvusd, wbtc, weth): + return [crvusd, wbtc, weth] + + +@pytest.fixture() +def twocrypto_ng_pool_coins(crvusd, weth): + return [crvusd, weth] + + +@pytest.fixture() +def weth(erc20_deployer): + return erc20_deployer.deploy("WETH", "WETH", 18) + + +@pytest.fixture() +def wbtc(erc20_deployer): + return erc20_deployer.deploy("WBTC", "WBTC", 8)