diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index b5cdca9..e97f134 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -26,7 +26,4 @@ jobs: - name: Run Tests run: pytest env: - ETHERSCAN_TOKEN: ${{ secrets.ETHERSKEM_TOKEN }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - WEB3_INFURA_PROJECT_ID: ${{ secrets.INFURA_TOKEN }} - WEB3_ALCHEMY_PROJECT_ID: ${{secrets.ALCHEMY_API_KEY}} + DRPC_KEY: ${{ secrets.DRPC_KEY }} diff --git a/.gitignore b/.gitignore index a70f6d3..500de94 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ __pycache__/ .DS_Store venv/ bvenv/ +.env \ No newline at end of file diff --git a/contracts/mainnet/MetaRegistry.vy b/contracts/mainnet/MetaRegistry.vy index f9f4ab0..71f4d0a 100644 --- a/contracts/mainnet/MetaRegistry.vy +++ b/contracts/mainnet/MetaRegistry.vy @@ -1,4 +1,4 @@ -# @version 0.3.7 +# @version 0.3.10 """ @title Curve Meta Registry @license MIT diff --git a/contracts/mainnet/abi/AddressProvider.json b/contracts/mainnet/abi/AddressProvider.json new file mode 100644 index 0000000..734cd08 --- /dev/null +++ b/contracts/mainnet/abi/AddressProvider.json @@ -0,0 +1,309 @@ +[ + { + "name": "NewAddressIdentifier", + "inputs": [ + { + "type": "uint256", + "name": "id", + "indexed": true + }, + { + "type": "address", + "name": "addr", + "indexed": false + }, + { + "type": "string", + "name": "description", + "indexed": false + } + ], + "anonymous": false, + "type": "event" + }, + { + "name": "AddressModified", + "inputs": [ + { + "type": "uint256", + "name": "id", + "indexed": true + }, + { + "type": "address", + "name": "new_address", + "indexed": false + }, + { + "type": "uint256", + "name": "version", + "indexed": false + } + ], + "anonymous": false, + "type": "event" + }, + { + "name": "CommitNewAdmin", + "inputs": [ + { + "type": "uint256", + "name": "deadline", + "indexed": true + }, + { + "type": "address", + "name": "admin", + "indexed": true + } + ], + "anonymous": false, + "type": "event" + }, + { + "name": "NewAdmin", + "inputs": [ + { + "type": "address", + "name": "admin", + "indexed": true + } + ], + "anonymous": false, + "type": "event" + }, + { + "outputs": [], + "inputs": [ + { + "type": "address", + "name": "_admin" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "name": "get_registry", + "outputs": [ + { + "type": "address", + "name": "" + } + ], + "inputs": [], + "stateMutability": "view", + "type": "function", + "gas": 1061 + }, + { + "name": "max_id", + "outputs": [ + { + "type": "uint256", + "name": "" + } + ], + "inputs": [], + "stateMutability": "view", + "type": "function", + "gas": 1258 + }, + { + "name": "get_address", + "outputs": [ + { + "type": "address", + "name": "" + } + ], + "inputs": [ + { + "type": "uint256", + "name": "_id" + } + ], + "stateMutability": "view", + "type": "function", + "gas": 1308 + }, + { + "name": "add_new_id", + "outputs": [ + { + "type": "uint256", + "name": "" + } + ], + "inputs": [ + { + "type": "address", + "name": "_address" + }, + { + "type": "string", + "name": "_description" + } + ], + "stateMutability": "nonpayable", + "type": "function", + "gas": 291275 + }, + { + "name": "set_address", + "outputs": [ + { + "type": "bool", + "name": "" + } + ], + "inputs": [ + { + "type": "uint256", + "name": "_id" + }, + { + "type": "address", + "name": "_address" + } + ], + "stateMutability": "nonpayable", + "type": "function", + "gas": 182430 + }, + { + "name": "unset_address", + "outputs": [ + { + "type": "bool", + "name": "" + } + ], + "inputs": [ + { + "type": "uint256", + "name": "_id" + } + ], + "stateMutability": "nonpayable", + "type": "function", + "gas": 101348 + }, + { + "name": "commit_transfer_ownership", + "outputs": [ + { + "type": "bool", + "name": "" + } + ], + "inputs": [ + { + "type": "address", + "name": "_new_admin" + } + ], + "stateMutability": "nonpayable", + "type": "function", + "gas": 74048 + }, + { + "name": "apply_transfer_ownership", + "outputs": [ + { + "type": "bool", + "name": "" + } + ], + "inputs": [], + "stateMutability": "nonpayable", + "type": "function", + "gas": 60125 + }, + { + "name": "revert_transfer_ownership", + "outputs": [ + { + "type": "bool", + "name": "" + } + ], + "inputs": [], + "stateMutability": "nonpayable", + "type": "function", + "gas": 21400 + }, + { + "name": "admin", + "outputs": [ + { + "type": "address", + "name": "" + } + ], + "inputs": [], + "stateMutability": "view", + "type": "function", + "gas": 1331 + }, + { + "name": "transfer_ownership_deadline", + "outputs": [ + { + "type": "uint256", + "name": "" + } + ], + "inputs": [], + "stateMutability": "view", + "type": "function", + "gas": 1361 + }, + { + "name": "future_admin", + "outputs": [ + { + "type": "address", + "name": "" + } + ], + "inputs": [], + "stateMutability": "view", + "type": "function", + "gas": 1391 + }, + { + "name": "get_id_info", + "outputs": [ + { + "type": "address", + "name": "addr" + }, + { + "type": "bool", + "name": "is_active" + }, + { + "type": "uint256", + "name": "version" + }, + { + "type": "uint256", + "name": "last_modified" + }, + { + "type": "string", + "name": "description" + } + ], + "inputs": [ + { + "type": "uint256", + "name": "arg0" + } + ], + "stateMutability": "view", + "type": "function", + "gas": 12168 + } +] \ No newline at end of file diff --git a/contracts/mainnet/abi/CryptoFactory.json b/contracts/mainnet/abi/CryptoFactory.json new file mode 100644 index 0000000..f8c5747 --- /dev/null +++ b/contracts/mainnet/abi/CryptoFactory.json @@ -0,0 +1,635 @@ +[ + { + "name": "CryptoPoolDeployed", + "inputs": [ + { + "name": "token", + "type": "address", + "indexed": false + }, + { + "name": "coins", + "type": "address[2]", + "indexed": false + }, + { + "name": "A", + "type": "uint256", + "indexed": false + }, + { + "name": "gamma", + "type": "uint256", + "indexed": false + }, + { + "name": "mid_fee", + "type": "uint256", + "indexed": false + }, + { + "name": "out_fee", + "type": "uint256", + "indexed": false + }, + { + "name": "allowed_extra_profit", + "type": "uint256", + "indexed": false + }, + { + "name": "fee_gamma", + "type": "uint256", + "indexed": false + }, + { + "name": "adjustment_step", + "type": "uint256", + "indexed": false + }, + { + "name": "admin_fee", + "type": "uint256", + "indexed": false + }, + { + "name": "ma_half_time", + "type": "uint256", + "indexed": false + }, + { + "name": "initial_price", + "type": "uint256", + "indexed": false + }, + { + "name": "deployer", + "type": "address", + "indexed": false + } + ], + "anonymous": false, + "type": "event" + }, + { + "name": "LiquidityGaugeDeployed", + "inputs": [ + { + "name": "pool", + "type": "address", + "indexed": false + }, + { + "name": "token", + "type": "address", + "indexed": false + }, + { + "name": "gauge", + "type": "address", + "indexed": false + } + ], + "anonymous": false, + "type": "event" + }, + { + "name": "UpdateFeeReceiver", + "inputs": [ + { + "name": "_old_fee_receiver", + "type": "address", + "indexed": false + }, + { + "name": "_new_fee_receiver", + "type": "address", + "indexed": false + } + ], + "anonymous": false, + "type": "event" + }, + { + "name": "UpdatePoolImplementation", + "inputs": [ + { + "name": "_old_pool_implementation", + "type": "address", + "indexed": false + }, + { + "name": "_new_pool_implementation", + "type": "address", + "indexed": false + } + ], + "anonymous": false, + "type": "event" + }, + { + "name": "UpdateTokenImplementation", + "inputs": [ + { + "name": "_old_token_implementation", + "type": "address", + "indexed": false + }, + { + "name": "_new_token_implementation", + "type": "address", + "indexed": false + } + ], + "anonymous": false, + "type": "event" + }, + { + "name": "UpdateGaugeImplementation", + "inputs": [ + { + "name": "_old_gauge_implementation", + "type": "address", + "indexed": false + }, + { + "name": "_new_gauge_implementation", + "type": "address", + "indexed": false + } + ], + "anonymous": false, + "type": "event" + }, + { + "name": "TransferOwnership", + "inputs": [ + { + "name": "_old_owner", + "type": "address", + "indexed": false + }, + { + "name": "_new_owner", + "type": "address", + "indexed": false + } + ], + "anonymous": false, + "type": "event" + }, + { + "stateMutability": "nonpayable", + "type": "constructor", + "inputs": [ + { + "name": "_fee_receiver", + "type": "address" + }, + { + "name": "_pool_implementation", + "type": "address" + }, + { + "name": "_token_implementation", + "type": "address" + }, + { + "name": "_gauge_implementation", + "type": "address" + }, + { + "name": "_weth", + "type": "address" + } + ], + "outputs": [] + }, + { + "stateMutability": "nonpayable", + "type": "function", + "name": "deploy_pool", + "inputs": [ + { + "name": "_name", + "type": "string" + }, + { + "name": "_symbol", + "type": "string" + }, + { + "name": "_coins", + "type": "address[2]" + }, + { + "name": "A", + "type": "uint256" + }, + { + "name": "gamma", + "type": "uint256" + }, + { + "name": "mid_fee", + "type": "uint256" + }, + { + "name": "out_fee", + "type": "uint256" + }, + { + "name": "allowed_extra_profit", + "type": "uint256" + }, + { + "name": "fee_gamma", + "type": "uint256" + }, + { + "name": "adjustment_step", + "type": "uint256" + }, + { + "name": "admin_fee", + "type": "uint256" + }, + { + "name": "ma_half_time", + "type": "uint256" + }, + { + "name": "initial_price", + "type": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "address" + } + ] + }, + { + "stateMutability": "nonpayable", + "type": "function", + "name": "deploy_gauge", + "inputs": [ + { + "name": "_pool", + "type": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "address" + } + ] + }, + { + "stateMutability": "nonpayable", + "type": "function", + "name": "set_fee_receiver", + "inputs": [ + { + "name": "_fee_receiver", + "type": "address" + } + ], + "outputs": [] + }, + { + "stateMutability": "nonpayable", + "type": "function", + "name": "set_pool_implementation", + "inputs": [ + { + "name": "_pool_implementation", + "type": "address" + } + ], + "outputs": [] + }, + { + "stateMutability": "nonpayable", + "type": "function", + "name": "set_token_implementation", + "inputs": [ + { + "name": "_token_implementation", + "type": "address" + } + ], + "outputs": [] + }, + { + "stateMutability": "nonpayable", + "type": "function", + "name": "set_gauge_implementation", + "inputs": [ + { + "name": "_gauge_implementation", + "type": "address" + } + ], + "outputs": [] + }, + { + "stateMutability": "nonpayable", + "type": "function", + "name": "commit_transfer_ownership", + "inputs": [ + { + "name": "_addr", + "type": "address" + } + ], + "outputs": [] + }, + { + "stateMutability": "nonpayable", + "type": "function", + "name": "accept_transfer_ownership", + "inputs": [], + "outputs": [] + }, + { + "stateMutability": "view", + "type": "function", + "name": "find_pool_for_coins", + "inputs": [ + { + "name": "_from", + "type": "address" + }, + { + "name": "_to", + "type": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "address" + } + ] + }, + { + "stateMutability": "view", + "type": "function", + "name": "find_pool_for_coins", + "inputs": [ + { + "name": "_from", + "type": "address" + }, + { + "name": "_to", + "type": "address" + }, + { + "name": "i", + "type": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "address" + } + ] + }, + { + "stateMutability": "view", + "type": "function", + "name": "get_coins", + "inputs": [ + { + "name": "_pool", + "type": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "address[2]" + } + ] + }, + { + "stateMutability": "view", + "type": "function", + "name": "get_decimals", + "inputs": [ + { + "name": "_pool", + "type": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256[2]" + } + ] + }, + { + "stateMutability": "view", + "type": "function", + "name": "get_balances", + "inputs": [ + { + "name": "_pool", + "type": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256[2]" + } + ] + }, + { + "stateMutability": "view", + "type": "function", + "name": "get_coin_indices", + "inputs": [ + { + "name": "_pool", + "type": "address" + }, + { + "name": "_from", + "type": "address" + }, + { + "name": "_to", + "type": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ] + }, + { + "stateMutability": "view", + "type": "function", + "name": "get_gauge", + "inputs": [ + { + "name": "_pool", + "type": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "address" + } + ] + }, + { + "stateMutability": "view", + "type": "function", + "name": "get_eth_index", + "inputs": [ + { + "name": "_pool", + "type": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256" + } + ] + }, + { + "stateMutability": "view", + "type": "function", + "name": "get_token", + "inputs": [ + { + "name": "_pool", + "type": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "address" + } + ] + }, + { + "stateMutability": "view", + "type": "function", + "name": "admin", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address" + } + ] + }, + { + "stateMutability": "view", + "type": "function", + "name": "future_admin", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address" + } + ] + }, + { + "stateMutability": "view", + "type": "function", + "name": "fee_receiver", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address" + } + ] + }, + { + "stateMutability": "view", + "type": "function", + "name": "pool_implementation", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address" + } + ] + }, + { + "stateMutability": "view", + "type": "function", + "name": "token_implementation", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address" + } + ] + }, + { + "stateMutability": "view", + "type": "function", + "name": "gauge_implementation", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address" + } + ] + }, + { + "stateMutability": "view", + "type": "function", + "name": "pool_count", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint256" + } + ] + }, + { + "stateMutability": "view", + "type": "function", + "name": "pool_list", + "inputs": [ + { + "name": "arg0", + "type": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "address" + } + ] + } +] \ No newline at end of file diff --git a/contracts/mainnet/abi/CryptoRegistry.json b/contracts/mainnet/abi/CryptoRegistry.json new file mode 100644 index 0000000..486ef19 --- /dev/null +++ b/contracts/mainnet/abi/CryptoRegistry.json @@ -0,0 +1,601 @@ +[ + { + "name": "PoolAdded", + "inputs": [ + { + "name": "pool", + "type": "address", + "indexed": true + } + ], + "anonymous": false, + "type": "event" + }, + { + "name": "PoolRemoved", + "inputs": [ + { + "name": "pool", + "type": "address", + "indexed": true + } + ], + "anonymous": false, + "type": "event" + }, + { + "stateMutability": "nonpayable", + "type": "constructor", + "inputs": [ + { + "name": "_address_provider", + "type": "address" + } + ], + "outputs": [] + }, + { + "stateMutability": "view", + "type": "function", + "name": "find_pool_for_coins", + "inputs": [ + { + "name": "_from", + "type": "address" + }, + { + "name": "_to", + "type": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "gas": 3111 + }, + { + "stateMutability": "view", + "type": "function", + "name": "find_pool_for_coins", + "inputs": [ + { + "name": "_from", + "type": "address" + }, + { + "name": "_to", + "type": "address" + }, + { + "name": "i", + "type": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "gas": 3111 + }, + { + "stateMutability": "view", + "type": "function", + "name": "get_n_coins", + "inputs": [ + { + "name": "_pool", + "type": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "gas": 2834 + }, + { + "stateMutability": "view", + "type": "function", + "name": "get_coins", + "inputs": [ + { + "name": "_pool", + "type": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "address[8]" + } + ], + "gas": 22975 + }, + { + "stateMutability": "view", + "type": "function", + "name": "get_decimals", + "inputs": [ + { + "name": "_pool", + "type": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256[8]" + } + ], + "gas": 9818 + }, + { + "stateMutability": "view", + "type": "function", + "name": "get_gauges", + "inputs": [ + { + "name": "_pool", + "type": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "address[10]" + }, + { + "name": "", + "type": "int128[10]" + } + ], + "gas": 26055 + }, + { + "stateMutability": "view", + "type": "function", + "name": "get_balances", + "inputs": [ + { + "name": "_pool", + "type": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256[8]" + } + ], + "gas": 41626 + }, + { + "stateMutability": "view", + "type": "function", + "name": "get_virtual_price_from_lp_token", + "inputs": [ + { + "name": "_token", + "type": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "gas": 5321 + }, + { + "stateMutability": "view", + "type": "function", + "name": "get_A", + "inputs": [ + { + "name": "_pool", + "type": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "gas": 3139 + }, + { + "stateMutability": "view", + "type": "function", + "name": "get_D", + "inputs": [ + { + "name": "_pool", + "type": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "gas": 3169 + }, + { + "stateMutability": "view", + "type": "function", + "name": "get_gamma", + "inputs": [ + { + "name": "_pool", + "type": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "gas": 3199 + }, + { + "stateMutability": "view", + "type": "function", + "name": "get_fees", + "inputs": [ + { + "name": "_pool", + "type": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256[4]" + } + ], + "gas": 10333 + }, + { + "stateMutability": "view", + "type": "function", + "name": "get_admin_balances", + "inputs": [ + { + "name": "_pool", + "type": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256[8]" + } + ], + "gas": 85771 + }, + { + "stateMutability": "view", + "type": "function", + "name": "get_coin_indices", + "inputs": [ + { + "name": "_pool", + "type": "address" + }, + { + "name": "_from", + "type": "address" + }, + { + "name": "_to", + "type": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "gas": 23608 + }, + { + "stateMutability": "view", + "type": "function", + "name": "get_pool_name", + "inputs": [ + { + "name": "_pool", + "type": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "gas": 13576 + }, + { + "stateMutability": "view", + "type": "function", + "name": "get_coin_swap_count", + "inputs": [ + { + "name": "_coin", + "type": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "gas": 3224 + }, + { + "stateMutability": "view", + "type": "function", + "name": "get_coin_swap_complement", + "inputs": [ + { + "name": "_coin", + "type": "address" + }, + { + "name": "_index", + "type": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "gas": 3299 + }, + { + "stateMutability": "nonpayable", + "type": "function", + "name": "add_pool", + "inputs": [ + { + "name": "_pool", + "type": "address" + }, + { + "name": "_n_coins", + "type": "uint256" + }, + { + "name": "_lp_token", + "type": "address" + }, + { + "name": "_gauge", + "type": "address" + }, + { + "name": "_zap", + "type": "address" + }, + { + "name": "_decimals", + "type": "uint256" + }, + { + "name": "_name", + "type": "string" + } + ], + "outputs": [], + "gas": 18586944 + }, + { + "stateMutability": "nonpayable", + "type": "function", + "name": "remove_pool", + "inputs": [ + { + "name": "_pool", + "type": "address" + } + ], + "outputs": [], + "gas": 399675363514 + }, + { + "stateMutability": "nonpayable", + "type": "function", + "name": "set_liquidity_gauges", + "inputs": [ + { + "name": "_pool", + "type": "address" + }, + { + "name": "_liquidity_gauges", + "type": "address[10]" + } + ], + "outputs": [], + "gas": 422284 + }, + { + "stateMutability": "nonpayable", + "type": "function", + "name": "batch_set_liquidity_gauges", + "inputs": [ + { + "name": "_pools", + "type": "address[10]" + }, + { + "name": "_liquidity_gauges", + "type": "address[10]" + } + ], + "outputs": [], + "gas": 444084 + }, + { + "stateMutability": "view", + "type": "function", + "name": "address_provider", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "gas": 3126 + }, + { + "stateMutability": "view", + "type": "function", + "name": "pool_list", + "inputs": [ + { + "name": "arg0", + "type": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "gas": 3201 + }, + { + "stateMutability": "view", + "type": "function", + "name": "pool_count", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "gas": 3186 + }, + { + "stateMutability": "view", + "type": "function", + "name": "coin_count", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "gas": 3216 + }, + { + "stateMutability": "view", + "type": "function", + "name": "get_coin", + "inputs": [ + { + "name": "arg0", + "type": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "gas": 3291 + }, + { + "stateMutability": "view", + "type": "function", + "name": "get_pool_from_lp_token", + "inputs": [ + { + "name": "arg0", + "type": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "gas": 3548 + }, + { + "stateMutability": "view", + "type": "function", + "name": "get_lp_token", + "inputs": [ + { + "name": "arg0", + "type": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "gas": 3578 + }, + { + "stateMutability": "view", + "type": "function", + "name": "get_zap", + "inputs": [ + { + "name": "arg0", + "type": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "gas": 3608 + }, + { + "stateMutability": "view", + "type": "function", + "name": "last_updated", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "gas": 3366 + } +] \ No newline at end of file diff --git a/contracts/mainnet/abi/GaugeController.json b/contracts/mainnet/abi/GaugeController.json new file mode 100644 index 0000000..12179c6 --- /dev/null +++ b/contracts/mainnet/abi/GaugeController.json @@ -0,0 +1,822 @@ +[ + { + "name": "CommitOwnership", + "inputs": [ + { + "type": "address", + "name": "admin", + "indexed": false + } + ], + "anonymous": false, + "type": "event" + }, + { + "name": "ApplyOwnership", + "inputs": [ + { + "type": "address", + "name": "admin", + "indexed": false + } + ], + "anonymous": false, + "type": "event" + }, + { + "name": "AddType", + "inputs": [ + { + "type": "string", + "name": "name", + "indexed": false + }, + { + "type": "int128", + "name": "type_id", + "indexed": false + } + ], + "anonymous": false, + "type": "event" + }, + { + "name": "NewTypeWeight", + "inputs": [ + { + "type": "int128", + "name": "type_id", + "indexed": false + }, + { + "type": "uint256", + "name": "time", + "indexed": false + }, + { + "type": "uint256", + "name": "weight", + "indexed": false + }, + { + "type": "uint256", + "name": "total_weight", + "indexed": false + } + ], + "anonymous": false, + "type": "event" + }, + { + "name": "NewGaugeWeight", + "inputs": [ + { + "type": "address", + "name": "gauge_address", + "indexed": false + }, + { + "type": "uint256", + "name": "time", + "indexed": false + }, + { + "type": "uint256", + "name": "weight", + "indexed": false + }, + { + "type": "uint256", + "name": "total_weight", + "indexed": false + } + ], + "anonymous": false, + "type": "event" + }, + { + "name": "VoteForGauge", + "inputs": [ + { + "type": "uint256", + "name": "time", + "indexed": false + }, + { + "type": "address", + "name": "user", + "indexed": false + }, + { + "type": "address", + "name": "gauge_addr", + "indexed": false + }, + { + "type": "uint256", + "name": "weight", + "indexed": false + } + ], + "anonymous": false, + "type": "event" + }, + { + "name": "NewGauge", + "inputs": [ + { + "type": "address", + "name": "addr", + "indexed": false + }, + { + "type": "int128", + "name": "gauge_type", + "indexed": false + }, + { + "type": "uint256", + "name": "weight", + "indexed": false + } + ], + "anonymous": false, + "type": "event" + }, + { + "outputs": [], + "inputs": [ + { + "type": "address", + "name": "_token" + }, + { + "type": "address", + "name": "_voting_escrow" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "name": "commit_transfer_ownership", + "outputs": [], + "inputs": [ + { + "type": "address", + "name": "addr" + } + ], + "stateMutability": "nonpayable", + "type": "function", + "gas": 37597 + }, + { + "name": "apply_transfer_ownership", + "outputs": [], + "inputs": [], + "stateMutability": "nonpayable", + "type": "function", + "gas": 38497 + }, + { + "name": "gauge_types", + "outputs": [ + { + "type": "int128", + "name": "" + } + ], + "inputs": [ + { + "type": "address", + "name": "_addr" + } + ], + "stateMutability": "view", + "type": "function", + "gas": 1625 + }, + { + "name": "add_gauge", + "outputs": [], + "inputs": [ + { + "type": "address", + "name": "addr" + }, + { + "type": "int128", + "name": "gauge_type" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "name": "add_gauge", + "outputs": [], + "inputs": [ + { + "type": "address", + "name": "addr" + }, + { + "type": "int128", + "name": "gauge_type" + }, + { + "type": "uint256", + "name": "weight" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "name": "checkpoint", + "outputs": [], + "inputs": [], + "stateMutability": "nonpayable", + "type": "function", + "gas": 18033784416 + }, + { + "name": "checkpoint_gauge", + "outputs": [], + "inputs": [ + { + "type": "address", + "name": "addr" + } + ], + "stateMutability": "nonpayable", + "type": "function", + "gas": 18087678795 + }, + { + "name": "gauge_relative_weight", + "outputs": [ + { + "type": "uint256", + "name": "" + } + ], + "inputs": [ + { + "type": "address", + "name": "addr" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "name": "gauge_relative_weight", + "outputs": [ + { + "type": "uint256", + "name": "" + } + ], + "inputs": [ + { + "type": "address", + "name": "addr" + }, + { + "type": "uint256", + "name": "time" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "name": "gauge_relative_weight_write", + "outputs": [ + { + "type": "uint256", + "name": "" + } + ], + "inputs": [ + { + "type": "address", + "name": "addr" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "name": "gauge_relative_weight_write", + "outputs": [ + { + "type": "uint256", + "name": "" + } + ], + "inputs": [ + { + "type": "address", + "name": "addr" + }, + { + "type": "uint256", + "name": "time" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "name": "add_type", + "outputs": [], + "inputs": [ + { + "type": "string", + "name": "_name" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "name": "add_type", + "outputs": [], + "inputs": [ + { + "type": "string", + "name": "_name" + }, + { + "type": "uint256", + "name": "weight" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "name": "change_type_weight", + "outputs": [], + "inputs": [ + { + "type": "int128", + "name": "type_id" + }, + { + "type": "uint256", + "name": "weight" + } + ], + "stateMutability": "nonpayable", + "type": "function", + "gas": 36246310050 + }, + { + "name": "change_gauge_weight", + "outputs": [], + "inputs": [ + { + "type": "address", + "name": "addr" + }, + { + "type": "uint256", + "name": "weight" + } + ], + "stateMutability": "nonpayable", + "type": "function", + "gas": 36354170809 + }, + { + "name": "vote_for_gauge_weights", + "outputs": [], + "inputs": [ + { + "type": "address", + "name": "_gauge_addr" + }, + { + "type": "uint256", + "name": "_user_weight" + } + ], + "stateMutability": "nonpayable", + "type": "function", + "gas": 18142052127 + }, + { + "name": "get_gauge_weight", + "outputs": [ + { + "type": "uint256", + "name": "" + } + ], + "inputs": [ + { + "type": "address", + "name": "addr" + } + ], + "stateMutability": "view", + "type": "function", + "gas": 2974 + }, + { + "name": "get_type_weight", + "outputs": [ + { + "type": "uint256", + "name": "" + } + ], + "inputs": [ + { + "type": "int128", + "name": "type_id" + } + ], + "stateMutability": "view", + "type": "function", + "gas": 2977 + }, + { + "name": "get_total_weight", + "outputs": [ + { + "type": "uint256", + "name": "" + } + ], + "inputs": [], + "stateMutability": "view", + "type": "function", + "gas": 2693 + }, + { + "name": "get_weights_sum_per_type", + "outputs": [ + { + "type": "uint256", + "name": "" + } + ], + "inputs": [ + { + "type": "int128", + "name": "type_id" + } + ], + "stateMutability": "view", + "type": "function", + "gas": 3109 + }, + { + "name": "admin", + "outputs": [ + { + "type": "address", + "name": "" + } + ], + "inputs": [], + "stateMutability": "view", + "type": "function", + "gas": 1841 + }, + { + "name": "future_admin", + "outputs": [ + { + "type": "address", + "name": "" + } + ], + "inputs": [], + "stateMutability": "view", + "type": "function", + "gas": 1871 + }, + { + "name": "token", + "outputs": [ + { + "type": "address", + "name": "" + } + ], + "inputs": [], + "stateMutability": "view", + "type": "function", + "gas": 1901 + }, + { + "name": "voting_escrow", + "outputs": [ + { + "type": "address", + "name": "" + } + ], + "inputs": [], + "stateMutability": "view", + "type": "function", + "gas": 1931 + }, + { + "name": "n_gauge_types", + "outputs": [ + { + "type": "int128", + "name": "" + } + ], + "inputs": [], + "stateMutability": "view", + "type": "function", + "gas": 1961 + }, + { + "name": "n_gauges", + "outputs": [ + { + "type": "int128", + "name": "" + } + ], + "inputs": [], + "stateMutability": "view", + "type": "function", + "gas": 1991 + }, + { + "name": "gauge_type_names", + "outputs": [ + { + "type": "string", + "name": "" + } + ], + "inputs": [ + { + "type": "int128", + "name": "arg0" + } + ], + "stateMutability": "view", + "type": "function", + "gas": 8628 + }, + { + "name": "gauges", + "outputs": [ + { + "type": "address", + "name": "" + } + ], + "inputs": [ + { + "type": "uint256", + "name": "arg0" + } + ], + "stateMutability": "view", + "type": "function", + "gas": 2160 + }, + { + "name": "vote_user_slopes", + "outputs": [ + { + "type": "uint256", + "name": "slope" + }, + { + "type": "uint256", + "name": "power" + }, + { + "type": "uint256", + "name": "end" + } + ], + "inputs": [ + { + "type": "address", + "name": "arg0" + }, + { + "type": "address", + "name": "arg1" + } + ], + "stateMutability": "view", + "type": "function", + "gas": 5020 + }, + { + "name": "vote_user_power", + "outputs": [ + { + "type": "uint256", + "name": "" + } + ], + "inputs": [ + { + "type": "address", + "name": "arg0" + } + ], + "stateMutability": "view", + "type": "function", + "gas": 2265 + }, + { + "name": "last_user_vote", + "outputs": [ + { + "type": "uint256", + "name": "" + } + ], + "inputs": [ + { + "type": "address", + "name": "arg0" + }, + { + "type": "address", + "name": "arg1" + } + ], + "stateMutability": "view", + "type": "function", + "gas": 2449 + }, + { + "name": "points_weight", + "outputs": [ + { + "type": "uint256", + "name": "bias" + }, + { + "type": "uint256", + "name": "slope" + } + ], + "inputs": [ + { + "type": "address", + "name": "arg0" + }, + { + "type": "uint256", + "name": "arg1" + } + ], + "stateMutability": "view", + "type": "function", + "gas": 3859 + }, + { + "name": "time_weight", + "outputs": [ + { + "type": "uint256", + "name": "" + } + ], + "inputs": [ + { + "type": "address", + "name": "arg0" + } + ], + "stateMutability": "view", + "type": "function", + "gas": 2355 + }, + { + "name": "points_sum", + "outputs": [ + { + "type": "uint256", + "name": "bias" + }, + { + "type": "uint256", + "name": "slope" + } + ], + "inputs": [ + { + "type": "int128", + "name": "arg0" + }, + { + "type": "uint256", + "name": "arg1" + } + ], + "stateMutability": "view", + "type": "function", + "gas": 3970 + }, + { + "name": "time_sum", + "outputs": [ + { + "type": "uint256", + "name": "" + } + ], + "inputs": [ + { + "type": "uint256", + "name": "arg0" + } + ], + "stateMutability": "view", + "type": "function", + "gas": 2370 + }, + { + "name": "points_total", + "outputs": [ + { + "type": "uint256", + "name": "" + } + ], + "inputs": [ + { + "type": "uint256", + "name": "arg0" + } + ], + "stateMutability": "view", + "type": "function", + "gas": 2406 + }, + { + "name": "time_total", + "outputs": [ + { + "type": "uint256", + "name": "" + } + ], + "inputs": [], + "stateMutability": "view", + "type": "function", + "gas": 2321 + }, + { + "name": "points_type_weight", + "outputs": [ + { + "type": "uint256", + "name": "" + } + ], + "inputs": [ + { + "type": "int128", + "name": "arg0" + }, + { + "type": "uint256", + "name": "arg1" + } + ], + "stateMutability": "view", + "type": "function", + "gas": 2671 + }, + { + "name": "time_type_weight", + "outputs": [ + { + "type": "uint256", + "name": "" + } + ], + "inputs": [ + { + "type": "uint256", + "name": "arg0" + } + ], + "stateMutability": "view", + "type": "function", + "gas": 2490 + } +] \ No newline at end of file diff --git a/contracts/mainnet/abi/ProxyAdmin.json b/contracts/mainnet/abi/ProxyAdmin.json new file mode 100644 index 0000000..d4bc6c0 --- /dev/null +++ b/contracts/mainnet/abi/ProxyAdmin.json @@ -0,0 +1,204 @@ +[ + { + "name": "TransactionExecuted", + "inputs": [ + { + "name": "admin", + "type": "address", + "indexed": true + }, + { + "name": "target", + "type": "address", + "indexed": true + }, + { + "name": "calldata", + "type": "bytes", + "indexed": false + }, + { + "name": "value", + "type": "uint256", + "indexed": false + } + ], + "anonymous": false, + "type": "event" + }, + { + "name": "RequestAdminChange", + "inputs": [ + { + "name": "current_admin", + "type": "address", + "indexed": false + }, + { + "name": "future_admin", + "type": "address", + "indexed": false + } + ], + "anonymous": false, + "type": "event" + }, + { + "name": "RevokeAdminChange", + "inputs": [ + { + "name": "current_admin", + "type": "address", + "indexed": false + }, + { + "name": "future_admin", + "type": "address", + "indexed": false + }, + { + "name": "calling_admin", + "type": "address", + "indexed": false + } + ], + "anonymous": false, + "type": "event" + }, + { + "name": "ApproveAdminChange", + "inputs": [ + { + "name": "current_admin", + "type": "address", + "indexed": false + }, + { + "name": "future_admin", + "type": "address", + "indexed": false + }, + { + "name": "calling_admin", + "type": "address", + "indexed": false + } + ], + "anonymous": false, + "type": "event" + }, + { + "name": "AcceptAdminChange", + "inputs": [ + { + "name": "previous_admin", + "type": "address", + "indexed": false + }, + { + "name": "current_admin", + "type": "address", + "indexed": false + } + ], + "anonymous": false, + "type": "event" + }, + { + "stateMutability": "nonpayable", + "type": "constructor", + "inputs": [ + { + "name": "_authorized", + "type": "address[2]" + } + ], + "outputs": [] + }, + { + "stateMutability": "payable", + "type": "function", + "name": "execute", + "inputs": [ + { + "name": "_target", + "type": "address" + }, + { + "name": "_calldata", + "type": "bytes" + } + ], + "outputs": [] + }, + { + "stateMutability": "view", + "type": "function", + "name": "get_admin_change_status", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address" + }, + { + "name": "", + "type": "address" + }, + { + "name": "", + "type": "bool" + } + ] + }, + { + "stateMutability": "nonpayable", + "type": "function", + "name": "request_admin_change", + "inputs": [ + { + "name": "_new_admin", + "type": "address" + } + ], + "outputs": [] + }, + { + "stateMutability": "nonpayable", + "type": "function", + "name": "approve_admin_change", + "inputs": [], + "outputs": [] + }, + { + "stateMutability": "nonpayable", + "type": "function", + "name": "revoke_admin_change", + "inputs": [], + "outputs": [] + }, + { + "stateMutability": "nonpayable", + "type": "function", + "name": "accept_admin_change", + "inputs": [], + "outputs": [] + }, + { + "stateMutability": "view", + "type": "function", + "name": "admins", + "inputs": [ + { + "name": "arg0", + "type": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "address" + } + ] + } +] \ No newline at end of file diff --git a/contracts/mainnet/abi/StableFactory.json b/contracts/mainnet/abi/StableFactory.json new file mode 100644 index 0000000..d6697ca --- /dev/null +++ b/contracts/mainnet/abi/StableFactory.json @@ -0,0 +1,1063 @@ +[ + { + "name": "BasePoolAdded", + "inputs": [ + { + "name": "base_pool", + "type": "address", + "indexed": false + } + ], + "anonymous": false, + "type": "event" + }, + { + "name": "PlainPoolDeployed", + "inputs": [ + { + "name": "coins", + "type": "address[4]", + "indexed": false + }, + { + "name": "A", + "type": "uint256", + "indexed": false + }, + { + "name": "fee", + "type": "uint256", + "indexed": false + }, + { + "name": "deployer", + "type": "address", + "indexed": false + } + ], + "anonymous": false, + "type": "event" + }, + { + "name": "MetaPoolDeployed", + "inputs": [ + { + "name": "coin", + "type": "address", + "indexed": false + }, + { + "name": "base_pool", + "type": "address", + "indexed": false + }, + { + "name": "A", + "type": "uint256", + "indexed": false + }, + { + "name": "fee", + "type": "uint256", + "indexed": false + }, + { + "name": "deployer", + "type": "address", + "indexed": false + } + ], + "anonymous": false, + "type": "event" + }, + { + "name": "LiquidityGaugeDeployed", + "inputs": [ + { + "name": "pool", + "type": "address", + "indexed": false + }, + { + "name": "gauge", + "type": "address", + "indexed": false + } + ], + "anonymous": false, + "type": "event" + }, + { + "stateMutability": "nonpayable", + "type": "constructor", + "inputs": [ + { + "name": "_fee_receiver", + "type": "address" + } + ], + "outputs": [] + }, + { + "stateMutability": "view", + "type": "function", + "name": "metapool_implementations", + "inputs": [ + { + "name": "_base_pool", + "type": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "address[10]" + } + ], + "gas": 21716 + }, + { + "stateMutability": "view", + "type": "function", + "name": "find_pool_for_coins", + "inputs": [ + { + "name": "_from", + "type": "address" + }, + { + "name": "_to", + "type": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "address" + } + ] + }, + { + "stateMutability": "view", + "type": "function", + "name": "find_pool_for_coins", + "inputs": [ + { + "name": "_from", + "type": "address" + }, + { + "name": "_to", + "type": "address" + }, + { + "name": "i", + "type": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "address" + } + ] + }, + { + "stateMutability": "view", + "type": "function", + "name": "get_base_pool", + "inputs": [ + { + "name": "_pool", + "type": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "gas": 2663 + }, + { + "stateMutability": "view", + "type": "function", + "name": "get_n_coins", + "inputs": [ + { + "name": "_pool", + "type": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "gas": 2699 + }, + { + "stateMutability": "view", + "type": "function", + "name": "get_meta_n_coins", + "inputs": [ + { + "name": "_pool", + "type": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "gas": 5201 + }, + { + "stateMutability": "view", + "type": "function", + "name": "get_coins", + "inputs": [ + { + "name": "_pool", + "type": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "address[4]" + } + ], + "gas": 9164 + }, + { + "stateMutability": "view", + "type": "function", + "name": "get_underlying_coins", + "inputs": [ + { + "name": "_pool", + "type": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "address[8]" + } + ], + "gas": 21345 + }, + { + "stateMutability": "view", + "type": "function", + "name": "get_decimals", + "inputs": [ + { + "name": "_pool", + "type": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256[4]" + } + ], + "gas": 20185 + }, + { + "stateMutability": "view", + "type": "function", + "name": "get_underlying_decimals", + "inputs": [ + { + "name": "_pool", + "type": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256[8]" + } + ], + "gas": 19730 + }, + { + "stateMutability": "view", + "type": "function", + "name": "get_metapool_rates", + "inputs": [ + { + "name": "_pool", + "type": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256[2]" + } + ], + "gas": 5281 + }, + { + "stateMutability": "view", + "type": "function", + "name": "get_balances", + "inputs": [ + { + "name": "_pool", + "type": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256[4]" + } + ], + "gas": 20435 + }, + { + "stateMutability": "view", + "type": "function", + "name": "get_underlying_balances", + "inputs": [ + { + "name": "_pool", + "type": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256[8]" + } + ], + "gas": 39733 + }, + { + "stateMutability": "view", + "type": "function", + "name": "get_A", + "inputs": [ + { + "name": "_pool", + "type": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "gas": 3135 + }, + { + "stateMutability": "view", + "type": "function", + "name": "get_fees", + "inputs": [ + { + "name": "_pool", + "type": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "gas": 5821 + }, + { + "stateMutability": "view", + "type": "function", + "name": "get_admin_balances", + "inputs": [ + { + "name": "_pool", + "type": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256[4]" + } + ], + "gas": 13535 + }, + { + "stateMutability": "view", + "type": "function", + "name": "get_coin_indices", + "inputs": [ + { + "name": "_pool", + "type": "address" + }, + { + "name": "_from", + "type": "address" + }, + { + "name": "_to", + "type": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "int128" + }, + { + "name": "", + "type": "int128" + }, + { + "name": "", + "type": "bool" + } + ], + "gas": 33407 + }, + { + "stateMutability": "view", + "type": "function", + "name": "get_gauge", + "inputs": [ + { + "name": "_pool", + "type": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "gas": 3089 + }, + { + "stateMutability": "view", + "type": "function", + "name": "get_implementation_address", + "inputs": [ + { + "name": "_pool", + "type": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "gas": 3119 + }, + { + "stateMutability": "view", + "type": "function", + "name": "is_meta", + "inputs": [ + { + "name": "_pool", + "type": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "gas": 3152 + }, + { + "stateMutability": "view", + "type": "function", + "name": "get_pool_asset_type", + "inputs": [ + { + "name": "_pool", + "type": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "gas": 5450 + }, + { + "stateMutability": "view", + "type": "function", + "name": "get_fee_receiver", + "inputs": [ + { + "name": "_pool", + "type": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "gas": 5480 + }, + { + "stateMutability": "nonpayable", + "type": "function", + "name": "deploy_plain_pool", + "inputs": [ + { + "name": "_name", + "type": "string" + }, + { + "name": "_symbol", + "type": "string" + }, + { + "name": "_coins", + "type": "address[4]" + }, + { + "name": "_A", + "type": "uint256" + }, + { + "name": "_fee", + "type": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "address" + } + ] + }, + { + "stateMutability": "nonpayable", + "type": "function", + "name": "deploy_plain_pool", + "inputs": [ + { + "name": "_name", + "type": "string" + }, + { + "name": "_symbol", + "type": "string" + }, + { + "name": "_coins", + "type": "address[4]" + }, + { + "name": "_A", + "type": "uint256" + }, + { + "name": "_fee", + "type": "uint256" + }, + { + "name": "_asset_type", + "type": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "address" + } + ] + }, + { + "stateMutability": "nonpayable", + "type": "function", + "name": "deploy_plain_pool", + "inputs": [ + { + "name": "_name", + "type": "string" + }, + { + "name": "_symbol", + "type": "string" + }, + { + "name": "_coins", + "type": "address[4]" + }, + { + "name": "_A", + "type": "uint256" + }, + { + "name": "_fee", + "type": "uint256" + }, + { + "name": "_asset_type", + "type": "uint256" + }, + { + "name": "_implementation_idx", + "type": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "address" + } + ] + }, + { + "stateMutability": "nonpayable", + "type": "function", + "name": "deploy_metapool", + "inputs": [ + { + "name": "_base_pool", + "type": "address" + }, + { + "name": "_name", + "type": "string" + }, + { + "name": "_symbol", + "type": "string" + }, + { + "name": "_coin", + "type": "address" + }, + { + "name": "_A", + "type": "uint256" + }, + { + "name": "_fee", + "type": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "address" + } + ] + }, + { + "stateMutability": "nonpayable", + "type": "function", + "name": "deploy_metapool", + "inputs": [ + { + "name": "_base_pool", + "type": "address" + }, + { + "name": "_name", + "type": "string" + }, + { + "name": "_symbol", + "type": "string" + }, + { + "name": "_coin", + "type": "address" + }, + { + "name": "_A", + "type": "uint256" + }, + { + "name": "_fee", + "type": "uint256" + }, + { + "name": "_implementation_idx", + "type": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "address" + } + ] + }, + { + "stateMutability": "nonpayable", + "type": "function", + "name": "deploy_gauge", + "inputs": [ + { + "name": "_pool", + "type": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "gas": 93079 + }, + { + "stateMutability": "nonpayable", + "type": "function", + "name": "add_base_pool", + "inputs": [ + { + "name": "_base_pool", + "type": "address" + }, + { + "name": "_fee_receiver", + "type": "address" + }, + { + "name": "_asset_type", + "type": "uint256" + }, + { + "name": "_implementations", + "type": "address[10]" + } + ], + "outputs": [], + "gas": 1206132 + }, + { + "stateMutability": "nonpayable", + "type": "function", + "name": "set_metapool_implementations", + "inputs": [ + { + "name": "_base_pool", + "type": "address" + }, + { + "name": "_implementations", + "type": "address[10]" + } + ], + "outputs": [], + "gas": 382072 + }, + { + "stateMutability": "nonpayable", + "type": "function", + "name": "set_plain_implementations", + "inputs": [ + { + "name": "_n_coins", + "type": "uint256" + }, + { + "name": "_implementations", + "type": "address[10]" + } + ], + "outputs": [], + "gas": 379687 + }, + { + "stateMutability": "nonpayable", + "type": "function", + "name": "set_gauge_implementation", + "inputs": [ + { + "name": "_gauge_implementation", + "type": "address" + } + ], + "outputs": [], + "gas": 38355 + }, + { + "stateMutability": "nonpayable", + "type": "function", + "name": "batch_set_pool_asset_type", + "inputs": [ + { + "name": "_pools", + "type": "address[32]" + }, + { + "name": "_asset_types", + "type": "uint256[32]" + } + ], + "outputs": [], + "gas": 1139545 + }, + { + "stateMutability": "nonpayable", + "type": "function", + "name": "commit_transfer_ownership", + "inputs": [ + { + "name": "_addr", + "type": "address" + } + ], + "outputs": [], + "gas": 38415 + }, + { + "stateMutability": "nonpayable", + "type": "function", + "name": "accept_transfer_ownership", + "inputs": [], + "outputs": [], + "gas": 58366 + }, + { + "stateMutability": "nonpayable", + "type": "function", + "name": "set_manager", + "inputs": [ + { + "name": "_manager", + "type": "address" + } + ], + "outputs": [], + "gas": 40996 + }, + { + "stateMutability": "nonpayable", + "type": "function", + "name": "set_fee_receiver", + "inputs": [ + { + "name": "_base_pool", + "type": "address" + }, + { + "name": "_fee_receiver", + "type": "address" + } + ], + "outputs": [], + "gas": 38770 + }, + { + "stateMutability": "nonpayable", + "type": "function", + "name": "convert_metapool_fees", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "gas": 12880 + }, + { + "stateMutability": "nonpayable", + "type": "function", + "name": "add_existing_metapools", + "inputs": [ + { + "name": "_pools", + "type": "address[10]" + } + ], + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "gas": 8610792 + }, + { + "stateMutability": "view", + "type": "function", + "name": "admin", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "gas": 3438 + }, + { + "stateMutability": "view", + "type": "function", + "name": "future_admin", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "gas": 3468 + }, + { + "stateMutability": "view", + "type": "function", + "name": "manager", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "gas": 3498 + }, + { + "stateMutability": "view", + "type": "function", + "name": "pool_list", + "inputs": [ + { + "name": "arg0", + "type": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "gas": 3573 + }, + { + "stateMutability": "view", + "type": "function", + "name": "pool_count", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "gas": 3558 + }, + { + "stateMutability": "view", + "type": "function", + "name": "base_pool_list", + "inputs": [ + { + "name": "arg0", + "type": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "gas": 3633 + }, + { + "stateMutability": "view", + "type": "function", + "name": "base_pool_count", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "gas": 3618 + }, + { + "stateMutability": "view", + "type": "function", + "name": "base_pool_assets", + "inputs": [ + { + "name": "arg0", + "type": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "gas": 3863 + }, + { + "stateMutability": "view", + "type": "function", + "name": "plain_implementations", + "inputs": [ + { + "name": "arg0", + "type": "uint256" + }, + { + "name": "arg1", + "type": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "gas": 3838 + }, + { + "stateMutability": "view", + "type": "function", + "name": "gauge_implementation", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "gas": 3708 + } +] \ No newline at end of file diff --git a/contracts/mainnet/abi/StableRegistry.json b/contracts/mainnet/abi/StableRegistry.json new file mode 100644 index 0000000..ac50894 --- /dev/null +++ b/contracts/mainnet/abi/StableRegistry.json @@ -0,0 +1,940 @@ +[ + { + "name": "PoolAdded", + "inputs": [ + { + "name": "pool", + "type": "address", + "indexed": true + }, + { + "name": "rate_method_id", + "type": "bytes", + "indexed": false + } + ], + "anonymous": false, + "type": "event" + }, + { + "name": "PoolRemoved", + "inputs": [ + { + "name": "pool", + "type": "address", + "indexed": true + } + ], + "anonymous": false, + "type": "event" + }, + { + "stateMutability": "nonpayable", + "type": "constructor", + "inputs": [ + { + "name": "_address_provider", + "type": "address" + }, + { + "name": "_gauge_controller", + "type": "address" + } + ], + "outputs": [] + }, + { + "stateMutability": "view", + "type": "function", + "name": "find_pool_for_coins", + "inputs": [ + { + "name": "_from", + "type": "address" + }, + { + "name": "_to", + "type": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "address" + } + ] + }, + { + "stateMutability": "view", + "type": "function", + "name": "find_pool_for_coins", + "inputs": [ + { + "name": "_from", + "type": "address" + }, + { + "name": "_to", + "type": "address" + }, + { + "name": "i", + "type": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "address" + } + ] + }, + { + "stateMutability": "view", + "type": "function", + "name": "get_n_coins", + "inputs": [ + { + "name": "_pool", + "type": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256[2]" + } + ], + "gas": 1521 + }, + { + "stateMutability": "view", + "type": "function", + "name": "get_coins", + "inputs": [ + { + "name": "_pool", + "type": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "address[8]" + } + ], + "gas": 12102 + }, + { + "stateMutability": "view", + "type": "function", + "name": "get_underlying_coins", + "inputs": [ + { + "name": "_pool", + "type": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "address[8]" + } + ], + "gas": 12194 + }, + { + "stateMutability": "view", + "type": "function", + "name": "get_decimals", + "inputs": [ + { + "name": "_pool", + "type": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256[8]" + } + ], + "gas": 7874 + }, + { + "stateMutability": "view", + "type": "function", + "name": "get_underlying_decimals", + "inputs": [ + { + "name": "_pool", + "type": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256[8]" + } + ], + "gas": 7966 + }, + { + "stateMutability": "view", + "type": "function", + "name": "get_rates", + "inputs": [ + { + "name": "_pool", + "type": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256[8]" + } + ], + "gas": 36992 + }, + { + "stateMutability": "view", + "type": "function", + "name": "get_gauges", + "inputs": [ + { + "name": "_pool", + "type": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "address[10]" + }, + { + "name": "", + "type": "int128[10]" + } + ], + "gas": 20157 + }, + { + "stateMutability": "view", + "type": "function", + "name": "get_balances", + "inputs": [ + { + "name": "_pool", + "type": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256[8]" + } + ], + "gas": 16583 + }, + { + "stateMutability": "view", + "type": "function", + "name": "get_underlying_balances", + "inputs": [ + { + "name": "_pool", + "type": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256[8]" + } + ], + "gas": 162842 + }, + { + "stateMutability": "view", + "type": "function", + "name": "get_virtual_price_from_lp_token", + "inputs": [ + { + "name": "_token", + "type": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "gas": 1927 + }, + { + "stateMutability": "view", + "type": "function", + "name": "get_A", + "inputs": [ + { + "name": "_pool", + "type": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "gas": 1045 + }, + { + "stateMutability": "view", + "type": "function", + "name": "get_parameters", + "inputs": [ + { + "name": "_pool", + "type": "address" + } + ], + "outputs": [ + { + "name": "A", + "type": "uint256" + }, + { + "name": "future_A", + "type": "uint256" + }, + { + "name": "fee", + "type": "uint256" + }, + { + "name": "admin_fee", + "type": "uint256" + }, + { + "name": "future_fee", + "type": "uint256" + }, + { + "name": "future_admin_fee", + "type": "uint256" + }, + { + "name": "future_owner", + "type": "address" + }, + { + "name": "initial_A", + "type": "uint256" + }, + { + "name": "initial_A_time", + "type": "uint256" + }, + { + "name": "future_A_time", + "type": "uint256" + } + ], + "gas": 6305 + }, + { + "stateMutability": "view", + "type": "function", + "name": "get_fees", + "inputs": [ + { + "name": "_pool", + "type": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256[2]" + } + ], + "gas": 1450 + }, + { + "stateMutability": "view", + "type": "function", + "name": "get_admin_balances", + "inputs": [ + { + "name": "_pool", + "type": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256[8]" + } + ], + "gas": 36454 + }, + { + "stateMutability": "view", + "type": "function", + "name": "get_coin_indices", + "inputs": [ + { + "name": "_pool", + "type": "address" + }, + { + "name": "_from", + "type": "address" + }, + { + "name": "_to", + "type": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "int128" + }, + { + "name": "", + "type": "int128" + }, + { + "name": "", + "type": "bool" + } + ], + "gas": 27131 + }, + { + "stateMutability": "view", + "type": "function", + "name": "estimate_gas_used", + "inputs": [ + { + "name": "_pool", + "type": "address" + }, + { + "name": "_from", + "type": "address" + }, + { + "name": "_to", + "type": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "gas": 32004 + }, + { + "stateMutability": "view", + "type": "function", + "name": "is_meta", + "inputs": [ + { + "name": "_pool", + "type": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "gas": 1900 + }, + { + "stateMutability": "view", + "type": "function", + "name": "get_pool_name", + "inputs": [ + { + "name": "_pool", + "type": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "gas": 8323 + }, + { + "stateMutability": "view", + "type": "function", + "name": "get_coin_swap_count", + "inputs": [ + { + "name": "_coin", + "type": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "gas": 1951 + }, + { + "stateMutability": "view", + "type": "function", + "name": "get_coin_swap_complement", + "inputs": [ + { + "name": "_coin", + "type": "address" + }, + { + "name": "_index", + "type": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "gas": 2090 + }, + { + "stateMutability": "view", + "type": "function", + "name": "get_pool_asset_type", + "inputs": [ + { + "name": "_pool", + "type": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "gas": 2011 + }, + { + "stateMutability": "nonpayable", + "type": "function", + "name": "add_pool", + "inputs": [ + { + "name": "_pool", + "type": "address" + }, + { + "name": "_n_coins", + "type": "uint256" + }, + { + "name": "_lp_token", + "type": "address" + }, + { + "name": "_rate_info", + "type": "bytes32" + }, + { + "name": "_decimals", + "type": "uint256" + }, + { + "name": "_underlying_decimals", + "type": "uint256" + }, + { + "name": "_has_initial_A", + "type": "bool" + }, + { + "name": "_is_v1", + "type": "bool" + }, + { + "name": "_name", + "type": "string" + } + ], + "outputs": [], + "gas": 61485845 + }, + { + "stateMutability": "nonpayable", + "type": "function", + "name": "add_pool_without_underlying", + "inputs": [ + { + "name": "_pool", + "type": "address" + }, + { + "name": "_n_coins", + "type": "uint256" + }, + { + "name": "_lp_token", + "type": "address" + }, + { + "name": "_rate_info", + "type": "bytes32" + }, + { + "name": "_decimals", + "type": "uint256" + }, + { + "name": "_use_rates", + "type": "uint256" + }, + { + "name": "_has_initial_A", + "type": "bool" + }, + { + "name": "_is_v1", + "type": "bool" + }, + { + "name": "_name", + "type": "string" + } + ], + "outputs": [], + "gas": 31306062 + }, + { + "stateMutability": "nonpayable", + "type": "function", + "name": "add_metapool", + "inputs": [ + { + "name": "_pool", + "type": "address" + }, + { + "name": "_n_coins", + "type": "uint256" + }, + { + "name": "_lp_token", + "type": "address" + }, + { + "name": "_decimals", + "type": "uint256" + }, + { + "name": "_name", + "type": "string" + } + ], + "outputs": [] + }, + { + "stateMutability": "nonpayable", + "type": "function", + "name": "add_metapool", + "inputs": [ + { + "name": "_pool", + "type": "address" + }, + { + "name": "_n_coins", + "type": "uint256" + }, + { + "name": "_lp_token", + "type": "address" + }, + { + "name": "_decimals", + "type": "uint256" + }, + { + "name": "_name", + "type": "string" + }, + { + "name": "_base_pool", + "type": "address" + } + ], + "outputs": [] + }, + { + "stateMutability": "nonpayable", + "type": "function", + "name": "remove_pool", + "inputs": [ + { + "name": "_pool", + "type": "address" + } + ], + "outputs": [], + "gas": 779731418758 + }, + { + "stateMutability": "nonpayable", + "type": "function", + "name": "set_pool_gas_estimates", + "inputs": [ + { + "name": "_addr", + "type": "address[5]" + }, + { + "name": "_amount", + "type": "uint256[2][5]" + } + ], + "outputs": [], + "gas": 390460 + }, + { + "stateMutability": "nonpayable", + "type": "function", + "name": "set_coin_gas_estimates", + "inputs": [ + { + "name": "_addr", + "type": "address[10]" + }, + { + "name": "_amount", + "type": "uint256[10]" + } + ], + "outputs": [], + "gas": 392047 + }, + { + "stateMutability": "nonpayable", + "type": "function", + "name": "set_gas_estimate_contract", + "inputs": [ + { + "name": "_pool", + "type": "address" + }, + { + "name": "_estimator", + "type": "address" + } + ], + "outputs": [], + "gas": 72629 + }, + { + "stateMutability": "nonpayable", + "type": "function", + "name": "set_liquidity_gauges", + "inputs": [ + { + "name": "_pool", + "type": "address" + }, + { + "name": "_liquidity_gauges", + "type": "address[10]" + } + ], + "outputs": [], + "gas": 400675 + }, + { + "stateMutability": "nonpayable", + "type": "function", + "name": "set_pool_asset_type", + "inputs": [ + { + "name": "_pool", + "type": "address" + }, + { + "name": "_asset_type", + "type": "uint256" + } + ], + "outputs": [], + "gas": 72667 + }, + { + "stateMutability": "nonpayable", + "type": "function", + "name": "batch_set_pool_asset_type", + "inputs": [ + { + "name": "_pools", + "type": "address[32]" + }, + { + "name": "_asset_types", + "type": "uint256[32]" + } + ], + "outputs": [], + "gas": 1173447 + }, + { + "stateMutability": "view", + "type": "function", + "name": "address_provider", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "gas": 2048 + }, + { + "stateMutability": "view", + "type": "function", + "name": "gauge_controller", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "gas": 2078 + }, + { + "stateMutability": "view", + "type": "function", + "name": "pool_list", + "inputs": [ + { + "name": "arg0", + "type": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "gas": 2217 + }, + { + "stateMutability": "view", + "type": "function", + "name": "pool_count", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "gas": 2138 + }, + { + "stateMutability": "view", + "type": "function", + "name": "coin_count", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "gas": 2168 + }, + { + "stateMutability": "view", + "type": "function", + "name": "get_coin", + "inputs": [ + { + "name": "arg0", + "type": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "gas": 2307 + }, + { + "stateMutability": "view", + "type": "function", + "name": "get_pool_from_lp_token", + "inputs": [ + { + "name": "arg0", + "type": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "gas": 2443 + }, + { + "stateMutability": "view", + "type": "function", + "name": "get_lp_token", + "inputs": [ + { + "name": "arg0", + "type": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "gas": 2473 + }, + { + "stateMutability": "view", + "type": "function", + "name": "last_updated", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "gas": 2288 + } +] \ No newline at end of file diff --git a/contracts/mainnet/mocks/AddressProvider.vy b/contracts/mainnet/mocks/AddressProvider.vy deleted file mode 100644 index cef5f21..0000000 --- a/contracts/mainnet/mocks/AddressProvider.vy +++ /dev/null @@ -1,213 +0,0 @@ -# @version 0.2.7 -""" -@title Curve Registry Address Provider -@license MIT -@author Curve.Fi -""" - -event NewAddressIdentifier: - id: indexed(uint256) - addr: address - description: String[64] - -event AddressModified: - id: indexed(uint256) - new_address: address - version: uint256 - -event CommitNewAdmin: - deadline: indexed(uint256) - admin: indexed(address) - -event NewAdmin: - admin: indexed(address) - - -struct AddressInfo: - addr: address - is_active: bool - version: uint256 - last_modified: uint256 - description: String[64] - - -registry: address -admin: public(address) -transfer_ownership_deadline: public(uint256) -future_admin: public(address) - -queue_length: uint256 -get_id_info: public(HashMap[uint256, AddressInfo]) - - -@external -def __init__(_admin: address): - self.admin = _admin - self.queue_length = 1 - self.get_id_info[0].description = "Main Registry" - - -@view -@external -def get_registry() -> address: - """ - @notice Get the address of the main registry contract - @dev This is a gas-efficient way of calling `AddressProvider.get_address(0)` - @return address main registry contract - """ - return self.registry - - -@view -@external -def max_id() -> uint256: - """ - @notice Get the highest ID set within the address provider - @return uint256 max ID - """ - return self.queue_length - 1 - - -@view -@external -def get_address(_id: uint256) -> address: - """ - @notice Fetch the address associated with `_id` - @dev Returns ZERO_ADDRESS if `_id` has not been defined, or has been unset - @param _id Identifier to fetch an address for - @return Current address associated to `_id` - """ - return self.get_id_info[_id].addr - - -@external -def add_new_id(_address: address, _description: String[64]) -> uint256: - """ - @notice Add a new identifier to the registry - @dev ID is auto-incremented - @param _address Initial address to assign to new identifier - @param _description Human-readable description of the identifier - @return uint256 identifier - """ - assert msg.sender == self.admin # dev: admin-only function - assert _address.is_contract # dev: not a contract - - id: uint256 = self.queue_length - self.get_id_info[id] = AddressInfo({ - addr: _address, - is_active: True, - version: 1, - last_modified: block.timestamp, - description: _description - }) - self.queue_length = id + 1 - - log NewAddressIdentifier(id, _address, _description) - - return id - - -@external -def set_address(_id: uint256, _address: address) -> bool: - """ - @notice Set a new address for an existing identifier - @param _id Identifier to set the new address for - @param _address Address to set - @return bool success - """ - assert msg.sender == self.admin # dev: admin-only function - assert _address.is_contract # dev: not a contract - assert self.queue_length > _id # dev: id does not exist - - version: uint256 = self.get_id_info[_id].version + 1 - - self.get_id_info[_id].addr = _address - self.get_id_info[_id].is_active = True - self.get_id_info[_id].version = version - self.get_id_info[_id].last_modified = block.timestamp - - if _id == 0: - self.registry = _address - - log AddressModified(_id, _address, version) - - return True - - -@external -def unset_address(_id: uint256) -> bool: - """ - @notice Unset an existing identifier - @dev An identifier cannot ever be removed, it can only have the - address unset so that it returns ZERO_ADDRESS - @param _id Identifier to unset - @return bool success - """ - assert msg.sender == self.admin # dev: admin-only function - assert self.get_id_info[_id].is_active # dev: not active - - self.get_id_info[_id].is_active = False - self.get_id_info[_id].addr = ZERO_ADDRESS - self.get_id_info[_id].last_modified = block.timestamp - - if _id == 0: - self.registry = ZERO_ADDRESS - - log AddressModified(_id, ZERO_ADDRESS, self.get_id_info[_id].version) - - return True - - -@external -def commit_transfer_ownership(_new_admin: address) -> bool: - """ - @notice Initiate a transfer of contract ownership - @dev Once initiated, the actual transfer may be performed three days later - @param _new_admin Address of the new owner account - @return bool success - """ - assert msg.sender == self.admin # dev: admin-only function - assert self.transfer_ownership_deadline == 0 # dev: transfer already active - - deadline: uint256 = block.timestamp + 3*86400 - self.transfer_ownership_deadline = deadline - self.future_admin = _new_admin - - log CommitNewAdmin(deadline, _new_admin) - - return True - - -@external -def apply_transfer_ownership() -> bool: - """ - @notice Finalize a transfer of contract ownership - @dev May only be called by the current owner, three days after a - call to `commit_transfer_ownership` - @return bool success - """ - assert msg.sender == self.admin # dev: admin-only function - assert self.transfer_ownership_deadline != 0 # dev: transfer not active - assert block.timestamp >= self.transfer_ownership_deadline # dev: now < deadline - - new_admin: address = self.future_admin - self.admin = new_admin - self.transfer_ownership_deadline = 0 - - log NewAdmin(new_admin) - - return True - - -@external -def revert_transfer_ownership() -> bool: - """ - @notice Revert a transfer of contract ownership - @dev May only be called by the current owner - @return bool success - """ - assert msg.sender == self.admin # dev: admin-only function - - self.transfer_ownership_deadline = 0 - - return True diff --git a/contracts/mainnet/mocks/CryptoFactory.vy b/contracts/mainnet/mocks/CryptoFactory.vy deleted file mode 100644 index 0780165..0000000 --- a/contracts/mainnet/mocks/CryptoFactory.vy +++ /dev/null @@ -1,441 +0,0 @@ -# @version 0.3.1 -""" -@title Curve Factory -@license MIT -@author Curve.Fi -@notice Permissionless pool deployer and registry -""" - - -interface CryptoPool: - def balances(i: uint256) -> uint256: view - def initialize( - A: uint256, - gamma: uint256, - mid_fee: uint256, - out_fee: uint256, - allowed_extra_profit: uint256, - fee_gamma: uint256, - adjustment_step: uint256, - admin_fee: uint256, - ma_half_time: uint256, - initial_price: uint256, - _token: address, - _coins: address[2], - _precisions: uint256 - ): nonpayable - -interface ERC20: - def decimals() -> uint256: view - -interface LiquidityGauge: - def initialize(_lp_token: address): nonpayable - -interface Token: - def initialize(_name: String[64], _symbol: String[32], _pool: address): nonpayable - - -event CryptoPoolDeployed: - token: address - coins: address[2] - A: uint256 - gamma: uint256 - mid_fee: uint256 - out_fee: uint256 - allowed_extra_profit: uint256 - fee_gamma: uint256 - adjustment_step: uint256 - admin_fee: uint256 - ma_half_time: uint256 - initial_price: uint256 - deployer: address - -event LiquidityGaugeDeployed: - pool: address - token: address - gauge: address - -event UpdateFeeReceiver: - _old_fee_receiver: address - _new_fee_receiver: address - -event UpdatePoolImplementation: - _old_pool_implementation: address - _new_pool_implementation: address - -event UpdateTokenImplementation: - _old_token_implementation: address - _new_token_implementation: address - -event UpdateGaugeImplementation: - _old_gauge_implementation: address - _new_gauge_implementation: address - -event TransferOwnership: - _old_owner: address - _new_owner: address - - -struct PoolArray: - token: address - liquidity_gauge: address - coins: address[2] - decimals: uint256 - - -N_COINS: constant(int128) = 2 -A_MULTIPLIER: constant(uint256) = 10000 - -# Limits -MAX_ADMIN_FEE: constant(uint256) = 10 * 10 ** 9 -MIN_FEE: constant(uint256) = 5 * 10 ** 5 # 0.5 bps -MAX_FEE: constant(uint256) = 10 * 10 ** 9 - -MIN_GAMMA: constant(uint256) = 10 ** 10 -MAX_GAMMA: constant(uint256) = 2 * 10 ** 16 - -MIN_A: constant(uint256) = N_COINS ** N_COINS * A_MULTIPLIER / 10 -MAX_A: constant(uint256) = N_COINS ** N_COINS * A_MULTIPLIER * 100000 - - -WETH: immutable(address) - - -admin: public(address) -future_admin: public(address) - -# fee receiver for plain pools -fee_receiver: public(address) - -pool_implementation: public(address) -token_implementation: public(address) -gauge_implementation: public(address) - -# mapping of coins -> pools for trading -# a mapping key is generated for each pair of addresses via -# `bitwise_xor(convert(a, uint256), convert(b, uint256))` -markets: HashMap[uint256, address[4294967296]] -market_counts: HashMap[uint256, uint256] - -pool_count: public(uint256) # actual length of pool_list -pool_data: HashMap[address, PoolArray] -pool_list: public(address[4294967296]) # master list of pools - - -@external -def __init__( - _fee_receiver: address, - _pool_implementation: address, - _token_implementation: address, - _gauge_implementation: address, - _weth: address -): - self.fee_receiver = _fee_receiver - self.pool_implementation = _pool_implementation - self.token_implementation = _token_implementation - self.gauge_implementation = _gauge_implementation - - self.admin = msg.sender - WETH = _weth - - log UpdateFeeReceiver(ZERO_ADDRESS, _fee_receiver) - log UpdatePoolImplementation(ZERO_ADDRESS, _pool_implementation) - log UpdateTokenImplementation(ZERO_ADDRESS, _token_implementation) - log UpdateGaugeImplementation(ZERO_ADDRESS, _gauge_implementation) - log TransferOwnership(ZERO_ADDRESS, msg.sender) - - -# <--- Pool Deployers ---> - -@external -def deploy_pool( - _name: String[32], - _symbol: String[10], - _coins: address[2], - A: uint256, - gamma: uint256, - mid_fee: uint256, - out_fee: uint256, - allowed_extra_profit: uint256, - fee_gamma: uint256, - adjustment_step: uint256, - admin_fee: uint256, - ma_half_time: uint256, - initial_price: uint256 -) -> address: - """ - @notice Deploy a new pool - @param _name Name of the new plain pool - @param _symbol Symbol for the new plain pool - will be concatenated with factory symbol - Other parameters need some description - @return Address of the deployed pool - """ - # Validate parameters - assert A > MIN_A-1 - assert A < MAX_A+1 - assert gamma > MIN_GAMMA-1 - assert gamma < MAX_GAMMA+1 - assert mid_fee > MIN_FEE-1 - assert mid_fee < MAX_FEE-1 - assert out_fee >= mid_fee - assert out_fee < MAX_FEE-1 - assert admin_fee < 10**18+1 - assert allowed_extra_profit < 10**16+1 - assert fee_gamma < 10**18+1 - assert fee_gamma > 0 - assert adjustment_step < 10**18+1 - assert adjustment_step > 0 - assert ma_half_time < 7 * 86400 - assert ma_half_time > 0 - assert initial_price > 10**6 - assert initial_price < 10**30 - assert _coins[0] != _coins[1], "Duplicate coins" - - decimals: uint256[2] = empty(uint256[2]) - for i in range(2): - d: uint256 = ERC20(_coins[i]).decimals() - assert d < 19, "Max 18 decimals for coins" - decimals[i] = d - precisions: uint256 = (18 - decimals[0]) + shift(18 - decimals[1], 8) - - - name: String[64] = concat("Curve.fi Factory Crypto Pool: ", _name) - symbol: String[32] = concat(_symbol, "-f") - - token: address = create_forwarder_to(self.token_implementation) - pool: address = create_forwarder_to(self.pool_implementation) - - Token(token).initialize(name, symbol, pool) - CryptoPool(pool).initialize( - A, gamma, mid_fee, out_fee, allowed_extra_profit, fee_gamma, - adjustment_step, admin_fee, ma_half_time, initial_price, - token, _coins, precisions) - - length: uint256 = self.pool_count - self.pool_list[length] = pool - self.pool_count = length + 1 - self.pool_data[pool].token = token - self.pool_data[pool].decimals = shift(decimals[0], 8) + decimals[1] - self.pool_data[pool].coins = _coins - - key: uint256 = bitwise_xor(convert(_coins[0], uint256), convert(_coins[1], uint256)) - length = self.market_counts[key] - self.markets[key][length] = pool - self.market_counts[key] = length + 1 - - log CryptoPoolDeployed( - token, _coins, - A, gamma, mid_fee, out_fee, allowed_extra_profit, fee_gamma, - adjustment_step, admin_fee, ma_half_time, initial_price, - msg.sender) - return pool - - -@external -def deploy_gauge(_pool: address) -> address: - """ - @notice Deploy a liquidity gauge for a factory pool - @param _pool Factory pool address to deploy a gauge for - @return Address of the deployed gauge - """ - assert self.pool_data[_pool].coins[0] != ZERO_ADDRESS, "Unknown pool" - assert self.pool_data[_pool].liquidity_gauge == ZERO_ADDRESS, "Gauge already deployed" - - gauge: address = create_forwarder_to(self.gauge_implementation) - token: address = self.pool_data[_pool].token - LiquidityGauge(gauge).initialize(token) - self.pool_data[_pool].liquidity_gauge = gauge - - log LiquidityGaugeDeployed(_pool, token, gauge) - return gauge - - -# <--- Admin / Guarded Functionality ---> - - -@external -def set_fee_receiver(_fee_receiver: address): - """ - @notice Set fee receiver - @param _fee_receiver Address that fees are sent to - """ - assert msg.sender == self.admin # dev: admin only - - log UpdateFeeReceiver(self.fee_receiver, _fee_receiver) - self.fee_receiver = _fee_receiver - - -@external -def set_pool_implementation(_pool_implementation: address): - """ - @notice Set pool implementation - @dev Set to ZERO_ADDRESS to prevent deployment of new pools - @param _pool_implementation Address of the new pool implementation - """ - assert msg.sender == self.admin # dev: admin only - - log UpdatePoolImplementation(self.pool_implementation, _pool_implementation) - self.pool_implementation = _pool_implementation - - -@external -def set_token_implementation(_token_implementation: address): - """ - @notice Set token implementation - @dev Set to ZERO_ADDRESS to prevent deployment of new pools - @param _token_implementation Address of the new token implementation - """ - assert msg.sender == self.admin # dev: admin only - - log UpdateTokenImplementation(self.token_implementation, _token_implementation) - self.token_implementation = _token_implementation - - -@external -def set_gauge_implementation(_gauge_implementation: address): - """ - @notice Set gauge implementation - @dev Set to ZERO_ADDRESS to prevent deployment of new gauges - @param _gauge_implementation Address of the new token implementation - """ - assert msg.sender == self.admin # dev: admin-only function - - log UpdateGaugeImplementation(self.gauge_implementation, _gauge_implementation) - self.gauge_implementation = _gauge_implementation - - -@external -def commit_transfer_ownership(_addr: address): - """ - @notice Transfer ownership of this contract to `addr` - @param _addr Address of the new owner - """ - assert msg.sender == self.admin # dev: admin only - - self.future_admin = _addr - - -@external -def accept_transfer_ownership(): - """ - @notice Accept a pending ownership transfer - @dev Only callable by the new owner - """ - assert msg.sender == self.future_admin # dev: future admin only - - log TransferOwnership(self.admin, msg.sender) - self.admin = msg.sender - - -# <--- Factory Getters ---> - - -@view -@external -def find_pool_for_coins(_from: address, _to: address, i: uint256 = 0) -> address: - """ - @notice Find an available pool for exchanging two coins - @param _from Address of coin to be sent - @param _to Address of coin to be received - @param i Index value. When multiple pools are available - this value is used to return the n'th address. - @return Pool address - """ - key: uint256 = bitwise_xor(convert(_from, uint256), convert(_to, uint256)) - return self.markets[key][i] - - -# <--- Pool Getters ---> - - -@view -@external -def get_coins(_pool: address) -> address[2]: - """ - @notice Get the coins within a pool - @param _pool Pool address - @return List of coin addresses - """ - return self.pool_data[_pool].coins - - -@view -@external -def get_decimals(_pool: address) -> uint256[2]: - """ - @notice Get decimal places for each coin within a pool - @param _pool Pool address - @return uint256 list of decimals - """ - decimals: uint256 = self.pool_data[_pool].decimals - return [shift(decimals, -8), decimals % 256] - - -@view -@external -def get_balances(_pool: address) -> uint256[2]: - """ - @notice Get balances for each coin within a pool - @dev For pools using lending, these are the wrapped coin balances - @param _pool Pool address - @return uint256 list of balances - """ - return [CryptoPool(_pool).balances(0), CryptoPool(_pool).balances(1)] - - -@view -@external -def get_coin_indices( - _pool: address, - _from: address, - _to: address -) -> (uint256, uint256): - """ - @notice Convert coin addresses to indices for use with pool methods - @param _pool Pool address - @param _from Coin address to be used as `i` within a pool - @param _to Coin address to be used as `j` within a pool - @return uint256 `i`, uint256 `j` - """ - coins: address[2] = self.pool_data[_pool].coins - - if _from == coins[0] and _to == coins[1]: - return 0, 1 - elif _from == coins[1] and _to == coins[0]: - return 1, 0 - else: - raise "Coins not found" - - -@view -@external -def get_gauge(_pool: address) -> address: - """ - @notice Get the address of the liquidity gauge contract for a factory pool - @dev Returns `ZERO_ADDRESS` if a gauge has not been deployed - @param _pool Pool address - @return Implementation contract address - """ - return self.pool_data[_pool].liquidity_gauge - - -@view -@external -def get_eth_index(_pool: address) -> uint256: - """ - @notice Get the index of WETH for a pool - @dev Returns MAX_UINT256 if WETH is not a coin in the pool - """ - for i in range(2): - if self.pool_data[_pool].coins[i] == WETH: - return i - return MAX_UINT256 - - -@view -@external -def get_token(_pool: address) -> address: - """ - @notice Get the address of the LP token of a pool - """ - return self.pool_data[_pool].token diff --git a/contracts/mainnet/mocks/CryptoRegistry.vy b/contracts/mainnet/mocks/CryptoRegistry.vy deleted file mode 100644 index c7ee9b5..0000000 --- a/contracts/mainnet/mocks/CryptoRegistry.vy +++ /dev/null @@ -1,681 +0,0 @@ -# @version 0.3.0 -""" -@title Curve CryptoSwap Registry -@license MIT -@author Curve.Fi -""" - -MAX_COINS: constant(int128) = 8 -CALC_INPUT_SIZE: constant(int128) = 100 - - -struct CoinInfo: - index: uint256 - register_count: uint256 - swap_count: uint256 - swap_for: address[MAX_INT128] - -struct PoolArray: - location: uint256 - decimals: uint256 - coins: address[MAX_COINS] - n_coins: uint256 - name: String[64] - - -interface AddressProvider: - def admin() -> address: view - def get_address(_id: uint256) -> address: view - def get_registry() -> address: view - -interface ERC20: - def balanceOf(_addr: address) -> uint256: view - def decimals() -> uint256: view - def totalSupply() -> uint256: view - -interface CurvePool: - def token() -> address: view - def coins(i: uint256) -> address: view - def A() -> uint256: view - def gamma() -> uint256: view - def fee() -> uint256: view - def get_virtual_price() -> uint256: view - def mid_fee() -> uint256: view - def out_fee() -> uint256: view - def admin_fee() -> uint256: view - def balances(i: uint256) -> uint256: view - def D() -> uint256: view - -interface LiquidityGauge: - def lp_token() -> address: view - -interface GaugeController: - def gauge_types(gauge: address) -> int128: view - - -event PoolAdded: - pool: indexed(address) - -event PoolRemoved: - pool: indexed(address) - - -address_provider: public(AddressProvider) -pool_list: public(address[65536]) # master list of pools -pool_count: public(uint256) # actual length of pool_list - -pool_data: HashMap[address, PoolArray] - -coin_count: public(uint256) # total unique coins registered -coins: HashMap[address, CoinInfo] -get_coin: public(address[65536]) # unique list of registered coins -# bitwise_xor(coina, coinb) -> (coina_pos, coinb_pos) sorted -# stored as uint128[2] -coin_swap_indexes: HashMap[uint256, uint256] - -# lp token -> pool -get_pool_from_lp_token: public(HashMap[address, address]) - -# pool -> lp token -get_lp_token: public(HashMap[address, address]) - -# mapping of coins -> pools for trading -# a mapping key is generated for each pair of addresses via -# `bitwise_xor(convert(a, uint256), convert(b, uint256))` -markets: HashMap[uint256, address[65536]] -market_counts: HashMap[uint256, uint256] - -liquidity_gauges: HashMap[address, address[10]] - -# mapping of pool -> deposit/exchange zap -get_zap: public(HashMap[address, address]) - -last_updated: public(uint256) - - -@external -def __init__(_address_provider: AddressProvider): - """ - @notice Constructor function - """ - self.address_provider = _address_provider - -# internal functionality for getters - -@view -@internal -def _get_balances(_pool: address) -> uint256[MAX_COINS]: - balances: uint256[MAX_COINS] = empty(uint256[MAX_COINS]) - for i in range(MAX_COINS): - if self.pool_data[_pool].coins[i] == ZERO_ADDRESS: - assert i != 0 - break - - balances[i] = CurvePool(_pool).balances(i) - - return balances - - -# targetted external getters, optimized for on-chain calls - -@view -@external -def find_pool_for_coins(_from: address, _to: address, i: uint256 = 0) -> address: - """ - @notice Find an available pool for exchanging two coins - @param _from Address of coin to be sent - @param _to Address of coin to be received - @param i Index value. When multiple pools are available - this value is used to return the n'th address. - @return Pool address - """ - key: uint256 = bitwise_xor(convert(_from, uint256), convert(_to, uint256)) - return self.markets[key][i] - - -@view -@external -def get_n_coins(_pool: address) -> uint256: - """ - @notice Get the number of coins in a pool - @dev For non-metapools, both returned values are identical - even when the pool does not use wrapping/lending - @param _pool Pool address - @return Number of wrapped coins, number of underlying coins - """ - return self.pool_data[_pool].n_coins - - -@view -@external -def get_coins(_pool: address) -> address[MAX_COINS]: - """ - @notice Get the coins within a pool - @dev For pools using lending, these are the wrapped coin addresses - @param _pool Pool address - @return List of coin addresses - """ - coins: address[MAX_COINS] = empty(address[MAX_COINS]) - n_coins: uint256 = self.pool_data[_pool].n_coins - for i in range(MAX_COINS): - if i == n_coins: - break - coins[i] = self.pool_data[_pool].coins[i] - - return coins - - -@view -@external -def get_decimals(_pool: address) -> uint256[MAX_COINS]: - """ - @notice Get decimal places for each coin within a pool - @dev For pools using lending, these are the wrapped coin decimal places - @param _pool Pool address - @return uint256 list of decimals - """ - - # decimals are tightly packed as a series of uint8 within a little-endian bytes32 - # the packed value is stored as uint256 to simplify unpacking via shift and modulo - packed: uint256 = self.pool_data[_pool].decimals - decimals: uint256[MAX_COINS] = empty(uint256[MAX_COINS]) - n_coins: int128 = convert(self.pool_data[_pool].n_coins, int128) - for i in range(MAX_COINS): - if i == n_coins: - break - decimals[i] = shift(packed, -8 * i) % 256 - - return decimals - - -@view -@external -def get_gauges(_pool: address) -> (address[10], int128[10]): - """ - @notice Get a list of LiquidityGauge contracts associated with a pool - @param _pool Pool address - @return address[10] of gauge addresses, int128[10] of gauge types - """ - liquidity_gauges: address[10] = empty(address[10]) - gauge_types: int128[10] = empty(int128[10]) - for i in range(10): - gauge: address = self.liquidity_gauges[_pool][i] - if gauge == ZERO_ADDRESS: - break - liquidity_gauges[i] = gauge - - return liquidity_gauges, gauge_types - - -@view -@external -def get_balances(_pool: address) -> uint256[MAX_COINS]: - """ - @notice Get balances for each coin within a pool - @dev For pools using lending, these are the wrapped coin balances - @param _pool Pool address - @return uint256 list of balances - """ - return self._get_balances(_pool) - - -@view -@external -def get_virtual_price_from_lp_token(_token: address) -> uint256: - """ - @notice Get the virtual price of a pool LP token - @param _token LP token address - @return uint256 Virtual price - """ - return CurvePool(self.get_pool_from_lp_token[_token]).get_virtual_price() - - -@view -@external -def get_A(_pool: address) -> uint256: - return CurvePool(_pool).A() - - -@view -@external -def get_D(_pool: address) -> uint256: - return CurvePool(_pool).D() - - -@view -@external -def get_gamma(_pool: address) -> uint256: - return CurvePool(_pool).gamma() - - -@view -@external -def get_fees(_pool: address) -> uint256[4]: - """ - @notice Get the fees for a pool - @dev Fees are expressed as integers - @return Pool fee as uint256 with 1e10 precision - Admin fee as 1e10 percentage of pool fee - Mid fee - Out fee - """ - return [CurvePool(_pool).fee(), CurvePool(_pool).admin_fee(), CurvePool(_pool).mid_fee(), CurvePool(_pool).out_fee()] - - -@view -@external -def get_admin_balances(_pool: address) -> uint256[MAX_COINS]: - """ - @notice Get the current admin balances (uncollected fees) for a pool - @param _pool Pool address - @return List of uint256 admin balances - """ - balances: uint256[MAX_COINS] = self._get_balances(_pool) - n_coins: uint256 = self.pool_data[_pool].n_coins - for i in range(MAX_COINS): - coin: address = self.pool_data[_pool].coins[i] - if i == n_coins: - break - if coin == 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE: - balances[i] = _pool.balance - balances[i] - else: - balances[i] = ERC20(coin).balanceOf(_pool) - balances[i] - - return balances - - -@view -@external -def get_coin_indices( - _pool: address, - _from: address, - _to: address -) -> (uint256, uint256): - """ - @notice Convert coin addresses to indices for use with pool methods - @param _from Coin address to be used as `i` within a pool - @param _to Coin address to be used as `j` within a pool - @return int128 `i`, int128 `j`, boolean indicating if `i` and `j` are underlying coins - """ - # the return value is stored as `uint256[3]` to reduce gas costs - # from index, to index, is the market underlying? - result: uint256[2] = empty(uint256[2]) - - found_market: bool = False - - # check coin markets - for x in range(MAX_COINS): - coin: address = self.pool_data[_pool].coins[x] - if coin == ZERO_ADDRESS: - # if we reach the end of the coins, reset `found_market` and try again - # with the underlying coins - found_market = False - break - if coin == _from: - result[0] = x - elif coin == _to: - result[1] = x - else: - continue - if found_market: - # the second time we find a match, break out of the loop - return result[0], result[1] - # the first time we find a match, set `found_market` to True - found_market = True - - raise "No available market" - - -@view -@external -def get_pool_name(_pool: address) -> String[64]: - """ - @notice Get the given name for a pool - @param _pool Pool address - @return The name of a pool - """ - return self.pool_data[_pool].name - - -@view -@external -def get_coin_swap_count(_coin: address) -> uint256: - """ - @notice Get the number of unique coins available to swap `_coin` against - @param _coin Coin address - @return The number of unique coins available to swap for - """ - return self.coins[_coin].swap_count - - -@view -@external -def get_coin_swap_complement(_coin: address, _index: uint256) -> address: - """ - @notice Get the coin available to swap against `_coin` at `_index` - @param _coin Coin address - @param _index An index in the `_coin`'s set of available counter - coin's - @return Address of a coin available to swap against `_coin` - """ - return self.coins[_coin].swap_for[_index] - - -# internal functionality used in admin setters - - -@internal -def _register_coin(_coin: address): - if self.coins[_coin].register_count == 0: - coin_count: uint256 = self.coin_count - self.coins[_coin].index = coin_count - self.get_coin[coin_count] = _coin - self.coin_count += 1 - self.coins[_coin].register_count += 1 - - -@internal -def _register_coin_pair(_coina: address, _coinb: address, _key: uint256): - # register _coinb in _coina's array of coins - coin_b_pos: uint256 = self.coins[_coina].swap_count - self.coins[_coina].swap_for[coin_b_pos] = _coinb - self.coins[_coina].swap_count += 1 - # register _coina in _coinb's array of coins - coin_a_pos: uint256 = self.coins[_coinb].swap_count - self.coins[_coinb].swap_for[coin_a_pos] = _coina - self.coins[_coinb].swap_count += 1 - # register indexes (coina pos in coinb array, coinb pos in coina array) - if convert(_coina, uint256) < convert(_coinb, uint256): - self.coin_swap_indexes[_key] = shift(coin_a_pos, 128) + coin_b_pos - else: - self.coin_swap_indexes[_key] = shift(coin_b_pos, 128) + coin_a_pos - - -@internal -def _unregister_coin(_coin: address): - self.coins[_coin].register_count -= 1 - - if self.coins[_coin].register_count == 0: - self.coin_count -= 1 - coin_count: uint256 = self.coin_count - location: uint256 = self.coins[_coin].index - - if location < coin_count: - coin_b: address = self.get_coin[coin_count] - self.get_coin[location] = coin_b - self.coins[coin_b].index = location - - self.coins[_coin].index = 0 - self.get_coin[coin_count] = ZERO_ADDRESS - - -@internal -def _unregister_coin_pair(_coina: address, _coinb: address, _coinb_idx: uint256): - """ - @param _coinb_idx the index of _coinb in _coina's array of unique coin's - """ - # decrement swap counts for both coins - self.coins[_coina].swap_count -= 1 - - # retrieve the last currently occupied index in coina's array - coina_arr_last_idx: uint256 = self.coins[_coina].swap_count - - # if coinb's index in coina's array is less than the last - # overwrite it's position with the last coin - if _coinb_idx < coina_arr_last_idx: - # here's our last coin in coina's array - coin_c: address = self.coins[_coina].swap_for[coina_arr_last_idx] - # get the bitwise_xor of the pair to retrieve their indexes - key: uint256 = bitwise_xor(convert(_coina, uint256), convert(coin_c, uint256)) - indexes: uint256 = self.coin_swap_indexes[key] - - # update the pairing's indexes - if convert(_coina, uint256) < convert(coin_c, uint256): - # least complicated most readable way of shifting twice to remove the lower order bits - self.coin_swap_indexes[key] = shift(shift(indexes, -128), 128) + _coinb_idx - else: - self.coin_swap_indexes[key] = shift(_coinb_idx, 128) + indexes % 2 ** 128 - # set _coinb_idx in coina's array to coin_c - self.coins[_coina].swap_for[_coinb_idx] = coin_c - - self.coins[_coina].swap_for[coina_arr_last_idx] = ZERO_ADDRESS - - -@internal -def _get_new_pool_coins( - _pool: address, - _n_coins: uint256, -) -> address[MAX_COINS]: - coin_list: address[MAX_COINS] = empty(address[MAX_COINS]) - coin: address = ZERO_ADDRESS - for i in range(MAX_COINS): - if i == _n_coins: - break - coin = CurvePool(_pool).coins(i) - self.pool_data[_pool].coins[i] = coin - coin_list[i] = coin - - for i in range(MAX_COINS): - if i == _n_coins: - break - - self._register_coin(coin_list[i]) - # add pool to markets - i2: uint256 = i + 1 - for x in range(i2, i2 + MAX_COINS): - if x == _n_coins: - break - - key: uint256 = bitwise_xor(convert(coin_list[i], uint256), convert(coin_list[x], uint256)) - length: uint256 = self.market_counts[key] - self.markets[key][length] = _pool - self.market_counts[key] = length + 1 - - # register the coin pair - if length == 0: - self._register_coin_pair(coin_list[x], coin_list[i], key) - - return coin_list - - -@view -@internal -def _get_new_pool_decimals(_coins: address[MAX_COINS], _n_coins: uint256) -> uint256: - packed: uint256 = 0 - value: uint256 = 0 - - n_coins: int128 = convert(_n_coins, int128) - for i in range(MAX_COINS): - if i == n_coins: - break - coin: address = _coins[i] - if coin == 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE: - value = 18 - else: - value = ERC20(coin).decimals() - assert value < 256 # dev: decimal overflow - - packed += shift(value, i * 8) - - return packed - - -@internal -def _remove_market(_pool: address, _coina: address, _coinb: address): - key: uint256 = bitwise_xor(convert(_coina, uint256), convert(_coinb, uint256)) - length: uint256 = self.market_counts[key] - 1 - if length == 0: - indexes: uint256 = self.coin_swap_indexes[key] - if convert(_coina, uint256) < convert(_coinb, uint256): - self._unregister_coin_pair(_coina, _coinb, indexes % 2 ** 128) - self._unregister_coin_pair(_coinb, _coina, shift(indexes, -128)) - else: - self._unregister_coin_pair(_coina, _coinb, shift(indexes, -128)) - self._unregister_coin_pair(_coinb, _coina, indexes % 2 ** 128) - self.coin_swap_indexes[key] = 0 - for i in range(65536): - if i > length: - break - if self.markets[key][i] == _pool: - if i < length: - self.markets[key][i] = self.markets[key][length] - self.markets[key][length] = ZERO_ADDRESS - self.market_counts[key] = length - break - - -# admin functions - -@external -def add_pool( - _pool: address, - _n_coins: uint256, - _lp_token: address, - _gauge: address, - _zap: address, - _decimals: uint256, - _name: String[64], -): - """ - @notice Add a pool to the registry - @dev Only callable by admin - @param _pool Pool address to add - @param _n_coins Number of coins in the pool - @param _lp_token Pool deposit token address - @param _decimals Coin decimal values, tightly packed as uint8 in a little-endian bytes32 - @param _name The name of the pool - """ - assert msg.sender == self.address_provider.admin() # dev: admin-only function - assert _lp_token != ZERO_ADDRESS - assert self.pool_data[_pool].coins[0] == ZERO_ADDRESS # dev: pool exists - assert self.get_pool_from_lp_token[_lp_token] == ZERO_ADDRESS - - # add pool to pool_list - length: uint256 = self.pool_count - self.pool_list[length] = _pool - self.pool_count = length + 1 - self.pool_data[_pool].location = length - self.pool_data[_pool].n_coins = _n_coins - self.pool_data[_pool].name = _name - - # update public mappings - self.get_pool_from_lp_token[_lp_token] = _pool - self.get_lp_token[_pool] = _lp_token - - coins: address[MAX_COINS] = self._get_new_pool_coins(_pool, _n_coins) - decimals: uint256 = _decimals - if decimals == 0: - decimals = self._get_new_pool_decimals(coins, _n_coins) - self.pool_data[_pool].decimals = decimals - - if _zap != ZERO_ADDRESS: - self.get_zap[_pool] = _zap - - if _gauge != ZERO_ADDRESS: - self.liquidity_gauges[_pool][0] = _gauge - - self.last_updated = block.timestamp - log PoolAdded(_pool) - - -@external -def remove_pool(_pool: address): - """ - @notice Remove a pool to the registry - @dev Only callable by admin - @param _pool Pool address to remove - """ - assert msg.sender == self.address_provider.admin() # dev: admin-only function - assert self.pool_data[_pool].coins[0] != ZERO_ADDRESS # dev: pool does not exist - - self.get_pool_from_lp_token[self.get_lp_token[_pool]] = ZERO_ADDRESS - self.get_lp_token[_pool] = ZERO_ADDRESS - - # remove _pool from pool_list - location: uint256 = self.pool_data[_pool].location - length: uint256 = self.pool_count - 1 - - if location < length: - # replace _pool with final value in pool_list - addr: address = self.pool_list[length] - self.pool_list[location] = addr - self.pool_data[addr].location = location - - # delete final pool_list value - self.pool_list[length] = ZERO_ADDRESS - self.pool_count = length - - self.pool_data[_pool].decimals = 0 - self.pool_data[_pool].n_coins = 0 - self.pool_data[_pool].name = "" - - coins: address[MAX_COINS] = empty(address[MAX_COINS]) - - for i in range(MAX_COINS): - coins[i] = self.pool_data[_pool].coins[i] - if coins[i] == ZERO_ADDRESS: - break - # delete coin address from pool_data - self.pool_data[_pool].coins[i] = ZERO_ADDRESS - self._unregister_coin(coins[i]) - - for i in range(MAX_COINS): - coin: address = coins[i] - if coin == ZERO_ADDRESS: - break - - # remove pool from markets - i2: uint256 = i + 1 - for x in range(i2, i2 + MAX_COINS): - coinx: address = coins[x] - if coinx == ZERO_ADDRESS: - break - self._remove_market(_pool, coin, coinx) - - if self.get_zap[_pool] != ZERO_ADDRESS: - self.get_zap[_pool] = ZERO_ADDRESS - - self.last_updated = block.timestamp - log PoolRemoved(_pool) - - -@external -def set_liquidity_gauges(_pool: address, _liquidity_gauges: address[10]): - """ - @notice Set liquidity gauge contracts - @param _pool Pool address - @param _liquidity_gauges Liquidity gauge address - """ - assert msg.sender == self.address_provider.admin() # dev: admin-only function - - _lp_token: address = self.get_lp_token[_pool] - for i in range(10): - _gauge: address = _liquidity_gauges[i] - if _gauge != ZERO_ADDRESS: - assert LiquidityGauge(_gauge).lp_token() == _lp_token # dev: wrong token - self.liquidity_gauges[_pool][i] = _gauge - elif self.liquidity_gauges[_pool][i] != ZERO_ADDRESS: - self.liquidity_gauges[_pool][i] = ZERO_ADDRESS - else: - break - self.last_updated = block.timestamp - - -@external -def batch_set_liquidity_gauges(_pools: address[10], _liquidity_gauges: address[10]): - """ - @notice Set many liquidity gauge contracts - @param _pools List of pool addresses - @param _liquidity_gauges List of liquidity gauge addresses - """ - assert msg.sender == self.address_provider.admin() # dev: admin-only function - - for i in range(10): - _pool: address = _pools[i] - if _pool == ZERO_ADDRESS: - break - _gauge: address = _liquidity_gauges[i] - assert LiquidityGauge(_gauge).lp_token() == self.get_lp_token[_pool] # dev: wrong token - self.liquidity_gauges[_pool][0] = _gauge - - self.last_updated = block.timestamp diff --git a/contracts/mainnet/mocks/GaugeController.vy b/contracts/mainnet/mocks/GaugeController.vy deleted file mode 100644 index 576f498..0000000 --- a/contracts/mainnet/mocks/GaugeController.vy +++ /dev/null @@ -1,596 +0,0 @@ -# @version 0.2.4 - -""" -@title Gauge Controller -@author Curve Finance -@license MIT -@notice Controls liquidity gauges and the issuance of coins through the gauges -""" - -# 7 * 86400 seconds - all future times are rounded by week -WEEK: constant(uint256) = 604800 - -# Cannot change weight votes more often than once in 10 days -WEIGHT_VOTE_DELAY: constant(uint256) = 10 * 86400 - - -struct Point: - bias: uint256 - slope: uint256 - -struct VotedSlope: - slope: uint256 - power: uint256 - end: uint256 - - -interface VotingEscrow: - def get_last_user_slope(addr: address) -> int128: view - def locked__end(addr: address) -> uint256: view - - -event CommitOwnership: - admin: address - -event ApplyOwnership: - admin: address - -event AddType: - name: String[64] - type_id: int128 - -event NewTypeWeight: - type_id: int128 - time: uint256 - weight: uint256 - total_weight: uint256 - -event NewGaugeWeight: - gauge_address: address - time: uint256 - weight: uint256 - total_weight: uint256 - -event VoteForGauge: - time: uint256 - user: address - gauge_addr: address - weight: uint256 - -event NewGauge: - addr: address - gauge_type: int128 - weight: uint256 - - -MULTIPLIER: constant(uint256) = 10 ** 18 - -admin: public(address) # Can and will be a smart contract -future_admin: public(address) # Can and will be a smart contract - -token: public(address) # CRV token -voting_escrow: public(address) # Voting escrow - -# Gauge parameters -# All numbers are "fixed point" on the basis of 1e18 -n_gauge_types: public(int128) -n_gauges: public(int128) -gauge_type_names: public(HashMap[int128, String[64]]) - -# Needed for enumeration -gauges: public(address[1000000000]) - -# we increment values by 1 prior to storing them here so we can rely on a value -# of zero as meaning the gauge has not been set -gauge_types_: HashMap[address, int128] - -vote_user_slopes: public(HashMap[address, HashMap[address, VotedSlope]]) # user -> gauge_addr -> VotedSlope -vote_user_power: public(HashMap[address, uint256]) # Total vote power used by user -last_user_vote: public(HashMap[address, HashMap[address, uint256]]) # Last user vote's timestamp for each gauge address - -# Past and scheduled points for gauge weight, sum of weights per type, total weight -# Point is for bias+slope -# changes_* are for changes in slope -# time_* are for the last change timestamp -# timestamps are rounded to whole weeks - -points_weight: public(HashMap[address, HashMap[uint256, Point]]) # gauge_addr -> time -> Point -changes_weight: HashMap[address, HashMap[uint256, uint256]] # gauge_addr -> time -> slope -time_weight: public(HashMap[address, uint256]) # gauge_addr -> last scheduled time (next week) - -points_sum: public(HashMap[int128, HashMap[uint256, Point]]) # type_id -> time -> Point -changes_sum: HashMap[int128, HashMap[uint256, uint256]] # type_id -> time -> slope -time_sum: public(uint256[1000000000]) # type_id -> last scheduled time (next week) - -points_total: public(HashMap[uint256, uint256]) # time -> total weight -time_total: public(uint256) # last scheduled time - -points_type_weight: public(HashMap[int128, HashMap[uint256, uint256]]) # type_id -> time -> type weight -time_type_weight: public(uint256[1000000000]) # type_id -> last scheduled time (next week) - - -@external -def __init__(_token: address, _voting_escrow: address): - """ - @notice Contract constructor - @param _token `ERC20CRV` contract address - @param _voting_escrow `VotingEscrow` contract address - """ - assert _token != ZERO_ADDRESS - assert _voting_escrow != ZERO_ADDRESS - - self.admin = msg.sender - self.token = _token - self.voting_escrow = _voting_escrow - self.time_total = block.timestamp / WEEK * WEEK - - -@external -def commit_transfer_ownership(addr: address): - """ - @notice Transfer ownership of GaugeController to `addr` - @param addr Address to have ownership transferred to - """ - assert msg.sender == self.admin # dev: admin only - self.future_admin = addr - log CommitOwnership(addr) - - -@external -def apply_transfer_ownership(): - """ - @notice Apply pending ownership transfer - """ - assert msg.sender == self.admin # dev: admin only - _admin: address = self.future_admin - assert _admin != ZERO_ADDRESS # dev: admin not set - self.admin = _admin - log ApplyOwnership(_admin) - - -@external -@view -def gauge_types(_addr: address) -> int128: - """ - @notice Get gauge type for address - @param _addr Gauge address - @return Gauge type id - """ - gauge_type: int128 = self.gauge_types_[_addr] - assert gauge_type != 0 - - return gauge_type - 1 - - -@internal -def _get_type_weight(gauge_type: int128) -> uint256: - """ - @notice Fill historic type weights week-over-week for missed checkins - and return the type weight for the future week - @param gauge_type Gauge type id - @return Type weight - """ - t: uint256 = self.time_type_weight[gauge_type] - if t > 0: - w: uint256 = self.points_type_weight[gauge_type][t] - for i in range(500): - if t > block.timestamp: - break - t += WEEK - self.points_type_weight[gauge_type][t] = w - if t > block.timestamp: - self.time_type_weight[gauge_type] = t - return w - else: - return 0 - - -@internal -def _get_sum(gauge_type: int128) -> uint256: - """ - @notice Fill sum of gauge weights for the same type week-over-week for - missed checkins and return the sum for the future week - @param gauge_type Gauge type id - @return Sum of weights - """ - t: uint256 = self.time_sum[gauge_type] - if t > 0: - pt: Point = self.points_sum[gauge_type][t] - for i in range(500): - if t > block.timestamp: - break - t += WEEK - d_bias: uint256 = pt.slope * WEEK - if pt.bias > d_bias: - pt.bias -= d_bias - d_slope: uint256 = self.changes_sum[gauge_type][t] - pt.slope -= d_slope - else: - pt.bias = 0 - pt.slope = 0 - self.points_sum[gauge_type][t] = pt - if t > block.timestamp: - self.time_sum[gauge_type] = t - return pt.bias - else: - return 0 - - -@internal -def _get_total() -> uint256: - """ - @notice Fill historic total weights week-over-week for missed checkins - and return the total for the future week - @return Total weight - """ - t: uint256 = self.time_total - _n_gauge_types: int128 = self.n_gauge_types - if t > block.timestamp: - # If we have already checkpointed - still need to change the value - t -= WEEK - pt: uint256 = self.points_total[t] - - for gauge_type in range(100): - if gauge_type == _n_gauge_types: - break - self._get_sum(gauge_type) - self._get_type_weight(gauge_type) - - for i in range(500): - if t > block.timestamp: - break - t += WEEK - pt = 0 - # Scales as n_types * n_unchecked_weeks (hopefully 1 at most) - for gauge_type in range(100): - if gauge_type == _n_gauge_types: - break - type_sum: uint256 = self.points_sum[gauge_type][t].bias - type_weight: uint256 = self.points_type_weight[gauge_type][t] - pt += type_sum * type_weight - self.points_total[t] = pt - - if t > block.timestamp: - self.time_total = t - return pt - - -@internal -def _get_weight(gauge_addr: address) -> uint256: - """ - @notice Fill historic gauge weights week-over-week for missed checkins - and return the total for the future week - @param gauge_addr Address of the gauge - @return Gauge weight - """ - t: uint256 = self.time_weight[gauge_addr] - if t > 0: - pt: Point = self.points_weight[gauge_addr][t] - for i in range(500): - if t > block.timestamp: - break - t += WEEK - d_bias: uint256 = pt.slope * WEEK - if pt.bias > d_bias: - pt.bias -= d_bias - d_slope: uint256 = self.changes_weight[gauge_addr][t] - pt.slope -= d_slope - else: - pt.bias = 0 - pt.slope = 0 - self.points_weight[gauge_addr][t] = pt - if t > block.timestamp: - self.time_weight[gauge_addr] = t - return pt.bias - else: - return 0 - - -@external -def add_gauge(addr: address, gauge_type: int128, weight: uint256 = 0): - """ - @notice Add gauge `addr` of type `gauge_type` with weight `weight` - @param addr Gauge address - @param gauge_type Gauge type - @param weight Gauge weight - """ - assert msg.sender == self.admin - assert (gauge_type >= 0) and (gauge_type < self.n_gauge_types) - assert self.gauge_types_[addr] == 0 # dev: cannot add the same gauge twice - - n: int128 = self.n_gauges - self.n_gauges = n + 1 - self.gauges[n] = addr - - self.gauge_types_[addr] = gauge_type + 1 - next_time: uint256 = (block.timestamp + WEEK) / WEEK * WEEK - - if weight > 0: - _type_weight: uint256 = self._get_type_weight(gauge_type) - _old_sum: uint256 = self._get_sum(gauge_type) - _old_total: uint256 = self._get_total() - - self.points_sum[gauge_type][next_time].bias = weight + _old_sum - self.time_sum[gauge_type] = next_time - self.points_total[next_time] = _old_total + _type_weight * weight - self.time_total = next_time - - self.points_weight[addr][next_time].bias = weight - - if self.time_sum[gauge_type] == 0: - self.time_sum[gauge_type] = next_time - self.time_weight[addr] = next_time - - log NewGauge(addr, gauge_type, weight) - - -@external -def checkpoint(): - """ - @notice Checkpoint to fill data common for all gauges - """ - self._get_total() - - -@external -def checkpoint_gauge(addr: address): - """ - @notice Checkpoint to fill data for both a specific gauge and common for all gauges - @param addr Gauge address - """ - self._get_weight(addr) - self._get_total() - - -@internal -@view -def _gauge_relative_weight(addr: address, time: uint256) -> uint256: - """ - @notice Get Gauge relative weight (not more than 1.0) normalized to 1e18 - (e.g. 1.0 == 1e18). Inflation which will be received by it is - inflation_rate * relative_weight / 1e18 - @param addr Gauge address - @param time Relative weight at the specified timestamp in the past or present - @return Value of relative weight normalized to 1e18 - """ - t: uint256 = time / WEEK * WEEK - _total_weight: uint256 = self.points_total[t] - - if _total_weight > 0: - gauge_type: int128 = self.gauge_types_[addr] - 1 - _type_weight: uint256 = self.points_type_weight[gauge_type][t] - _gauge_weight: uint256 = self.points_weight[addr][t].bias - return MULTIPLIER * _type_weight * _gauge_weight / _total_weight - - else: - return 0 - - -@external -@view -def gauge_relative_weight(addr: address, time: uint256 = block.timestamp) -> uint256: - """ - @notice Get Gauge relative weight (not more than 1.0) normalized to 1e18 - (e.g. 1.0 == 1e18). Inflation which will be received by it is - inflation_rate * relative_weight / 1e18 - @param addr Gauge address - @param time Relative weight at the specified timestamp in the past or present - @return Value of relative weight normalized to 1e18 - """ - return self._gauge_relative_weight(addr, time) - - -@external -def gauge_relative_weight_write(addr: address, time: uint256 = block.timestamp) -> uint256: - """ - @notice Get gauge weight normalized to 1e18 and also fill all the unfilled - values for type and gauge records - @dev Any address can call, however nothing is recorded if the values are filled already - @param addr Gauge address - @param time Relative weight at the specified timestamp in the past or present - @return Value of relative weight normalized to 1e18 - """ - self._get_weight(addr) - self._get_total() # Also calculates get_sum - return self._gauge_relative_weight(addr, time) - - - - -@internal -def _change_type_weight(type_id: int128, weight: uint256): - """ - @notice Change type weight - @param type_id Type id - @param weight New type weight - """ - old_weight: uint256 = self._get_type_weight(type_id) - old_sum: uint256 = self._get_sum(type_id) - _total_weight: uint256 = self._get_total() - next_time: uint256 = (block.timestamp + WEEK) / WEEK * WEEK - - _total_weight = _total_weight + old_sum * weight - old_sum * old_weight - self.points_total[next_time] = _total_weight - self.points_type_weight[type_id][next_time] = weight - self.time_total = next_time - self.time_type_weight[type_id] = next_time - - log NewTypeWeight(type_id, next_time, weight, _total_weight) - - -@external -def add_type(_name: String[64], weight: uint256 = 0): - """ - @notice Add gauge type with name `_name` and weight `weight` - @param _name Name of gauge type - @param weight Weight of gauge type - """ - assert msg.sender == self.admin - type_id: int128 = self.n_gauge_types - self.gauge_type_names[type_id] = _name - self.n_gauge_types = type_id + 1 - if weight != 0: - self._change_type_weight(type_id, weight) - log AddType(_name, type_id) - - -@external -def change_type_weight(type_id: int128, weight: uint256): - """ - @notice Change gauge type `type_id` weight to `weight` - @param type_id Gauge type id - @param weight New Gauge weight - """ - assert msg.sender == self.admin - self._change_type_weight(type_id, weight) - - -@internal -def _change_gauge_weight(addr: address, weight: uint256): - # Change gauge weight - # Only needed when testing in reality - gauge_type: int128 = self.gauge_types_[addr] - 1 - old_gauge_weight: uint256 = self._get_weight(addr) - type_weight: uint256 = self._get_type_weight(gauge_type) - old_sum: uint256 = self._get_sum(gauge_type) - _total_weight: uint256 = self._get_total() - next_time: uint256 = (block.timestamp + WEEK) / WEEK * WEEK - - self.points_weight[addr][next_time].bias = weight - self.time_weight[addr] = next_time - - new_sum: uint256 = old_sum + weight - old_gauge_weight - self.points_sum[gauge_type][next_time].bias = new_sum - self.time_sum[gauge_type] = next_time - - _total_weight = _total_weight + new_sum * type_weight - old_sum * type_weight - self.points_total[next_time] = _total_weight - self.time_total = next_time - - log NewGaugeWeight(addr, block.timestamp, weight, _total_weight) - - -@external -def change_gauge_weight(addr: address, weight: uint256): - """ - @notice Change weight of gauge `addr` to `weight` - @param addr `GaugeController` contract address - @param weight New Gauge weight - """ - assert msg.sender == self.admin - self._change_gauge_weight(addr, weight) - - -@external -def vote_for_gauge_weights(_gauge_addr: address, _user_weight: uint256): - """ - @notice Allocate voting power for changing pool weights - @param _gauge_addr Gauge which `msg.sender` votes for - @param _user_weight Weight for a gauge in bps (units of 0.01%). Minimal is 0.01%. Ignored if 0 - """ - escrow: address = self.voting_escrow - slope: uint256 = convert(VotingEscrow(escrow).get_last_user_slope(msg.sender), uint256) - lock_end: uint256 = VotingEscrow(escrow).locked__end(msg.sender) - _n_gauges: int128 = self.n_gauges - next_time: uint256 = (block.timestamp + WEEK) / WEEK * WEEK - assert lock_end > next_time, "Your token lock expires too soon" - assert (_user_weight >= 0) and (_user_weight <= 10000), "You used all your voting power" - assert block.timestamp >= self.last_user_vote[msg.sender][_gauge_addr] + WEIGHT_VOTE_DELAY, "Cannot vote so often" - - gauge_type: int128 = self.gauge_types_[_gauge_addr] - 1 - assert gauge_type >= 0, "Gauge not added" - # Prepare slopes and biases in memory - old_slope: VotedSlope = self.vote_user_slopes[msg.sender][_gauge_addr] - old_dt: uint256 = 0 - if old_slope.end > next_time: - old_dt = old_slope.end - next_time - old_bias: uint256 = old_slope.slope * old_dt - new_slope: VotedSlope = VotedSlope({ - slope: slope * _user_weight / 10000, - end: lock_end, - power: _user_weight - }) - new_dt: uint256 = lock_end - next_time # dev: raises when expired - new_bias: uint256 = new_slope.slope * new_dt - - # Check and update powers (weights) used - power_used: uint256 = self.vote_user_power[msg.sender] - power_used = power_used + new_slope.power - old_slope.power - self.vote_user_power[msg.sender] = power_used - assert (power_used >= 0) and (power_used <= 10000), 'Used too much power' - - ## Remove old and schedule new slope changes - # Remove slope changes for old slopes - # Schedule recording of initial slope for next_time - old_weight_bias: uint256 = self._get_weight(_gauge_addr) - old_weight_slope: uint256 = self.points_weight[_gauge_addr][next_time].slope - old_sum_bias: uint256 = self._get_sum(gauge_type) - old_sum_slope: uint256 = self.points_sum[gauge_type][next_time].slope - - self.points_weight[_gauge_addr][next_time].bias = max(old_weight_bias + new_bias, old_bias) - old_bias - self.points_sum[gauge_type][next_time].bias = max(old_sum_bias + new_bias, old_bias) - old_bias - if old_slope.end > next_time: - self.points_weight[_gauge_addr][next_time].slope = max(old_weight_slope + new_slope.slope, old_slope.slope) - old_slope.slope - self.points_sum[gauge_type][next_time].slope = max(old_sum_slope + new_slope.slope, old_slope.slope) - old_slope.slope - else: - self.points_weight[_gauge_addr][next_time].slope += new_slope.slope - self.points_sum[gauge_type][next_time].slope += new_slope.slope - if old_slope.end > block.timestamp: - # Cancel old slope changes if they still didn't happen - self.changes_weight[_gauge_addr][old_slope.end] -= old_slope.slope - self.changes_sum[gauge_type][old_slope.end] -= old_slope.slope - # Add slope changes for new slopes - self.changes_weight[_gauge_addr][new_slope.end] += new_slope.slope - self.changes_sum[gauge_type][new_slope.end] += new_slope.slope - - self._get_total() - - self.vote_user_slopes[msg.sender][_gauge_addr] = new_slope - - # Record last action time - self.last_user_vote[msg.sender][_gauge_addr] = block.timestamp - - log VoteForGauge(block.timestamp, msg.sender, _gauge_addr, _user_weight) - - -@external -@view -def get_gauge_weight(addr: address) -> uint256: - """ - @notice Get current gauge weight - @param addr Gauge address - @return Gauge weight - """ - return self.points_weight[addr][self.time_weight[addr]].bias - - -@external -@view -def get_type_weight(type_id: int128) -> uint256: - """ - @notice Get current type weight - @param type_id Type id - @return Type weight - """ - return self.points_type_weight[type_id][self.time_type_weight[type_id]] - - -@external -@view -def get_total_weight() -> uint256: - """ - @notice Get current total (type-weighted) weight - @return Total weight - """ - return self.points_total[self.time_total] - - -@external -@view -def get_weights_sum_per_type(type_id: int128) -> uint256: - """ - @notice Get sum of gauge weights per type - @param type_id Type id - @return Sum of gauge weights - """ - return self.points_sum[type_id][self.time_sum[type_id]].bias diff --git a/contracts/mainnet/mocks/ProxyAdmin.vy b/contracts/mainnet/mocks/ProxyAdmin.vy deleted file mode 100644 index df57810..0000000 --- a/contracts/mainnet/mocks/ProxyAdmin.vy +++ /dev/null @@ -1,155 +0,0 @@ -# @version 0.2.11 -""" -@title ProxyAdmin -@notice Thin proxy allowing shared ownership of contracts -@author Ben Hauser -@license MIT -""" - - -event TransactionExecuted: - admin: indexed(address) - target: indexed(address) - calldata: Bytes[100000] - value: uint256 - -event RequestAdminChange: - current_admin: address - future_admin: address - -event RevokeAdminChange: - current_admin: address - future_admin: address - calling_admin: address - -event ApproveAdminChange: - current_admin: address - future_admin: address - calling_admin: address - -event AcceptAdminChange: - previous_admin: address - current_admin: address - - -admins: public(address[2]) - -pending_current_admin: uint256 -pending_new_admin: address -change_approved: bool - - -@external -def __init__(_authorized: address[2]): - """ - @notice Contract constructor - @param _authorized Admin accounts for this contract - """ - self.admins = _authorized - - -@payable -@external -def execute(_target: address, _calldata: Bytes[100000]): - """ - @notice Execute a contract call - @dev Ether sent when calling this function is forwarded onward - @param _target Address of the contract to call - @param _calldata Calldata to use in the call - """ - assert msg.sender in self.admins # dev: only admin - - raw_call(_target, _calldata, value=msg.value) - log TransactionExecuted(msg.sender, _target, _calldata, msg.value) - - -@view -@external -def get_admin_change_status() -> (address, address, bool): - """ - @notice Get information about a pending admin change - @return Admin address to be replaced, - admin address to be added, - has change been approved? - """ - idx: uint256 = self.pending_current_admin - if idx == 0: - return ZERO_ADDRESS, ZERO_ADDRESS, False - else: - return self.admins[idx - 1], self.pending_new_admin, self.change_approved - - -@external -def request_admin_change(_new_admin: address): - """ - @notice Initiate changing an admin address - @param _new_admin New admin address (replaces msg.sender) - """ - assert self.pending_current_admin == 0 # dev: already an active request - - admin_list: address[2] = self.admins - assert _new_admin not in admin_list # dev: new admin is already admin - - for i in range(2): - if admin_list[i] == msg.sender: - self.pending_current_admin = i + 1 - self.pending_new_admin = _new_admin - log RequestAdminChange(msg.sender, _new_admin) - return - - raise # dev: only admin - - -@external -def approve_admin_change(): - """ - @notice Approve changing an admin address - @dev Only callable by the 2nd admin address (the one that will not change) - """ - idx: uint256 = self.pending_current_admin - - assert idx > 0 # dev: no active request - assert msg.sender == self.admins[idx % 2] # dev: caller is not 2nd admin - - self.change_approved = True - log ApproveAdminChange(self.admins[idx - 1], self.pending_new_admin, msg.sender) - - -@external -def revoke_admin_change(): - """ - @notice Revoke changing an admin address - @dev May be called by either admin at any time to reset the process, - even if approval has previous been given - """ - assert msg.sender in self.admins # dev: only admin - - idx: uint256 = self.pending_current_admin - pending_admin: address = ZERO_ADDRESS - if idx > 0: - pending_admin = self.admins[idx - 1] - - log RevokeAdminChange(pending_admin, self.pending_new_admin, msg.sender) - - self.pending_current_admin = 0 - self.pending_new_admin = ZERO_ADDRESS - self.change_approved = False - - - -@external -def accept_admin_change(): - """ - @notice Accept a changed admin address - @dev Only callable by the new admin address, after approval has been given - """ - assert self.change_approved == True # dev: change not approved - assert msg.sender == self.pending_new_admin # dev: only new admin - - idx: uint256 = self.pending_current_admin - 1 - log AcceptAdminChange(self.admins[idx], msg.sender) - self.admins[idx] = msg.sender - - self.pending_current_admin = 0 - self.pending_new_admin = ZERO_ADDRESS - self.change_approved = False diff --git a/contracts/mainnet/mocks/StableFactory.vy b/contracts/mainnet/mocks/StableFactory.vy deleted file mode 100644 index 4616ae4..0000000 --- a/contracts/mainnet/mocks/StableFactory.vy +++ /dev/null @@ -1,955 +0,0 @@ -# @version 0.2.15 -""" -@title Curve Factory -@license MIT -@author Curve.Fi -@notice Permissionless pool deployer and registry -""" - -struct PoolArray: - base_pool: address - implementation: address - liquidity_gauge: address - coins: address[MAX_PLAIN_COINS] - decimals: uint256[MAX_PLAIN_COINS] - n_coins: uint256 - asset_type: uint256 - -struct BasePoolArray: - implementations: address[10] - lp_token: address - fee_receiver: address - coins: address[MAX_COINS] - decimals: uint256 - n_coins: uint256 - asset_type: uint256 - - -interface AddressProvider: - def admin() -> address: view - def get_registry() -> address: view - -interface Registry: - def get_lp_token(pool: address) -> address: view - def get_n_coins(pool: address) -> uint256: view - def get_coins(pool: address) -> address[MAX_COINS]: view - def get_pool_from_lp_token(lp_token: address) -> address: view - -interface ERC20: - def balanceOf(_addr: address) -> uint256: view - def decimals() -> uint256: view - def totalSupply() -> uint256: view - def approve(_spender: address, _amount: uint256): nonpayable - -interface CurvePlainPool: - def initialize( - _name: String[32], - _symbol: String[10], - _coins: address[4], - _rate_multipliers: uint256[4], - _A: uint256, - _fee: uint256, - ): nonpayable - -interface CurvePool: - def A() -> uint256: view - def fee() -> uint256: view - def admin_fee() -> uint256: view - def balances(i: uint256) -> uint256: view - def admin_balances(i: uint256) -> uint256: view - def get_virtual_price() -> uint256: view - def initialize( - _name: String[32], - _symbol: String[10], - _coin: address, - _rate_multiplier: uint256, - _A: uint256, - _fee: uint256, - ): nonpayable - def exchange( - i: int128, - j: int128, - dx: uint256, - min_dy: uint256, - _receiver: address, - ) -> uint256: nonpayable - -interface CurveFactoryMetapool: - def coins(i :uint256) -> address: view - def decimals() -> uint256: view - -interface OldFactory: - def get_coins(_pool: address) -> address[2]: view - -interface LiquidityGauge: - def initialize(_lp_token: address): nonpayable - - -event BasePoolAdded: - base_pool: address - -event PlainPoolDeployed: - coins: address[MAX_PLAIN_COINS] - A: uint256 - fee: uint256 - deployer: address - -event MetaPoolDeployed: - coin: address - base_pool: address - A: uint256 - fee: uint256 - deployer: address - -event LiquidityGaugeDeployed: - pool: address - gauge: address - - -MAX_COINS: constant(int128) = 8 -MAX_PLAIN_COINS: constant(int128) = 4 # max coins in a plain pool -ADDRESS_PROVIDER: constant(address) = 0x0000000022D53366457F9d5E68Ec105046FC4383 -OLD_FACTORY: constant(address) = 0x0959158b6040D32d04c301A72CBFD6b39E21c9AE - -admin: public(address) -future_admin: public(address) -manager: public(address) - -pool_list: public(address[4294967296]) # master list of pools -pool_count: public(uint256) # actual length of pool_list -pool_data: HashMap[address, PoolArray] - -base_pool_list: public(address[4294967296]) # master list of pools -base_pool_count: public(uint256) # actual length of pool_list -base_pool_data: HashMap[address, BasePoolArray] - -# asset -> is used in a metapool? -base_pool_assets: public(HashMap[address, bool]) - -# number of coins -> implementation addresses -# for "plain pools" (as opposed to metapools), implementation contracts -# are organized according to the number of coins in the pool -plain_implementations: public(HashMap[uint256, address[10]]) - -# fee receiver for plain pools -fee_receiver: address - -gauge_implementation: public(address) - -# mapping of coins -> pools for trading -# a mapping key is generated for each pair of addresses via -# `bitwise_xor(convert(a, uint256), convert(b, uint256))` -markets: HashMap[uint256, address[4294967296]] -market_counts: HashMap[uint256, uint256] - - -@external -def __init__(_fee_receiver: address): - self.admin = msg.sender - self.manager = msg.sender - self.fee_receiver = _fee_receiver - - -# <--- Factory Getters ---> - -@view -@external -def metapool_implementations(_base_pool: address) -> address[10]: - """ - @notice Get a list of implementation contracts for metapools targetting the given base pool - @dev A base pool is the pool for the LP token contained within the metapool - @param _base_pool Address of the base pool - @return List of implementation contract addresses - """ - return self.base_pool_data[_base_pool].implementations - - -@view -@external -def find_pool_for_coins(_from: address, _to: address, i: uint256 = 0) -> address: - """ - @notice Find an available pool for exchanging two coins - @param _from Address of coin to be sent - @param _to Address of coin to be received - @param i Index value. When multiple pools are available - this value is used to return the n'th address. - @return Pool address - """ - key: uint256 = bitwise_xor(convert(_from, uint256), convert(_to, uint256)) - return self.markets[key][i] - - -# <--- Pool Getters ---> - -@view -@external -def get_base_pool(_pool: address) -> address: - """ - @notice Get the base pool for a given factory metapool - @param _pool Metapool address - @return Address of base pool - """ - return self.pool_data[_pool].base_pool - - -@view -@external -def get_n_coins(_pool: address) -> (uint256): - """ - @notice Get the number of coins in a pool - @param _pool Pool address - @return Number of coins - """ - return self.pool_data[_pool].n_coins - - -@view -@external -def get_meta_n_coins(_pool: address) -> (uint256, uint256): - """ - @notice Get the number of coins in a metapool - @param _pool Pool address - @return Number of wrapped coins, number of underlying coins - """ - base_pool: address = self.pool_data[_pool].base_pool - return 2, self.base_pool_data[base_pool].n_coins + 1 - - -@view -@external -def get_coins(_pool: address) -> address[MAX_PLAIN_COINS]: - """ - @notice Get the coins within a pool - @param _pool Pool address - @return List of coin addresses - """ - return self.pool_data[_pool].coins - - -@view -@external -def get_underlying_coins(_pool: address) -> address[MAX_COINS]: - """ - @notice Get the underlying coins within a pool - @dev Reverts if a pool does not exist or is not a metapool - @param _pool Pool address - @return List of coin addresses - """ - coins: address[MAX_COINS] = empty(address[MAX_COINS]) - base_pool: address = self.pool_data[_pool].base_pool - assert base_pool != ZERO_ADDRESS # dev: pool is not metapool - coins[0] = self.pool_data[_pool].coins[0] - for i in range(1, MAX_COINS): - coins[i] = self.base_pool_data[base_pool].coins[i - 1] - if coins[i] == ZERO_ADDRESS: - break - - return coins - - -@view -@external -def get_decimals(_pool: address) -> uint256[MAX_PLAIN_COINS]: - """ - @notice Get decimal places for each coin within a pool - @param _pool Pool address - @return uint256 list of decimals - """ - if self.pool_data[_pool].base_pool != ZERO_ADDRESS: - decimals: uint256[MAX_PLAIN_COINS] = empty(uint256[MAX_PLAIN_COINS]) - decimals = self.pool_data[_pool].decimals - decimals[1] = 18 - return decimals - return self.pool_data[_pool].decimals - - -@view -@external -def get_underlying_decimals(_pool: address) -> uint256[MAX_COINS]: - """ - @notice Get decimal places for each underlying coin within a pool - @param _pool Pool address - @return uint256 list of decimals - """ - # decimals are tightly packed as a series of uint8 within a little-endian bytes32 - # the packed value is stored as uint256 to simplify unpacking via shift and modulo - pool_decimals: uint256[MAX_PLAIN_COINS] = empty(uint256[MAX_PLAIN_COINS]) - pool_decimals = self.pool_data[_pool].decimals - decimals: uint256[MAX_COINS] = empty(uint256[MAX_COINS]) - decimals[0] = pool_decimals[0] - base_pool: address = self.pool_data[_pool].base_pool - packed_decimals: uint256 = self.base_pool_data[base_pool].decimals - for i in range(MAX_COINS): - unpacked: uint256 = shift(packed_decimals, -8 * i) % 256 - if unpacked == 0: - break - decimals[i+1] = unpacked - - return decimals - - -@view -@external -def get_metapool_rates(_pool: address) -> uint256[2]: - """ - @notice Get rates for coins within a metapool - @param _pool Pool address - @return Rates for each coin, precision normalized to 10**18 - """ - rates: uint256[2] = [10**18, 0] - rates[1] = CurvePool(self.pool_data[_pool].base_pool).get_virtual_price() - return rates - - -@view -@external -def get_balances(_pool: address) -> uint256[MAX_PLAIN_COINS]: - """ - @notice Get balances for each coin within a pool - @dev For pools using lending, these are the wrapped coin balances - @param _pool Pool address - @return uint256 list of balances - """ - if self.pool_data[_pool].base_pool != ZERO_ADDRESS: - return [CurvePool(_pool).balances(0), CurvePool(_pool).balances(1), 0, 0] - n_coins: uint256 = self.pool_data[_pool].n_coins - balances: uint256[MAX_PLAIN_COINS] = empty(uint256[MAX_PLAIN_COINS]) - for i in range(MAX_PLAIN_COINS): - if i < n_coins: - balances[i] = CurvePool(_pool).balances(i) - else: - balances[i] = 0 - return balances - - -@view -@external -def get_underlying_balances(_pool: address) -> uint256[MAX_COINS]: - """ - @notice Get balances for each underlying coin within a metapool - @param _pool Metapool address - @return uint256 list of underlying balances - """ - - underlying_balances: uint256[MAX_COINS] = empty(uint256[MAX_COINS]) - underlying_balances[0] = CurvePool(_pool).balances(0) - - base_total_supply: uint256 = ERC20(self.pool_data[_pool].coins[1]).totalSupply() - if base_total_supply > 0: - underlying_pct: uint256 = CurvePool(_pool).balances(1) * 10**36 / base_total_supply - base_pool: address = self.pool_data[_pool].base_pool - assert base_pool != ZERO_ADDRESS # dev: pool is not a metapool - n_coins: uint256 = self.base_pool_data[base_pool].n_coins - for i in range(MAX_COINS): - if i == n_coins: - break - underlying_balances[i + 1] = CurvePool(base_pool).balances(i) * underlying_pct / 10**36 - - return underlying_balances - - -@view -@external -def get_A(_pool: address) -> uint256: - """ - @notice Get the amplfication co-efficient for a pool - @param _pool Pool address - @return uint256 A - """ - return CurvePool(_pool).A() - - -@view -@external -def get_fees(_pool: address) -> (uint256, uint256): - """ - @notice Get the fees for a pool - @dev Fees are expressed as integers - @return Pool fee and admin fee as uint256 with 1e10 precision - """ - return CurvePool(_pool).fee(), CurvePool(_pool).admin_fee() - - -@view -@external -def get_admin_balances(_pool: address) -> uint256[MAX_PLAIN_COINS]: - """ - @notice Get the current admin balances (uncollected fees) for a pool - @param _pool Pool address - @return List of uint256 admin balances - """ - n_coins: uint256 = self.pool_data[_pool].n_coins - admin_balances: uint256[MAX_PLAIN_COINS] = empty(uint256[MAX_PLAIN_COINS]) - for i in range(MAX_PLAIN_COINS): - if i == n_coins: - break - admin_balances[i] = CurvePool(_pool).admin_balances(i) - return admin_balances - - -@view -@external -def get_coin_indices( - _pool: address, - _from: address, - _to: address -) -> (int128, int128, bool): - """ - @notice Convert coin addresses to indices for use with pool methods - @param _pool Pool address - @param _from Coin address to be used as `i` within a pool - @param _to Coin address to be used as `j` within a pool - @return int128 `i`, int128 `j`, boolean indicating if `i` and `j` are underlying coins - """ - coin: address = self.pool_data[_pool].coins[0] - base_pool: address = self.pool_data[_pool].base_pool - if coin in [_from, _to] and base_pool != ZERO_ADDRESS: - base_lp_token: address = self.pool_data[_pool].coins[1] - if base_lp_token in [_from, _to]: - # True and False convert to 1 and 0 - a bit of voodoo that - # works because we only ever have 2 non-underlying coins if base pool is ZERO_ADDRESS - return convert(_to == coin, int128), convert(_from == coin, int128), False - - found_market: bool = False - i: int128 = 0 - j: int128 = 0 - for x in range(MAX_COINS): - if base_pool == ZERO_ADDRESS: - if x >= MAX_PLAIN_COINS: - raise "No available market" - if x != 0: - coin = self.pool_data[_pool].coins[x] - else: - if x != 0: - coin = self.base_pool_data[base_pool].coins[x-1] - if coin == ZERO_ADDRESS: - raise "No available market" - if coin == _from: - i = x - elif coin == _to: - j = x - else: - continue - if found_market: - # the second time we find a match, break out of the loop - break - # the first time we find a match, set `found_market` to True - found_market = True - - return i, j, True - - -@view -@external -def get_gauge(_pool: address) -> address: - """ - @notice Get the address of the liquidity gauge contract for a factory pool - @dev Returns `ZERO_ADDRESS` if a gauge has not been deployed - @param _pool Pool address - @return Implementation contract address - """ - return self.pool_data[_pool].liquidity_gauge - - -@view -@external -def get_implementation_address(_pool: address) -> address: - """ - @notice Get the address of the implementation contract used for a factory pool - @param _pool Pool address - @return Implementation contract address - """ - return self.pool_data[_pool].implementation - - -@view -@external -def is_meta(_pool: address) -> bool: - """ - @notice Verify `_pool` is a metapool - @param _pool Pool address - @return True if `_pool` is a metapool - """ - return self.pool_data[_pool].base_pool != ZERO_ADDRESS - - -@view -@external -def get_pool_asset_type(_pool: address) -> uint256: - """ - @notice Query the asset type of `_pool` - @dev 0 = USD, 1 = ETH, 2 = BTC, 3 = Other - @param _pool Pool Address - @return Integer indicating the pool asset type - """ - base_pool: address = self.pool_data[_pool].base_pool - if base_pool == ZERO_ADDRESS: - return self.pool_data[_pool].asset_type - else: - return self.base_pool_data[base_pool].asset_type - - -@view -@external -def get_fee_receiver(_pool: address) -> address: - base_pool: address = self.pool_data[_pool].base_pool - if base_pool == ZERO_ADDRESS: - return self.fee_receiver - else: - return self.base_pool_data[base_pool].fee_receiver - - -# <--- Pool Deployers ---> - -@external -def deploy_plain_pool( - _name: String[32], - _symbol: String[10], - _coins: address[MAX_PLAIN_COINS], - _A: uint256, - _fee: uint256, - _asset_type: uint256 = 0, - _implementation_idx: uint256 = 0, -) -> address: - """ - @notice Deploy a new plain pool - @param _name Name of the new plain pool - @param _symbol Symbol for the new plain pool - will be - concatenated with factory symbol - @param _coins List of addresses of the coins being used in the pool. - @param _A Amplification co-efficient - a lower value here means - less tolerance for imbalance within the pool's assets. - Suggested values include: - * Uncollateralized algorithmic stablecoins: 5-10 - * Non-redeemable, collateralized assets: 100 - * Redeemable assets: 200-400 - @param _fee Trade fee, given as an integer with 1e10 precision. The - minimum fee is 0.04% (4000000), the maximum is 1% (100000000). - 50% of the fee is distributed to veCRV holders. - @param _asset_type Asset type for pool, as an integer - 0 = USD, 1 = ETH, 2 = BTC, 3 = Other - @param _implementation_idx Index of the implementation to use. All possible - implementations for a pool of N_COINS can be publicly accessed - via `plain_implementations(N_COINS)` - @return Address of the deployed pool - """ - # fee must be between 0.04% and 1% - assert _fee >= 4000000 and _fee <= 100000000, "Invalid fee" - - n_coins: uint256 = MAX_PLAIN_COINS - rate_multipliers: uint256[MAX_PLAIN_COINS] = empty(uint256[MAX_PLAIN_COINS]) - decimals: uint256[MAX_PLAIN_COINS] = empty(uint256[MAX_PLAIN_COINS]) - - for i in range(MAX_PLAIN_COINS): - coin: address = _coins[i] - if coin == ZERO_ADDRESS: - assert i > 1, "Insufficient coins" - n_coins = i - break - assert self.base_pool_assets[coin] == False, "Invalid asset, deploy a metapool" - - if _coins[i] == 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE: - assert i == 0, "ETH must be first coin" - decimals[0] = 18 - else: - decimals[i] = ERC20(coin).decimals() - assert decimals[i] < 19, "Max 18 decimals for coins" - - rate_multipliers[i] = 10 ** (36 - decimals[i]) - - for x in range(i, i+MAX_PLAIN_COINS): - if x+1 == MAX_PLAIN_COINS: - break - if _coins[x+1] == ZERO_ADDRESS: - break - assert coin != _coins[x+1], "Duplicate coins" - - implementation: address = self.plain_implementations[n_coins][_implementation_idx] - assert implementation != ZERO_ADDRESS, "Invalid implementation index" - pool: address = create_forwarder_to(implementation) - CurvePlainPool(pool).initialize(_name, _symbol, _coins, rate_multipliers, _A, _fee) - - length: uint256 = self.pool_count - self.pool_list[length] = pool - self.pool_count = length + 1 - self.pool_data[pool].decimals = decimals - self.pool_data[pool].n_coins = n_coins - self.pool_data[pool].base_pool = ZERO_ADDRESS - self.pool_data[pool].implementation = implementation - if _asset_type != 0: - self.pool_data[pool].asset_type = _asset_type - - for i in range(MAX_PLAIN_COINS): - coin: address = _coins[i] - if coin == ZERO_ADDRESS: - break - self.pool_data[pool].coins[i] = coin - raw_call( - coin, - concat( - method_id("approve(address,uint256)"), - convert(pool, bytes32), - convert(MAX_UINT256, bytes32) - ) - ) - for j in range(MAX_PLAIN_COINS): - if i < j: - swappable_coin: address = _coins[j] - key: uint256 = bitwise_xor(convert(coin, uint256), convert(swappable_coin, uint256)) - length = self.market_counts[key] - self.markets[key][length] = pool - self.market_counts[key] = length + 1 - - log PlainPoolDeployed(_coins, _A, _fee, msg.sender) - return pool - - -@external -def deploy_metapool( - _base_pool: address, - _name: String[32], - _symbol: String[10], - _coin: address, - _A: uint256, - _fee: uint256, - _implementation_idx: uint256 = 0, -) -> address: - """ - @notice Deploy a new metapool - @param _base_pool Address of the base pool to use - within the metapool - @param _name Name of the new metapool - @param _symbol Symbol for the new metapool - will be - concatenated with the base pool symbol - @param _coin Address of the coin being used in the metapool - @param _A Amplification co-efficient - a higher value here means - less tolerance for imbalance within the pool's assets. - Suggested values include: - * Uncollateralized algorithmic stablecoins: 5-10 - * Non-redeemable, collateralized assets: 100 - * Redeemable assets: 200-400 - @param _fee Trade fee, given as an integer with 1e10 precision. The - minimum fee is 0.04% (4000000), the maximum is 1% (100000000). - 50% of the fee is distributed to veCRV holders. - @param _implementation_idx Index of the implementation to use. All possible - implementations for a BASE_POOL can be publicly accessed - via `metapool_implementations(BASE_POOL)` - @return Address of the deployed pool - """ - # fee must be between 0.04% and 1% - assert _fee >= 4000000 and _fee <= 100000000, "Invalid fee" - - implementation: address = self.base_pool_data[_base_pool].implementations[_implementation_idx] - assert implementation != ZERO_ADDRESS, "Invalid implementation index" - - # things break if a token has >18 decimals - decimals: uint256 = ERC20(_coin).decimals() - assert decimals < 19, "Max 18 decimals for coins" - - pool: address = create_forwarder_to(implementation) - CurvePool(pool).initialize(_name, _symbol, _coin, 10 ** (36 - decimals), _A, _fee) - ERC20(_coin).approve(pool, MAX_UINT256) - - # add pool to pool_list - length: uint256 = self.pool_count - self.pool_list[length] = pool - self.pool_count = length + 1 - - base_lp_token: address = self.base_pool_data[_base_pool].lp_token - - self.pool_data[pool].decimals = [decimals, 0, 0, 0] - self.pool_data[pool].n_coins = 2 - self.pool_data[pool].base_pool = _base_pool - self.pool_data[pool].coins[0] = _coin - self.pool_data[pool].coins[1] = self.base_pool_data[_base_pool].lp_token - self.pool_data[pool].implementation = implementation - - is_finished: bool = False - for i in range(MAX_COINS): - swappable_coin: address = self.base_pool_data[_base_pool].coins[i] - if swappable_coin == ZERO_ADDRESS: - is_finished = True - swappable_coin = base_lp_token - - key: uint256 = bitwise_xor(convert(_coin, uint256), convert(swappable_coin, uint256)) - length = self.market_counts[key] - self.markets[key][length] = pool - self.market_counts[key] = length + 1 - if is_finished: - break - - log MetaPoolDeployed(_coin, _base_pool, _A, _fee, msg.sender) - return pool - - -@external -def deploy_gauge(_pool: address) -> address: - """ - @notice Deploy a liquidity gauge for a factory pool - @param _pool Factory pool address to deploy a gauge for - @return Address of the deployed gauge - """ - assert self.pool_data[_pool].coins[0] != ZERO_ADDRESS, "Unknown pool" - assert self.pool_data[_pool].liquidity_gauge == ZERO_ADDRESS, "Gauge already deployed" - implementation: address = self.gauge_implementation - assert implementation != ZERO_ADDRESS, "Gauge implementation not set" - - gauge: address = create_forwarder_to(implementation) - LiquidityGauge(gauge).initialize(_pool) - self.pool_data[_pool].liquidity_gauge = gauge - - log LiquidityGaugeDeployed(_pool, gauge) - return gauge - - -# <--- Admin / Guarded Functionality ---> - -@external -def add_base_pool( - _base_pool: address, - _fee_receiver: address, - _asset_type: uint256, - _implementations: address[10], -): - """ - @notice Add a base pool to the registry, which may be used in factory metapools - @dev Only callable by admin - @param _base_pool Pool address to add - @param _fee_receiver Admin fee receiver address for metapools using this base pool - @param _asset_type Asset type for pool, as an integer 0 = USD, 1 = ETH, 2 = BTC, 3 = Other - @param _implementations List of implementation addresses that can be used with this base pool - """ - assert msg.sender == self.admin # dev: admin-only function - assert self.base_pool_data[_base_pool].coins[0] == ZERO_ADDRESS # dev: pool exists - - registry: address = AddressProvider(ADDRESS_PROVIDER).get_registry() - n_coins: uint256 = Registry(registry).get_n_coins(_base_pool) - - # add pool to pool_list - length: uint256 = self.base_pool_count - self.base_pool_list[length] = _base_pool - self.base_pool_count = length + 1 - self.base_pool_data[_base_pool].lp_token = Registry(registry).get_lp_token(_base_pool) - self.base_pool_data[_base_pool].n_coins = n_coins - self.base_pool_data[_base_pool].fee_receiver = _fee_receiver - if _asset_type != 0: - self.base_pool_data[_base_pool].asset_type = _asset_type - - for i in range(10): - implementation: address = _implementations[i] - if implementation == ZERO_ADDRESS: - break - self.base_pool_data[_base_pool].implementations[i] = implementation - - decimals: uint256 = 0 - coins: address[MAX_COINS] = Registry(registry).get_coins(_base_pool) - for i in range(MAX_COINS): - if i == n_coins: - break - coin: address = coins[i] - self.base_pool_data[_base_pool].coins[i] = coin - self.base_pool_assets[coin] = True - decimals += shift(ERC20(coin).decimals(), convert(i*8, int128)) - self.base_pool_data[_base_pool].decimals = decimals - - log BasePoolAdded(_base_pool) - - -@external -def set_metapool_implementations( - _base_pool: address, - _implementations: address[10], -): - """ - @notice Set implementation contracts for a metapool - @dev Only callable by admin - @param _base_pool Pool address to add - @param _implementations Implementation address to use when deploying metapools - """ - assert msg.sender == self.admin # dev: admin-only function - assert self.base_pool_data[_base_pool].coins[0] != ZERO_ADDRESS # dev: base pool does not exist - - for i in range(10): - new_imp: address = _implementations[i] - current_imp: address = self.base_pool_data[_base_pool].implementations[i] - if new_imp == current_imp: - if new_imp == ZERO_ADDRESS: - break - else: - self.base_pool_data[_base_pool].implementations[i] = new_imp - - -@external -def set_plain_implementations( - _n_coins: uint256, - _implementations: address[10], -): - assert msg.sender == self.admin # dev: admin-only function - - for i in range(10): - new_imp: address = _implementations[i] - current_imp: address = self.plain_implementations[_n_coins][i] - if new_imp == current_imp: - if new_imp == ZERO_ADDRESS: - break - else: - self.plain_implementations[_n_coins][i] = new_imp - - -@external -def set_gauge_implementation(_gauge_implementation: address): - assert msg.sender == self.admin # dev: admin-only function - - self.gauge_implementation = _gauge_implementation - - -@external -def batch_set_pool_asset_type(_pools: address[32], _asset_types: uint256[32]): - """ - @notice Batch set the asset type for factory pools - @dev Used to modify asset types that were set incorrectly at deployment - """ - assert msg.sender in [self.manager, self.admin] # dev: admin-only function - - for i in range(32): - if _pools[i] == ZERO_ADDRESS: - break - self.pool_data[_pools[i]].asset_type = _asset_types[i] - - -@external -def commit_transfer_ownership(_addr: address): - """ - @notice Transfer ownership of this contract to `addr` - @param _addr Address of the new owner - """ - assert msg.sender == self.admin # dev: admin only - - self.future_admin = _addr - - -@external -def accept_transfer_ownership(): - """ - @notice Accept a pending ownership transfer - @dev Only callable by the new owner - """ - _admin: address = self.future_admin - assert msg.sender == _admin # dev: future admin only - - self.admin = _admin - self.future_admin = ZERO_ADDRESS - - -@external -def set_manager(_manager: address): - """ - @notice Set the manager - @dev Callable by the admin or existing manager - @param _manager Manager address - """ - assert msg.sender in [self.manager, self.admin] # dev: admin-only function - - self.manager = _manager - - -@external -def set_fee_receiver(_base_pool: address, _fee_receiver: address): - """ - @notice Set fee receiver for base and plain pools - @param _base_pool Address of base pool to set fee receiver for. - For plain pools, leave as `ZERO_ADDRESS`. - @param _fee_receiver Address that fees are sent to - """ - assert msg.sender == self.admin # dev: admin only - if _base_pool == ZERO_ADDRESS: - self.fee_receiver = _fee_receiver - else: - self.base_pool_data[_base_pool].fee_receiver = _fee_receiver - - -@external -def convert_metapool_fees() -> bool: - """ - @notice Convert the fees of a metapool and transfer to - the metapool's fee receiver - @dev All fees are converted to LP token of base pool - """ - base_pool: address = self.pool_data[msg.sender].base_pool - assert base_pool != ZERO_ADDRESS # dev: sender must be metapool - coin: address = self.pool_data[msg.sender].coins[0] - - amount: uint256 = ERC20(coin).balanceOf(self) - receiver: address = self.base_pool_data[base_pool].fee_receiver - - CurvePool(msg.sender).exchange(0, 1, amount, 0, receiver) - return True - - -# <--- Pool Migration ---> - -@external -def add_existing_metapools(_pools: address[10]) -> bool: - """ - @notice Add existing metapools from the old factory - @dev Base pools that are used by the pools to be added must - be added separately with `add_base_pool` - @param _pools Addresses of existing pools to add - """ - - length: uint256 = self.pool_count - for pool in _pools: - if pool == ZERO_ADDRESS: - break - - assert self.pool_data[pool].coins[0] == ZERO_ADDRESS # dev: pool already exists - - coins: address[2] = OldFactory(OLD_FACTORY).get_coins(pool) - assert coins[0] != ZERO_ADDRESS # dev: pool not in old factory - - # add pool to pool list - self.pool_list[length] = pool - length += 1 - - base_pool: address = ZERO_ADDRESS - implementation: address = ZERO_ADDRESS - - if coins[1] == 0x6c3F90f043a72FA612cbac8115EE7e52BDe6E490: - # 3pool - base_pool = 0xbEbc44782C7dB0a1A60Cb6fe97d0b483032FF1C7 - implementation = 0x5F890841f657d90E081bAbdB532A05996Af79Fe6 - elif coins[1] == 0x075b1bb99792c9E1041bA13afEf80C91a1e70fB3: - # sbtc - base_pool = 0x7fC77b5c7614E1533320Ea6DDc2Eb61fa00A9714 - implementation = 0x2f956eEe002B0dEbD468CF2E0490d1aEc65e027F - self.pool_data[pool].asset_type = 2 - else: - raise - - # update pool data - self.pool_data[pool].decimals[0] = ERC20(coins[0]).decimals() - self.pool_data[pool].base_pool = base_pool - meta_coin: address = CurveFactoryMetapool(pool).coins(0) - self.pool_data[pool].coins[0] = coins[0] - self.pool_data[pool].coins[1] = coins[1] - self.pool_data[pool].implementation = implementation - - base_pool_coins: address[MAX_COINS] = self.base_pool_data[base_pool].coins - assert base_pool_coins[0] != ZERO_ADDRESS # dev: unknown base pool - - is_finished: bool = False - for i in range(MAX_COINS): - swappable_coin: address = base_pool_coins[i] - if swappable_coin == ZERO_ADDRESS: - is_finished = True - swappable_coin = coins[1] - - key: uint256 = bitwise_xor(convert(meta_coin, uint256), convert(swappable_coin, uint256)) - market_idx: uint256 = self.market_counts[key] - self.markets[key][market_idx] = pool - self.market_counts[key] = market_idx + 1 - if is_finished: - break - - self.pool_count = length - return True diff --git a/contracts/mainnet/mocks/StableRegistry.vy b/contracts/mainnet/mocks/StableRegistry.vy deleted file mode 100644 index 91e5b98..0000000 --- a/contracts/mainnet/mocks/StableRegistry.vy +++ /dev/null @@ -1,1245 +0,0 @@ -# @version 0.2.11 -""" -@title Curve Registry -@license MIT -@author Curve.Fi -""" - -MAX_COINS: constant(int128) = 8 -CALC_INPUT_SIZE: constant(int128) = 100 - - -struct CoinInfo: - index: uint256 - register_count: uint256 - swap_count: uint256 - swap_for: address[MAX_INT128] - -struct PoolArray: - location: uint256 - decimals: uint256 - underlying_decimals: uint256 - rate_info: bytes32 - base_pool: address - coins: address[MAX_COINS] - ul_coins: address[MAX_COINS] - n_coins: uint256 # [coins, underlying coins] tightly packed as uint128[2] - has_initial_A: bool - is_v1: bool - name: String[64] - asset_type: uint256 - -struct PoolParams: - A: uint256 - future_A: uint256 - fee: uint256 - admin_fee: uint256 - future_fee: uint256 - future_admin_fee: uint256 - future_owner: address - initial_A: uint256 - initial_A_time: uint256 - future_A_time: uint256 - - -interface AddressProvider: - def admin() -> address: view - def get_address(_id: uint256) -> address: view - -interface ERC20: - def balanceOf(_addr: address) -> uint256: view - def decimals() -> uint256: view - def totalSupply() -> uint256: view - -interface CurvePool: - def A() -> uint256: view - def future_A() -> uint256: view - def fee() -> uint256: view - def admin_fee() -> uint256: view - def future_fee() -> uint256: view - def future_admin_fee() -> uint256: view - def future_owner() -> address: view - def initial_A() -> uint256: view - def initial_A_time() -> uint256: view - def future_A_time() -> uint256: view - def coins(i: uint256) -> address: view - def underlying_coins(i: uint256) -> address: view - def balances(i: uint256) -> uint256: view - def get_virtual_price() -> uint256: view - -interface CurvePoolV1: - def coins(i: int128) -> address: view - def underlying_coins(i: int128) -> address: view - def balances(i: int128) -> uint256: view - -interface CurveMetapool: - def base_pool() -> address: view - -interface GasEstimator: - def estimate_gas_used(_pool: address, _from: address, _to: address) -> uint256: view - -interface LiquidityGauge: - def lp_token() -> address: view - -interface GaugeController: - def gauge_types(gauge: address) -> int128: view - -interface RateCalc: - def get_rate(_coin: address) -> uint256: view - - -event PoolAdded: - pool: indexed(address) - rate_method_id: Bytes[4] - -event PoolRemoved: - pool: indexed(address) - - -address_provider: public(AddressProvider) -gauge_controller: public(address) -pool_list: public(address[65536]) # master list of pools -pool_count: public(uint256) # actual length of pool_list - -pool_data: HashMap[address, PoolArray] - -coin_count: public(uint256) # total unique coins registered -coins: HashMap[address, CoinInfo] -get_coin: public(address[65536]) # unique list of registered coins -# bitwise_xor(coina, coinb) -> (coina_pos, coinb_pos) sorted -# stored as uint128[2] -coin_swap_indexes: HashMap[uint256, uint256] - -# lp token -> pool -get_pool_from_lp_token: public(HashMap[address, address]) - -# pool -> lp token -get_lp_token: public(HashMap[address, address]) - -# mapping of estimated gas costs for pools and coins -# for a pool the values are [wrapped exchange, underlying exchange] -# for a coin the values are [transfer cost, 0] -gas_estimate_values: HashMap[address, uint256[2]] - -# pool -> gas estimation contract -# used when gas costs for a pool are too complex to be handled by summing -# values in `gas_estimate_values` -gas_estimate_contracts: HashMap[address, address] - -# mapping of coins -> pools for trading -# a mapping key is generated for each pair of addresses via -# `bitwise_xor(convert(a, uint256), convert(b, uint256))` -markets: HashMap[uint256, address[65536]] -market_counts: HashMap[uint256, uint256] - -liquidity_gauges: HashMap[address, address[10]] - -last_updated: public(uint256) - - -@external -def __init__(_address_provider: address, _gauge_controller: address): - """ - @notice Constructor function - """ - self.address_provider = AddressProvider(_address_provider) - self.gauge_controller = _gauge_controller - - -# internal functionality for getters - -@view -@internal -def _unpack_decimals(_packed: uint256, _n_coins: uint256) -> uint256[MAX_COINS]: - # decimals are tightly packed as a series of uint8 within a little-endian bytes32 - # the packed value is stored as uint256 to simplify unpacking via shift and modulo - decimals: uint256[MAX_COINS] = empty(uint256[MAX_COINS]) - n_coins: int128 = convert(_n_coins, int128) - for i in range(MAX_COINS): - if i == n_coins: - break - decimals[i] = shift(_packed, -8 * i) % 256 - - return decimals - - -@view -@internal -def _get_rates(_pool: address) -> uint256[MAX_COINS]: - rates: uint256[MAX_COINS] = empty(uint256[MAX_COINS]) - base_pool: address = self.pool_data[_pool].base_pool - if base_pool == ZERO_ADDRESS: - rate_info: bytes32 = self.pool_data[_pool].rate_info - rate_calc_addr: uint256 = convert(slice(rate_info, 8, 20), uint256) - rate_method_id: Bytes[4] = slice(rate_info, 28, 4) - - for i in range(MAX_COINS): - coin: address = self.pool_data[_pool].coins[i] - if coin == ZERO_ADDRESS: - break - if rate_info == EMPTY_BYTES32 or coin == self.pool_data[_pool].ul_coins[i]: - rates[i] = 10 ** 18 - elif rate_calc_addr != 0: - rates[i] = RateCalc(convert(rate_calc_addr, address)).get_rate(coin) - else: - rates[i] = convert( - raw_call(coin, rate_method_id, max_outsize=32, is_static_call=True), # dev: bad response - uint256 - ) - else: - base_coin_idx: uint256 = shift(self.pool_data[_pool].n_coins, -128) - 1 - rates[base_coin_idx] = CurvePool(base_pool).get_virtual_price() - for i in range(MAX_COINS): - if i == base_coin_idx: - break - rates[i] = 10 ** 18 - - return rates - -@view -@internal -def _get_balances(_pool: address) -> uint256[MAX_COINS]: - is_v1: bool = self.pool_data[_pool].is_v1 - - balances: uint256[MAX_COINS] = empty(uint256[MAX_COINS]) - for i in range(MAX_COINS): - if self.pool_data[_pool].coins[i] == ZERO_ADDRESS: - assert i != 0 - break - - if is_v1: - balances[i] = CurvePoolV1(_pool).balances(i) - else: - balances[i] = CurvePool(_pool).balances(convert(i, uint256)) - - return balances - - -@view -@internal -def _get_underlying_balances(_pool: address) -> uint256[MAX_COINS]: - balances: uint256[MAX_COINS] = self._get_balances(_pool) - rates: uint256[MAX_COINS] = self._get_rates(_pool) - decimals: uint256 = self.pool_data[_pool].underlying_decimals - underlying_balances: uint256[MAX_COINS] = balances - for i in range(MAX_COINS): - coin: address = self.pool_data[_pool].coins[i] - if coin == ZERO_ADDRESS: - break - ucoin: address = self.pool_data[_pool].ul_coins[i] - if ucoin == ZERO_ADDRESS: - continue - if ucoin != coin: - underlying_balances[i] = balances[i] * rates[i] / 10**(shift(decimals, -8 * i) % 256) - - return underlying_balances - - -@view -@internal -def _get_meta_underlying_balances(_pool: address, _base_pool: address) -> uint256[MAX_COINS]: - base_coin_idx: uint256 = shift(self.pool_data[_pool].n_coins, -128) - 1 - is_v1: bool = self.pool_data[_base_pool].is_v1 - base_total_supply: uint256 = ERC20(self.get_lp_token[_base_pool]).totalSupply() - - underlying_balances: uint256[MAX_COINS] = empty(uint256[MAX_COINS]) - ul_balance: uint256 = 0 - underlying_pct: uint256 = 0 - if base_total_supply > 0: - underlying_pct = CurvePool(_pool).balances(base_coin_idx) * 10**36 / base_total_supply - - for i in range(MAX_COINS): - if self.pool_data[_pool].ul_coins[i] == ZERO_ADDRESS: - break - if i < base_coin_idx: - ul_balance = CurvePool(_pool).balances(i) - else: - if is_v1: - ul_balance = CurvePoolV1(_base_pool).balances(convert(i - base_coin_idx, int128)) - else: - ul_balance = CurvePool(_base_pool).balances(i-base_coin_idx) - ul_balance = ul_balance * underlying_pct / 10**36 - underlying_balances[i] = ul_balance - - return underlying_balances - - -@view -@internal -def _get_coin_indices( - _pool: address, - _from: address, - _to: address -) -> uint256[3]: - """ - Convert coin addresses to indices for use with pool methods. - """ - # the return value is stored as `uint256[3]` to reduce gas costs - # from index, to index, is the market underlying? - result: uint256[3] = empty(uint256[3]) - - found_market: bool = False - - # check coin markets - for x in range(MAX_COINS): - coin: address = self.pool_data[_pool].coins[x] - if coin == ZERO_ADDRESS: - # if we reach the end of the coins, reset `found_market` and try again - # with the underlying coins - found_market = False - break - if coin == _from: - result[0] = x - elif coin == _to: - result[1] = x - else: - continue - - if found_market: - # the second time we find a match, break out of the loop - break - # the first time we find a match, set `found_market` to True - found_market = True - - if not found_market: - # check underlying coin markets - for x in range(MAX_COINS): - coin: address = self.pool_data[_pool].ul_coins[x] - if coin == ZERO_ADDRESS: - raise "No available market" - if coin == _from: - result[0] = x - elif coin == _to: - result[1] = x - else: - continue - - if found_market: - result[2] = 1 - break - found_market = True - - return result - - -# targetted external getters, optimized for on-chain calls - -@view -@external -def find_pool_for_coins(_from: address, _to: address, i: uint256 = 0) -> address: - """ - @notice Find an available pool for exchanging two coins - @param _from Address of coin to be sent - @param _to Address of coin to be received - @param i Index value. When multiple pools are available - this value is used to return the n'th address. - @return Pool address - """ - key: uint256 = bitwise_xor(convert(_from, uint256), convert(_to, uint256)) - return self.markets[key][i] - - -@view -@external -def get_n_coins(_pool: address) -> uint256[2]: - """ - @notice Get the number of coins in a pool - @dev For non-metapools, both returned values are identical - even when the pool does not use wrapping/lending - @param _pool Pool address - @return Number of wrapped coins, number of underlying coins - """ - n_coins: uint256 = self.pool_data[_pool].n_coins - return [shift(n_coins, -128), n_coins % 2**128] - - -@view -@external -def get_coins(_pool: address) -> address[MAX_COINS]: - """ - @notice Get the coins within a pool - @dev For pools using lending, these are the wrapped coin addresses - @param _pool Pool address - @return List of coin addresses - """ - coins: address[MAX_COINS] = empty(address[MAX_COINS]) - n_coins: uint256 = shift(self.pool_data[_pool].n_coins, -128) - for i in range(MAX_COINS): - if i == n_coins: - break - coins[i] = self.pool_data[_pool].coins[i] - - return coins - - -@view -@external -def get_underlying_coins(_pool: address) -> address[MAX_COINS]: - """ - @notice Get the underlying coins within a pool - @dev For pools that do not lend, returns the same value as `get_coins` - @param _pool Pool address - @return List of coin addresses - """ - coins: address[MAX_COINS] = empty(address[MAX_COINS]) - n_coins: uint256 = self.pool_data[_pool].n_coins % 2**128 - for i in range(MAX_COINS): - if i == n_coins: - break - coins[i] = self.pool_data[_pool].ul_coins[i] - - return coins - - -@view -@external -def get_decimals(_pool: address) -> uint256[MAX_COINS]: - """ - @notice Get decimal places for each coin within a pool - @dev For pools using lending, these are the wrapped coin decimal places - @param _pool Pool address - @return uint256 list of decimals - """ - n_coins: uint256 = shift(self.pool_data[_pool].n_coins, -128) - return self._unpack_decimals(self.pool_data[_pool].decimals, n_coins) - - -@view -@external -def get_underlying_decimals(_pool: address) -> uint256[MAX_COINS]: - """ - @notice Get decimal places for each underlying coin within a pool - @dev For pools that do not lend, returns the same value as `get_decimals` - @param _pool Pool address - @return uint256 list of decimals - """ - n_coins: uint256 = self.pool_data[_pool].n_coins % 2**128 - return self._unpack_decimals(self.pool_data[_pool].underlying_decimals, n_coins) - - -@view -@external -def get_rates(_pool: address) -> uint256[MAX_COINS]: - """ - @notice Get rates between coins and underlying coins - @dev For coins where there is no underlying coin, or where - the underlying coin cannot be swapped, the rate is - given as 1e18 - @param _pool Pool address - @return Rates between coins and underlying coins - """ - return self._get_rates(_pool) - - -@view -@external -def get_gauges(_pool: address) -> (address[10], int128[10]): - """ - @notice Get a list of LiquidityGauge contracts associated with a pool - @param _pool Pool address - @return address[10] of gauge addresses, int128[10] of gauge types - """ - liquidity_gauges: address[10] = empty(address[10]) - gauge_types: int128[10] = empty(int128[10]) - gauge_controller: address = self.gauge_controller - for i in range(10): - gauge: address = self.liquidity_gauges[_pool][i] - if gauge == ZERO_ADDRESS: - break - liquidity_gauges[i] = gauge - gauge_types[i] = GaugeController(gauge_controller).gauge_types(gauge) - - return liquidity_gauges, gauge_types - - -@view -@external -def get_balances(_pool: address) -> uint256[MAX_COINS]: - """ - @notice Get balances for each coin within a pool - @dev For pools using lending, these are the wrapped coin balances - @param _pool Pool address - @return uint256 list of balances - """ - return self._get_balances(_pool) - - -@view -@external -def get_underlying_balances(_pool: address) -> uint256[MAX_COINS]: - """ - @notice Get balances for each underlying coin within a pool - @dev For pools that do not lend, returns the same value as `get_balances` - @param _pool Pool address - @return uint256 list of underlyingbalances - """ - base_pool: address = self.pool_data[_pool].base_pool - if base_pool == ZERO_ADDRESS: - return self._get_underlying_balances(_pool) - return self._get_meta_underlying_balances(_pool, base_pool) - - -@view -@external -def get_virtual_price_from_lp_token(_token: address) -> uint256: - """ - @notice Get the virtual price of a pool LP token - @param _token LP token address - @return uint256 Virtual price - """ - return CurvePool(self.get_pool_from_lp_token[_token]).get_virtual_price() - - -@view -@external -def get_A(_pool: address) -> uint256: - return CurvePool(_pool).A() - - -@view -@external -def get_parameters(_pool: address) -> PoolParams: - """ - @notice Get parameters for a pool - @dev For older pools where `initial_A` is not public, this value is set to 0 - @param _pool Pool address - @return Pool amp, future amp, fee, admin fee, future fee, future admin fee, - future owner, initial amp, initial amp time, future amp time - """ - pool_params: PoolParams = empty(PoolParams) - pool_params.A = CurvePool(_pool).A() - pool_params.future_A = CurvePool(_pool).future_A() - pool_params.fee = CurvePool(_pool).fee() - pool_params.future_fee = CurvePool(_pool).future_fee() - pool_params.admin_fee = CurvePool(_pool).admin_fee() - pool_params.future_admin_fee = CurvePool(_pool).future_admin_fee() - pool_params.future_owner = CurvePool(_pool).future_owner() - - if self.pool_data[_pool].has_initial_A: - pool_params.initial_A = CurvePool(_pool).initial_A() - pool_params.initial_A_time = CurvePool(_pool).initial_A_time() - pool_params.future_A_time = CurvePool(_pool).future_A_time() - - return pool_params - - -@view -@external -def get_fees(_pool: address) -> uint256[2]: - """ - @notice Get the fees for a pool - @dev Fees are expressed as integers - @return Pool fee as uint256 with 1e10 precision - Admin fee as 1e10 percentage of pool fee - """ - return [CurvePool(_pool).fee(), CurvePool(_pool).admin_fee()] - - -@view -@external -def get_admin_balances(_pool: address) -> uint256[MAX_COINS]: - """ - @notice Get the current admin balances (uncollected fees) for a pool - @param _pool Pool address - @return List of uint256 admin balances - """ - balances: uint256[MAX_COINS] = self._get_balances(_pool) - n_coins: uint256 = shift(self.pool_data[_pool].n_coins, -128) - for i in range(MAX_COINS): - coin: address = self.pool_data[_pool].coins[i] - if i == n_coins: - break - if coin == 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE: - balances[i] = _pool.balance - balances[i] - else: - balances[i] = ERC20(coin).balanceOf(_pool) - balances[i] - - return balances - - -@view -@external -def get_coin_indices( - _pool: address, - _from: address, - _to: address -) -> (int128, int128, bool): - """ - @notice Convert coin addresses to indices for use with pool methods - @param _from Coin address to be used as `i` within a pool - @param _to Coin address to be used as `j` within a pool - @return int128 `i`, int128 `j`, boolean indicating if `i` and `j` are underlying coins - """ - result: uint256[3] = self._get_coin_indices(_pool, _from, _to) - return convert(result[0], int128), convert(result[1], int128), result[2] > 0 - - -@view -@external -def estimate_gas_used(_pool: address, _from: address, _to: address) -> uint256: - """ - @notice Estimate the gas used in an exchange. - @param _pool Pool address - @param _from Address of coin to be sent - @param _to Address of coin to be received - @return Upper-bound gas estimate, in wei - """ - estimator: address = self.gas_estimate_contracts[_pool] - if estimator != ZERO_ADDRESS: - return GasEstimator(estimator).estimate_gas_used(_pool, _from, _to) - - # here we call `_get_coin_indices` to find out if the exchange involves wrapped - # or underlying coins, and use the result as an index in `gas_estimate_values` - # 0 == wrapped 1 == underlying - idx_underlying: uint256 = self._get_coin_indices(_pool, _from, _to)[2] - - total: uint256 = self.gas_estimate_values[_pool][idx_underlying] - assert total != 0 # dev: pool value not set - - for addr in [_from, _to]: - _gas: uint256 = self.gas_estimate_values[addr][0] - assert _gas != 0 # dev: coin value not set - total += _gas - - return total - -@view -@external -def is_meta(_pool: address) -> bool: - """ - @notice Verify `_pool` is a metapool - @param _pool Pool address - @return True if `_pool` is a metapool - """ - return self.pool_data[_pool].base_pool != ZERO_ADDRESS - - -@view -@external -def get_pool_name(_pool: address) -> String[64]: - """ - @notice Get the given name for a pool - @param _pool Pool address - @return The name of a pool - """ - return self.pool_data[_pool].name - - -@view -@external -def get_coin_swap_count(_coin: address) -> uint256: - """ - @notice Get the number of unique coins available to swap `_coin` against - @param _coin Coin address - @return The number of unique coins available to swap for - """ - return self.coins[_coin].swap_count - - -@view -@external -def get_coin_swap_complement(_coin: address, _index: uint256) -> address: - """ - @notice Get the coin available to swap against `_coin` at `_index` - @param _coin Coin address - @param _index An index in the `_coin`'s set of available counter - coin's - @return Address of a coin available to swap against `_coin` - """ - return self.coins[_coin].swap_for[_index] - - -@view -@external -def get_pool_asset_type(_pool: address) -> uint256: - """ - @notice Query the asset type of `_pool` - @param _pool Pool Address - @return The asset type as an unstripped string - """ - return self.pool_data[_pool].asset_type - - -# internal functionality used in admin setters - -@internal -def _add_pool( - _sender: address, - _pool: address, - _n_coins: uint256, - _lp_token: address, - _rate_info: bytes32, - _has_initial_A: bool, - _is_v1: bool, - _name: String[64], -): - assert _sender == self.address_provider.admin() # dev: admin-only function - assert _lp_token != ZERO_ADDRESS - assert self.pool_data[_pool].coins[0] == ZERO_ADDRESS # dev: pool exists - assert self.get_pool_from_lp_token[_lp_token] == ZERO_ADDRESS - - # add pool to pool_list - length: uint256 = self.pool_count - self.pool_list[length] = _pool - self.pool_count = length + 1 - self.pool_data[_pool].location = length - self.pool_data[_pool].rate_info = _rate_info - self.pool_data[_pool].has_initial_A = _has_initial_A - self.pool_data[_pool].is_v1 = _is_v1 - self.pool_data[_pool].n_coins = _n_coins - self.pool_data[_pool].name = _name - - # update public mappings - self.get_pool_from_lp_token[_lp_token] = _pool - self.get_lp_token[_pool] = _lp_token - self.last_updated = block.timestamp - - log PoolAdded(_pool, slice(_rate_info, 28, 4)) - - -@internal -def _register_coin(_coin: address): - if self.coins[_coin].register_count == 0: - coin_count: uint256 = self.coin_count - self.coins[_coin].index = coin_count - self.get_coin[coin_count] = _coin - self.coin_count += 1 - self.coins[_coin].register_count += 1 - - -@internal -def _register_coin_pair(_coina: address, _coinb: address, _key: uint256): - # register _coinb in _coina's array of coins - coin_b_pos: uint256 = self.coins[_coina].swap_count - self.coins[_coina].swap_for[coin_b_pos] = _coinb - self.coins[_coina].swap_count += 1 - # register _coina in _coinb's array of coins - coin_a_pos: uint256 = self.coins[_coinb].swap_count - self.coins[_coinb].swap_for[coin_a_pos] = _coina - self.coins[_coinb].swap_count += 1 - # register indexes (coina pos in coinb array, coinb pos in coina array) - if convert(_coina, uint256) < convert(_coinb, uint256): - self.coin_swap_indexes[_key] = shift(coin_a_pos, 128) + coin_b_pos - else: - self.coin_swap_indexes[_key] = shift(coin_b_pos, 128) + coin_a_pos - - -@internal -def _unregister_coin(_coin: address): - self.coins[_coin].register_count -= 1 - - if self.coins[_coin].register_count == 0: - self.coin_count -= 1 - coin_count: uint256 = self.coin_count - location: uint256 = self.coins[_coin].index - - if location < coin_count: - coin_b: address = self.get_coin[coin_count] - self.get_coin[location] = coin_b - self.coins[coin_b].index = location - - self.coins[_coin].index = 0 - self.get_coin[coin_count] = ZERO_ADDRESS - - -@internal -def _unregister_coin_pair(_coina: address, _coinb: address, _coinb_idx: uint256): - """ - @param _coinb_idx the index of _coinb in _coina's array of unique coin's - """ - # decrement swap counts for both coins - self.coins[_coina].swap_count -= 1 - - # retrieve the last currently occupied index in coina's array - coina_arr_last_idx: uint256 = self.coins[_coina].swap_count - - # if coinb's index in coina's array is less than the last - # overwrite it's position with the last coin - if _coinb_idx < coina_arr_last_idx: - # here's our last coin in coina's array - coin_c: address = self.coins[_coina].swap_for[coina_arr_last_idx] - # get the bitwise_xor of the pair to retrieve their indexes - key: uint256 = bitwise_xor(convert(_coina, uint256), convert(coin_c, uint256)) - indexes: uint256 = self.coin_swap_indexes[key] - - # update the pairing's indexes - if convert(_coina, uint256) < convert(coin_c, uint256): - # least complicated most readable way of shifting twice to remove the lower order bits - self.coin_swap_indexes[key] = shift(shift(indexes, -128), 128) + _coinb_idx - else: - self.coin_swap_indexes[key] = shift(_coinb_idx, 128) + indexes % 2 ** 128 - # set _coinb_idx in coina's array to coin_c - self.coins[_coina].swap_for[_coinb_idx] = coin_c - - self.coins[_coina].swap_for[coina_arr_last_idx] = ZERO_ADDRESS - - -@internal -def _get_new_pool_coins( - _pool: address, - _n_coins: uint256, - _is_underlying: bool, - _is_v1: bool -) -> address[MAX_COINS]: - coin_list: address[MAX_COINS] = empty(address[MAX_COINS]) - coin: address = ZERO_ADDRESS - for i in range(MAX_COINS): - if i == _n_coins: - break - if _is_underlying: - if _is_v1: - coin = CurvePoolV1(_pool).underlying_coins(convert(i, int128)) - else: - coin = CurvePool(_pool).underlying_coins(i) - self.pool_data[_pool].ul_coins[i] = coin - else: - if _is_v1: - coin = CurvePoolV1(_pool).coins(convert(i, int128)) - else: - coin = CurvePool(_pool).coins(i) - self.pool_data[_pool].coins[i] = coin - coin_list[i] = coin - - for i in range(MAX_COINS): - if i == _n_coins: - break - - self._register_coin(coin_list[i]) - # add pool to markets - i2: uint256 = i + 1 - for x in range(i2, i2 + MAX_COINS): - if x == _n_coins: - break - - key: uint256 = bitwise_xor(convert(coin_list[i], uint256), convert(coin_list[x], uint256)) - length: uint256 = self.market_counts[key] - self.markets[key][length] = _pool - self.market_counts[key] = length + 1 - - # register the coin pair - if length == 0: - self._register_coin_pair(coin_list[x], coin_list[i], key) - - return coin_list - - -@view -@internal -def _get_new_pool_decimals(_coins: address[MAX_COINS], _n_coins: uint256) -> uint256: - packed: uint256 = 0 - value: uint256 = 0 - - n_coins: int128 = convert(_n_coins, int128) - for i in range(MAX_COINS): - if i == n_coins: - break - coin: address = _coins[i] - if coin == 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE: - value = 18 - else: - value = ERC20(coin).decimals() - assert value < 256 # dev: decimal overflow - - packed += shift(value, i * 8) - - return packed - - -@internal -def _remove_market(_pool: address, _coina: address, _coinb: address): - key: uint256 = bitwise_xor(convert(_coina, uint256), convert(_coinb, uint256)) - length: uint256 = self.market_counts[key] - 1 - if length == 0: - indexes: uint256 = self.coin_swap_indexes[key] - if convert(_coina, uint256) < convert(_coinb, uint256): - self._unregister_coin_pair(_coina, _coinb, indexes % 2 ** 128) - self._unregister_coin_pair(_coinb, _coina, shift(indexes, -128)) - else: - self._unregister_coin_pair(_coina, _coinb, shift(indexes, -128)) - self._unregister_coin_pair(_coinb, _coina, indexes % 2 ** 128) - self.coin_swap_indexes[key] = 0 - for i in range(65536): - if i > length: - break - if self.markets[key][i] == _pool: - if i < length: - self.markets[key][i] = self.markets[key][length] - self.markets[key][length] = ZERO_ADDRESS - self.market_counts[key] = length - break - - -# admin functions - -@external -def add_pool( - _pool: address, - _n_coins: uint256, - _lp_token: address, - _rate_info: bytes32, - _decimals: uint256, - _underlying_decimals: uint256, - _has_initial_A: bool, - _is_v1: bool, - _name: String[64], -): - """ - @notice Add a pool to the registry - @dev Only callable by admin - @param _pool Pool address to add - @param _n_coins Number of coins in the pool - @param _lp_token Pool deposit token address - @param _rate_info Encoded twenty-byte rate calculator address and/or four-byte - function signature to query coin rates - @param _decimals Coin decimal values, tightly packed as uint8 in a little-endian bytes32 - @param _underlying_decimals Underlying coin decimal values, tightly packed - as uint8 in a little-endian bytes32 - @param _name The name of the pool - """ - self._add_pool( - msg.sender, - _pool, - _n_coins + shift(_n_coins, 128), - _lp_token, - _rate_info, - _has_initial_A, - _is_v1, - _name, - ) - - coins: address[MAX_COINS] = self._get_new_pool_coins(_pool, _n_coins, False, _is_v1) - decimals: uint256 = _decimals - if decimals == 0: - decimals = self._get_new_pool_decimals(coins, _n_coins) - self.pool_data[_pool].decimals = decimals - - coins = self._get_new_pool_coins(_pool, _n_coins, True, _is_v1) - decimals = _underlying_decimals - if decimals == 0: - decimals = self._get_new_pool_decimals(coins, _n_coins) - self.pool_data[_pool].underlying_decimals = decimals - - -@external -def add_pool_without_underlying( - _pool: address, - _n_coins: uint256, - _lp_token: address, - _rate_info: bytes32, - _decimals: uint256, - _use_rates: uint256, - _has_initial_A: bool, - _is_v1: bool, - _name: String[64], -): - """ - @notice Add a pool to the registry - @dev Only callable by admin - @param _pool Pool address to add - @param _n_coins Number of coins in the pool - @param _lp_token Pool deposit token address - @param _rate_info Encoded twenty-byte rate calculator address and/or four-byte - function signature to query coin rates - @param _decimals Coin decimal values, tightly packed as uint8 in a little-endian bytes32 - @param _use_rates Boolean array indicating which coins use lending rates, - tightly packed in a little-endian bytes32 - @param _name The name of the pool - """ - self._add_pool( - msg.sender, - _pool, - _n_coins + shift(_n_coins, 128), - _lp_token, - _rate_info, - _has_initial_A, - _is_v1, - _name, - ) - - coins: address[MAX_COINS] = self._get_new_pool_coins(_pool, _n_coins, False, _is_v1) - - decimals: uint256 = _decimals - if decimals == 0: - decimals = self._get_new_pool_decimals(coins, _n_coins) - self.pool_data[_pool].decimals = decimals - - udecimals: uint256 = 0 - for i in range(MAX_COINS): - if i == _n_coins: - break - offset: int128 = -8 * convert(i, int128) - if shift(_use_rates, offset) % 256 == 0: - self.pool_data[_pool].ul_coins[i] = coins[i] - udecimals += shift(shift(decimals, offset) % 256, -offset) - - self.pool_data[_pool].underlying_decimals = udecimals - - -@external -def add_metapool( - _pool: address, - _n_coins: uint256, - _lp_token: address, - _decimals: uint256, - _name: String[64], - _base_pool: address = ZERO_ADDRESS -): - """ - @notice Add a pool to the registry - @dev Only callable by admin - @param _pool Pool address to add - @param _n_coins Number of coins in the pool - @param _lp_token Pool deposit token address - @param _decimals Coin decimal values, tightly packed as uint8 in a little-endian bytes32 - @param _name The name of the pool - @param _base_pool Address of the base_pool useful for adding factory pools - """ - base_coin_offset: uint256 = _n_coins - 1 - - base_pool: address = _base_pool - if base_pool == ZERO_ADDRESS: - base_pool = CurveMetapool(_pool).base_pool() - base_n_coins: uint256 = shift(self.pool_data[base_pool].n_coins, -128) - assert base_n_coins > 0 # dev: base pool unknown - - self._add_pool( - msg.sender, - _pool, - base_n_coins + base_coin_offset + shift(_n_coins, 128), - _lp_token, - EMPTY_BYTES32, - True, - False, - _name, - ) - - coins: address[MAX_COINS] = self._get_new_pool_coins(_pool, _n_coins, False, False) - - decimals: uint256 = _decimals - if decimals == 0: - decimals = self._get_new_pool_decimals(coins, _n_coins) - - self.pool_data[_pool].decimals = decimals - self.pool_data[_pool].base_pool = base_pool - - base_coins: address[MAX_COINS] = empty(address[MAX_COINS]) - coin: address = ZERO_ADDRESS - for i in range(MAX_COINS): - if i == base_n_coins + base_coin_offset: - break - if i < base_coin_offset: - coin = coins[i] - else: - x: uint256 = i - base_coin_offset - coin = self.pool_data[base_pool].coins[x] - base_coins[x] = coin - self._register_coin(base_coins[x]) - self.pool_data[_pool].ul_coins[i] = coin - - underlying_decimals: uint256 = shift( - self.pool_data[base_pool].decimals, 8 * convert(base_coin_offset, int128) - ) - underlying_decimals += decimals % 256 ** base_coin_offset - - self.pool_data[_pool].underlying_decimals = underlying_decimals - - for i in range(MAX_COINS): - if i == base_coin_offset: - break - for x in range(MAX_COINS): - if x == base_n_coins: - break - key: uint256 = bitwise_xor(convert(coins[i], uint256), convert(base_coins[x], uint256)) - length: uint256 = self.market_counts[key] - self.markets[key][length] = _pool - self.market_counts[key] = length + 1 - - # register the coin pair - if length == 0: - self._register_coin_pair(coins[i], base_coins[x], key) - - -@external -def remove_pool(_pool: address): - """ - @notice Remove a pool to the registry - @dev Only callable by admin - @param _pool Pool address to remove - """ - assert msg.sender == self.address_provider.admin() # dev: admin-only function - assert self.pool_data[_pool].coins[0] != ZERO_ADDRESS # dev: pool does not exist - - - self.get_pool_from_lp_token[self.get_lp_token[_pool]] = ZERO_ADDRESS - self.get_lp_token[_pool] = ZERO_ADDRESS - - # remove _pool from pool_list - location: uint256 = self.pool_data[_pool].location - length: uint256 = self.pool_count - 1 - - if location < length: - # replace _pool with final value in pool_list - addr: address = self.pool_list[length] - self.pool_list[location] = addr - self.pool_data[addr].location = location - - # delete final pool_list value - self.pool_list[length] = ZERO_ADDRESS - self.pool_count = length - - self.pool_data[_pool].underlying_decimals = 0 - self.pool_data[_pool].decimals = 0 - self.pool_data[_pool].n_coins = 0 - self.pool_data[_pool].name = "" - self.pool_data[_pool].asset_type = 0 - - coins: address[MAX_COINS] = empty(address[MAX_COINS]) - ucoins: address[MAX_COINS] = empty(address[MAX_COINS]) - - for i in range(MAX_COINS): - coins[i] = self.pool_data[_pool].coins[i] - ucoins[i] = self.pool_data[_pool].ul_coins[i] - if ucoins[i] == ZERO_ADDRESS and coins[i] == ZERO_ADDRESS: - break - if coins[i] != ZERO_ADDRESS: - # delete coin address from pool_data - self.pool_data[_pool].coins[i] = ZERO_ADDRESS - self._unregister_coin(coins[i]) - if ucoins[i] != ZERO_ADDRESS: - # delete underlying_coin from pool_data - self.pool_data[_pool].ul_coins[i] = ZERO_ADDRESS - if self.coins[ucoins[i]].register_count != 0: - self._unregister_coin(ucoins[i]) - - is_meta: bool = self.pool_data[_pool].base_pool != ZERO_ADDRESS - for i in range(MAX_COINS): - coin: address = coins[i] - ucoin: address = ucoins[i] - if coin == ZERO_ADDRESS: - break - - # remove pool from markets - i2: uint256 = i + 1 - for x in range(i2, i2 + MAX_COINS): - ucoinx: address = ucoins[x] - if ucoinx == ZERO_ADDRESS: - break - - coinx: address = coins[x] - if coinx != ZERO_ADDRESS: - self._remove_market(_pool, coin, coinx) - - if coin != ucoin or coinx != ucoinx: - self._remove_market(_pool, ucoin, ucoinx) - - if is_meta and not ucoin in coins: - key: uint256 = bitwise_xor(convert(ucoin, uint256), convert(ucoinx, uint256)) - self._register_coin_pair(ucoin, ucoinx, key) - - self.pool_data[_pool].base_pool = ZERO_ADDRESS - self.last_updated = block.timestamp - log PoolRemoved(_pool) - - -@external -def set_pool_gas_estimates(_addr: address[5], _amount: uint256[2][5]): - """ - @notice Set gas estimate amounts - @param _addr Array of pool addresses - @param _amount Array of gas estimate amounts as `[(wrapped, underlying), ..]` - """ - assert msg.sender == self.address_provider.admin() # dev: admin-only function - - for i in range(5): - _pool: address = _addr[i] - if _pool == ZERO_ADDRESS: - break - self.gas_estimate_values[_pool] = _amount[i] - self.last_updated = block.timestamp - - -@external -def set_coin_gas_estimates(_addr: address[10], _amount: uint256[10]): - """ - @notice Set gas estimate amounts - @param _addr Array of coin addresses - @param _amount Array of gas estimate amounts - """ - assert msg.sender == self.address_provider.admin() # dev: admin-only function - - for i in range(10): - _coin: address = _addr[i] - if _coin == ZERO_ADDRESS: - break - self.gas_estimate_values[_coin][0] = _amount[i] - self.last_updated = block.timestamp - - -@external -def set_gas_estimate_contract(_pool: address, _estimator: address): - """ - @notice Set gas estimate contract - @param _pool Pool address - @param _estimator GasEstimator address - """ - assert msg.sender == self.address_provider.admin() # dev: admin-only function - - self.gas_estimate_contracts[_pool] = _estimator - self.last_updated = block.timestamp - - -@external -def set_liquidity_gauges(_pool: address, _liquidity_gauges: address[10]): - """ - @notice Set liquidity gauge contracts`` - @param _pool Pool address - @param _liquidity_gauges Liquidity gauge address - """ - assert msg.sender == self.address_provider.admin() # dev: admin-only function - - _lp_token: address = self.get_lp_token[_pool] - _gauge_controller: address = self.gauge_controller - for i in range(10): - _gauge: address = _liquidity_gauges[i] - if _gauge != ZERO_ADDRESS: - assert LiquidityGauge(_gauge).lp_token() == _lp_token # dev: wrong token - GaugeController(_gauge_controller).gauge_types(_gauge) - self.liquidity_gauges[_pool][i] = _gauge - elif self.liquidity_gauges[_pool][i] != ZERO_ADDRESS: - self.liquidity_gauges[_pool][i] = ZERO_ADDRESS - else: - break - self.last_updated = block.timestamp - - -@external -def set_pool_asset_type(_pool: address, _asset_type: uint256): - """ - @notice Set the asset type name for a curve pool - @dev This is a simple way to setting the cache of categories instead of - performing some computation for no reason. Pool's don't necessarily - change once they are deployed. - @param _pool Pool address - @param _asset_type String of asset type - """ - assert msg.sender == self.address_provider.admin() # dev: admin-only function - - self.pool_data[_pool].asset_type = _asset_type - self.last_updated = block.timestamp - - -@external -def batch_set_pool_asset_type(_pools: address[32], _asset_types: uint256[32]): - """ - @notice Batch set the asset type name for curve pools - @dev This is a simple way of setting the cache of categories instead of - performing some computation for no reason. Pool's don't necessarily - change once they are deployed. - """ - assert msg.sender == self.address_provider.admin() # dev: admin-only function - - for i in range(32): - if _pools[i] == ZERO_ADDRESS: - break - self.pool_data[_pools[i]].asset_type = _asset_types[i] - self.last_updated = block.timestamp diff --git a/contracts/mainnet/registries/BasePoolRegistry.vy b/contracts/mainnet/registries/BasePoolRegistry.vy index 0b9e395..9332a83 100644 --- a/contracts/mainnet/registries/BasePoolRegistry.vy +++ b/contracts/mainnet/registries/BasePoolRegistry.vy @@ -1,4 +1,4 @@ -# @version 0.3.7 +# @version 0.3.10 """ @title Curve BasePool Registry @license MIT diff --git a/contracts/mainnet/registries/CryptoRegistryV1.vy b/contracts/mainnet/registries/CryptoRegistryV1.vy index 65b2680..d88d089 100644 --- a/contracts/mainnet/registries/CryptoRegistryV1.vy +++ b/contracts/mainnet/registries/CryptoRegistryV1.vy @@ -1,4 +1,4 @@ -# @version 0.3.7 +# @version 0.3.10 """ @title Curve CryptoSwap Registry @license MIT diff --git a/contracts/mainnet/registry_handlers/CryptoFactoryHandler.vy b/contracts/mainnet/registry_handlers/CryptoFactoryHandler.vy index a1ce65a..6a42afc 100644 --- a/contracts/mainnet/registry_handlers/CryptoFactoryHandler.vy +++ b/contracts/mainnet/registry_handlers/CryptoFactoryHandler.vy @@ -1,4 +1,4 @@ -# @version 0.3.4 +# @version 0.3.10 """ @title Curve Registry Handler for v2 Factory @license MIT diff --git a/contracts/mainnet/registry_handlers/CryptoRegistryHandler.vy b/contracts/mainnet/registry_handlers/CryptoRegistryHandler.vy index 4b73217..3a2d33e 100644 --- a/contracts/mainnet/registry_handlers/CryptoRegistryHandler.vy +++ b/contracts/mainnet/registry_handlers/CryptoRegistryHandler.vy @@ -1,4 +1,4 @@ -# @version 0.3.4 +# @version 0.3.10 """ @title Curve Registry Handler for v2 Crypto Registry @license MIT diff --git a/contracts/mainnet/registry_handlers/StableFactoryHandler.vy b/contracts/mainnet/registry_handlers/StableFactoryHandler.vy index fd8cfda..4710c93 100644 --- a/contracts/mainnet/registry_handlers/StableFactoryHandler.vy +++ b/contracts/mainnet/registry_handlers/StableFactoryHandler.vy @@ -1,4 +1,4 @@ -# @version 0.3.4 +# @version 0.3.10 """ @title Curve Registry Handler for v1 Factory (latest) @license MIT diff --git a/contracts/mainnet/registry_handlers/StableRegistryHandler.vy b/contracts/mainnet/registry_handlers/StableRegistryHandler.vy index c61cb28..521a3f6 100644 --- a/contracts/mainnet/registry_handlers/StableRegistryHandler.vy +++ b/contracts/mainnet/registry_handlers/StableRegistryHandler.vy @@ -1,4 +1,4 @@ -# @version 0.3.4 +# @version 0.3.10 """ @title Curve Registry Handler for v1 Registry @license MIT diff --git a/docker-compose.yaml b/docker-compose.yaml new file mode 100644 index 0000000..385d6ca --- /dev/null +++ b/docker-compose.yaml @@ -0,0 +1,7 @@ +version: '3.1' + +services: + test: + build: ./ + container_name: metaregistry-test + env_file: .env diff --git a/scripts/setup_metaregistry.py b/scripts/setup_metaregistry.py index 3946e9d..820e783 100644 --- a/scripts/setup_metaregistry.py +++ b/scripts/setup_metaregistry.py @@ -1,11 +1,11 @@ import sys import click -from ape import accounts, project -from ape.cli import NetworkBoundCommand, account_option, network_option -from ape.utils import ZERO_ADDRESS +from eth.constants import ZERO_ADDRESS from rich.console import Console as RichConsole +from tests.utils import get_deployed_contract + RICH_CONSOLE = RichConsole(file=sys.stdout) ADDRESS_PROVIDER = "0x0000000022D53366457F9d5E68Ec105046FC4383" @@ -140,36 +140,22 @@ def cli(): def main(network: str, account: str): # admin only: only admin of ADDRESSPROVIDER's proxy admin can do the following: - address_provider = project.AddressProvider.at(ADDRESS_PROVIDER) + address_provider = get_deployed_contract('AddressProvider', ADDRESS_PROVIDER) address_provider_admin = address_provider.admin() - proxy_admin = project.ProxyAdmin.at(address_provider_admin) + proxy_admin = get_deployed_contract('ProxyAdmin', address_provider_admin) if network == "ethereum:mainnet-fork": RICH_CONSOLE.log("Simulation mode.") account = accounts[proxy_admin.admins(1)] # deployed contracts: - base_pool_registry = project.BasePoolRegistry.at( - "0xDE3eAD9B2145bBA2EB74007e58ED07308716B725" - ) - crypto_registry = project.CryptoRegistryV1.at( - "0x9a32aF1A11D9c937aEa61A3790C2983257eA8Bc0" - ) - stable_registry_handler = project.StableRegistryHandler.at( - "0x46a8a9CF4Fc8e99EC3A14558ACABC1D93A27de68" - ) - stable_factory_handler = project.StableFactoryHandler.at( - "0x127db66E7F0b16470Bec194d0f496F9Fa065d0A9" - ) - crypto_registry_handler = project.CryptoRegistryHandler.at( - "0x5f493fEE8D67D3AE3bA730827B34126CFcA0ae94" - ) - crypto_factory_handler = project.CryptoFactoryHandler.at( - "0xC4F389020002396143B863F6325aA6ae481D19CE" - ) - metaregistry = project.MetaRegistry.at( - "0xF98B45FA17DE75FB1aD0e7aFD971b0ca00e379fC" - ) + base_pool_registry = get_deployed_contract('BasePoolRegistry', "0xDE3eAD9B2145bBA2EB74007e58ED07308716B725") + crypto_registry = get_deployed_contract('CryptoRegistryV1', "0x9a32aF1A11D9c937aEa61A3790C2983257eA8Bc0") + stable_registry_handler = get_deployed_contract('StableRegistryHandler', "0x46a8a9CF4Fc8e99EC3A14558ACABC1D93A27de68") + stable_factory_handler = get_deployed_contract('StableFactoryHandler', "0x127db66E7F0b16470Bec194d0f496F9Fa065d0A9") + crypto_registry_handler = get_deployed_contract('CryptoRegistryHandler', "0x5f493fEE8D67D3AE3bA730827B34126CFcA0ae94") + crypto_factory_handler = get_deployed_contract('CryptoFactoryHandler', "0xC4F389020002396143B863F6325aA6ae481D19CE") + metaregistry = get_deployed_contract('MetaRegistry', "0xF98B45FA17DE75FB1aD0e7aFD971b0ca00e379fC") registry_handlers = [ stable_registry_handler, stable_factory_handler, diff --git a/tests/conftest.py b/tests/conftest.py index 2c4f61e..bd9aa58 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,6 +1,9 @@ -import pytest +from os import environ + import boa -from boa.network import NetworkEnv +import pytest + +from tests.utils import get_contract_pools pytest_plugins = [ "fixtures.accounts", @@ -25,15 +28,15 @@ def pytest_sessionstart(): global STABLE_REGISTRY_POOLS global ALL_POOLS - boa.env.fork("https://mainnet.infura.io/v3/84842078b09946638c03157f83405213") + # connect to the network. TODO: use Drpc-Key header instead of GET param + boa.env.fork(f"https://lb.drpc.org/ogrpc?network=ethereum&dkey={environ['DRPC_KEY']}") - # store instance of registries globally, so we don't have to recreate multiple times - # when generating tests: - - STABLE_REGISTRY_POOLS = get_pools("StableRegistry", "0x90E00ACe148ca3b23Ac1bC8C240C2a7Dd9c2d7f5") - STABLE_FACTORY_POOLS = get_pools("StableFactory", "0xB9fC157394Af804a3578134A6585C0dc9cc990d4") - CRYPTO_REGISTRY_POOLS = get_pools("CryptoRegistry", "0x8F942C20D02bEfc377D41445793068908E2250D0") - CRYPTO_FACTORY_POOLS = get_pools("CryptoFactory", "0xF18056Bbd320E96A48e3Fbf8bC061322531aac99") + # store instance of registries globally, so we don't have to recreate multiple times when generating tests. + # TODO: Can we move these to fixtures? + STABLE_REGISTRY_POOLS = get_contract_pools("StableRegistry", "0x90E00ACe148ca3b23Ac1bC8C240C2a7Dd9c2d7f5") + STABLE_FACTORY_POOLS = get_contract_pools("StableFactory", "0xB9fC157394Af804a3578134A6585C0dc9cc990d4") + CRYPTO_REGISTRY_POOLS = get_contract_pools("CryptoRegistry", "0x8F942C20D02bEfc377D41445793068908E2250D0") + CRYPTO_FACTORY_POOLS = get_contract_pools("CryptoFactory", "0xF18056Bbd320E96A48e3Fbf8bC061322531aac99") ALL_POOLS = ( STABLE_REGISTRY_POOLS @@ -43,12 +46,6 @@ def pytest_sessionstart(): ) -def get_pools(registryName, registryAddress): - deployer = boa.load_partial(f"contracts/mainnet/mocks/{registryName}", registryName) - registry = deployer.at(registryAddress) - return [registry.pool_list(i) for i in range(registry.pool_count())] - - def pytest_generate_tests(metafunc): if "stable_registry_pool" in metafunc.fixturenames: metafunc.parametrize("stable_registry_pool", STABLE_REGISTRY_POOLS) diff --git a/tests/fixtures/accounts.py b/tests/fixtures/accounts.py index 5708cff..d4b5a7d 100644 --- a/tests/fixtures/accounts.py +++ b/tests/fixtures/accounts.py @@ -1,12 +1,13 @@ +import logging from collections import namedtuple import pytest from eth_account import Account from eth_account.hdaccount import HDPath from eth_account.hdaccount.mnemonic import Mnemonic -from ethpm_types import HexBytes +from eth_account.signers.local import LocalAccount -GeneratedDevAccount = namedtuple("GeneratedDevAccount", ("address", "private_key")) +from tests.utils import get_deployed_contract @pytest.fixture(scope="session") @@ -14,38 +15,35 @@ def seed() -> bytes: return Mnemonic.to_seed("test") @pytest.fixture(scope="session") -def accounts(seed) -> list[GeneratedDevAccount]: +def accounts(seed) -> list[LocalAccount]: """ Generate 10 dev accounts from a seed. Based on ape's `generate_test_accounts` method: https://github.com/ApeWorX/ape/blob/9d4b66786/src/ape/utils/testing.py#L28 """ - def generate_account(index: int, hd_path_format="m/44'/60'/0'/{}") -> GeneratedDevAccount: + def generate_account(index: int, hd_path_format="m/44'/60'/0'/{}") -> LocalAccount: hd_path = HDPath(hd_path_format.format(index)) - private_key = HexBytes(hd_path.derive(seed)).hex() - address = Account.from_key(private_key).address - return GeneratedDevAccount(address, private_key) + private_key = f"0x{hd_path.derive(seed).hex()}" + return Account.from_key(private_key) return [generate_account(index) for index in range(10)] @pytest.fixture(scope="session") -def alice(accounts): - return accounts[0] +def alice_address(accounts): + return accounts[0].address @pytest.fixture(scope="session") -def unauthorised_account(accounts): - return accounts[1] +def unauthorised_address(accounts): + return accounts[1].address @pytest.fixture(scope="session") def random_address(accounts): - return accounts[2] + return accounts[2].address @pytest.fixture(scope="module") def owner(accounts): - address_provider = ape.project.AddressProvider.at( - "0x0000000022D53366457F9d5E68Ec105046FC4383" - ) - return accounts[address_provider.admin()] + address_provider = get_deployed_contract('AddressProvider', "0x0000000022D53366457F9d5E68Ec105046FC4383") + return address_provider.admin() diff --git a/tests/fixtures/constants.py b/tests/fixtures/constants.py index 1aeaeb2..5001718 100644 --- a/tests/fixtures/constants.py +++ b/tests/fixtures/constants.py @@ -1,7 +1,9 @@ -import ape import pytest +ZERO_ADDRESS = "0x0000000000000000000000000000000000000000" + + @pytest.fixture(scope="module") def base_pools(): @@ -47,7 +49,7 @@ def crypto_registry_pools(base_pools): "zap": "0x3993d34e7e99Abf6B6f367309975d1360222D446", "num_coins": 3, "name": "tricrypto2", - "base_pool": ape.utils.ZERO_ADDRESS, + "base_pool": ZERO_ADDRESS, "has_positive_rebasing_tokens": False, } @@ -66,10 +68,10 @@ def crypto_registry_pools(base_pools): "pool": "0x98a7F18d4E56Cfe84E3D081B40001B3d5bD3eB8B", "lp_token": "0x3D229E1B4faab62F621eF2F6A610961f7BD7b23B", "gauge": "0x65CA7Dc5CB661fC58De57B1E1aF404649a27AD35", - "zap": ape.utils.ZERO_ADDRESS, + "zap": ZERO_ADDRESS, "num_coins": 2, "name": "eursusd", - "base_pool": ape.utils.ZERO_ADDRESS, + "base_pool": ZERO_ADDRESS, "has_positive_rebasing_tokens": False, } @@ -77,10 +79,10 @@ def crypto_registry_pools(base_pools): "pool": "0x8301AE4fc9c624d1D396cbDAa1ed877821D7C511", "lp_token": "0xEd4064f376cB8d68F770FB1Ff088a3d0F3FF5c4d", "gauge": "0x1cEBdB0856dd985fAe9b8fEa2262469360B8a3a6", - "zap": ape.utils.ZERO_ADDRESS, + "zap": ZERO_ADDRESS, "num_coins": 2, "name": "crveth", - "base_pool": ape.utils.ZERO_ADDRESS, + "base_pool": ZERO_ADDRESS, "has_positive_rebasing_tokens": False, } @@ -88,10 +90,10 @@ def crypto_registry_pools(base_pools): "pool": "0xB576491F1E6e5E62f1d8F26062Ee822B40B0E0d4", "lp_token": "0x3A283D9c08E8b55966afb64C515f5143cf907611", "gauge": "0x7E1444BA99dcdFfE8fBdb42C02F0005D14f13BE1", - "zap": ape.utils.ZERO_ADDRESS, + "zap": ZERO_ADDRESS, "num_coins": 2, "name": "cvxeth", - "base_pool": ape.utils.ZERO_ADDRESS, + "base_pool": ZERO_ADDRESS, "has_positive_rebasing_tokens": False, } @@ -110,10 +112,10 @@ def crypto_registry_pools(base_pools): "pool": "0x98638FAcf9a3865cd033F36548713183f6996122", "lp_token": "0x8282BD15dcA2EA2bDf24163E8f2781B30C43A2ef", "gauge": "0x08380a4999Be1a958E2abbA07968d703C7A3027C", - "zap": ape.utils.ZERO_ADDRESS, + "zap": ZERO_ADDRESS, "num_coins": 2, "name": "spelleth", - "base_pool": ape.utils.ZERO_ADDRESS, + "base_pool": ZERO_ADDRESS, "has_positive_rebasing_tokens": False, } @@ -121,10 +123,10 @@ def crypto_registry_pools(base_pools): "pool": "0x752eBeb79963cf0732E9c0fec72a49FD1DEfAEAC", "lp_token": "0xCb08717451aaE9EF950a2524E33B6DCaBA60147B", "gauge": "0x6070fBD4E608ee5391189E7205d70cc4A274c017", - "zap": ape.utils.ZERO_ADDRESS, + "zap": ZERO_ADDRESS, "num_coins": 2, "name": "teth", - "base_pool": ape.utils.ZERO_ADDRESS, + "base_pool": ZERO_ADDRESS, "has_positive_rebasing_tokens": False, } diff --git a/tests/fixtures/contracts.py b/tests/fixtures/contracts.py index 96e39d0..b7192f2 100644 --- a/tests/fixtures/contracts.py +++ b/tests/fixtures/contracts.py @@ -3,7 +3,7 @@ @pytest.fixture(scope="module") def address_provider_contract(accounts): - address_provider = ape.project.AddressProvider.at( + address_provider = get_deployed_contract('AddressProvider', "0x0000000022D53366457F9d5E68Ec105046FC4383" ) return accounts[address_provider.admin()] diff --git a/tests/fixtures/deployments.py b/tests/fixtures/deployments.py index ef57cd1..51d9fa4 100644 --- a/tests/fixtures/deployments.py +++ b/tests/fixtures/deployments.py @@ -1,45 +1,41 @@ +import boa import pytest +from boa.vyper.contract import VyperContract + +from tests.utils import get_deployed_contract, deploy_contract ADDRESS_PROVIDER = "0x0000000022D53366457F9d5E68Ec105046FC4383" @pytest.fixture(scope="module", autouse=True) -def gauge_controller() -> ape.Contract: - return ape.project.GaugeController.at( - "0x2F50D538606Fa9EDD2B11E2446BEb18C9D5846bB" - ) +def gauge_controller() -> VyperContract: + return get_deployed_contract('GaugeController', "0x2F50D538606Fa9EDD2B11E2446BEb18C9D5846bB") @pytest.fixture(scope="module", autouse=True) -def stable_registry() -> ape.Contract: - return ape.project.StableRegistry.at( - "0x90E00ACe148ca3b23Ac1bC8C240C2a7Dd9c2d7f5" - ) +def stable_registry() -> VyperContract: + return get_deployed_contract('StableRegistry', "0x90E00ACe148ca3b23Ac1bC8C240C2a7Dd9c2d7f5") @pytest.fixture(scope="module", autouse=True) -def stable_factory() -> ape.Contract: - return ape.project.StableFactory.at( - "0xB9fC157394Af804a3578134A6585C0dc9cc990d4" - ) +def stable_factory() -> VyperContract: + return get_deployed_contract('StableFactory', "0xB9fC157394Af804a3578134A6585C0dc9cc990d4") @pytest.fixture(scope="module", autouse=True) -def crypto_factory() -> ape.Contract: - return ape.project.CryptoFactory.at( - "0xF18056Bbd320E96A48e3Fbf8bC061322531aac99" - ) +def crypto_factory() -> VyperContract: + return get_deployed_contract('CryptoFactory', "0xF18056Bbd320E96A48e3Fbf8bC061322531aac99") @pytest.fixture(scope="module", autouse=True) -def base_pool_registry(alice, project): - return project.BasePoolRegistry.deploy(sender=alice) +def base_pool_registry(alice_address): + return deploy_contract("BasePoolRegistry", sender=alice_address, directory="registries") @pytest.fixture(scope="module", autouse=True) def populated_base_pool_registry(base_pool_registry, owner, base_pools): - - for _, data in base_pools.items(): + for data in base_pools.values(): + boa.env.eoa = owner base_pool_registry.add_base_pool( data["pool"], data["lp_token"], @@ -47,9 +43,7 @@ def populated_base_pool_registry(base_pool_registry, owner, base_pools): data["is_legacy"], data["is_lending"], data["is_v2"], - sender=owner, ) - return base_pool_registry @@ -57,10 +51,8 @@ def populated_base_pool_registry(base_pool_registry, owner, base_pools): def crypto_registry( populated_base_pool_registry, owner, crypto_registry_pools ): - - crypto_registry = ape.project.CryptoRegistryV1.deploy( - ADDRESS_PROVIDER, populated_base_pool_registry, sender=owner - ) + crypto_registry = deploy_contract("CryptoRegistryV1", ADDRESS_PROVIDER, populated_base_pool_registry, + directory="registries", sender=owner) for _, pool in crypto_registry_pools.items(): crypto_registry.add_pool( @@ -80,78 +72,61 @@ def crypto_registry( @pytest.fixture(scope="module", autouse=True) def address_provider(crypto_registry, owner): - contract = ape.project.AddressProvider.at(ADDRESS_PROVIDER) + contract = get_deployed_contract('AddressProvider', ADDRESS_PROVIDER) contract.set_address(5, crypto_registry, sender=owner) return contract @pytest.fixture(scope="module", autouse=True) -def metaregistry(address_provider, owner, project): - return project.MetaRegistry.deploy(address_provider, sender=owner) +def metaregistry(address_provider, owner): + return deploy_contract("MetaRegistry", address_provider, sender=owner) @pytest.fixture(scope="module", autouse=True) -def stable_registry_handler(stable_registry, owner, project): - return project.StableRegistryHandler.deploy( - stable_registry.address, sender=owner +def stable_registry_handler(stable_registry, owner): + return deploy_contract( + "StableRegistryHandler", stable_registry.address, + sender=owner, directory="registry_handlers", override_address=stable_registry.address, ) @pytest.fixture(scope="module", autouse=True) -def stable_factory_handler( - populated_base_pool_registry, stable_factory, owner, project -): - return project.StableFactoryHandler.deploy( - stable_factory.address, populated_base_pool_registry, sender=owner +def stable_factory_handler(populated_base_pool_registry, stable_factory, owner): + return deploy_contract( + "StableFactoryHandler", stable_factory.address, populated_base_pool_registry.address, + sender=owner, directory="registry_handlers", override_address=stable_factory.address, ) @pytest.fixture(scope="module", autouse=True) -def crypto_registry_handler(owner, crypto_registry, project): - return project.CryptoRegistryHandler.deploy(crypto_registry, sender=owner) +def crypto_registry_handler(owner, crypto_registry): + return deploy_contract( + "CryptoRegistryHandler", crypto_registry.address, sender=owner, directory="registry_handlers", + ) @pytest.fixture(scope="module", autouse=True) -def crypto_factory_handler( - populated_base_pool_registry, crypto_factory, owner, project -): - return project.CryptoFactoryHandler.deploy( - crypto_factory.address, populated_base_pool_registry, sender=owner +def crypto_factory_handler(populated_base_pool_registry, crypto_factory, owner): + return deploy_contract( + "CryptoFactoryHandler", crypto_factory.address, populated_base_pool_registry.address, + sender=owner, directory="registry_handlers", override_address=crypto_factory.address, ) @pytest.fixture(scope="module") -def registries( - stable_registry, stable_factory, crypto_registry, crypto_factory -): - return [ - stable_registry, - stable_factory, - crypto_registry, - crypto_factory, - ] +def registries(stable_registry, stable_factory, crypto_registry, crypto_factory): + return [stable_registry, stable_factory, crypto_registry, crypto_factory] @pytest.fixture(scope="module") -def handlers( - stable_registry_handler, - stable_factory_handler, - crypto_registry_handler, - crypto_factory_handler, -): - return [ - stable_registry_handler, - stable_factory_handler, - crypto_registry_handler, - crypto_factory_handler, - ] +def handlers(stable_registry_handler, stable_factory_handler, crypto_registry_handler, crypto_factory_handler): + return [stable_registry_handler, stable_factory_handler, crypto_registry_handler, crypto_factory_handler] @pytest.fixture(scope="module", autouse=True) def populated_metaregistry(metaregistry, handlers, owner): for handler in handlers: metaregistry.add_registry_handler(handler.address, sender=owner) - return metaregistry diff --git a/tests/fixtures/functions.py b/tests/fixtures/functions.py index 706e5a3..0acbddd 100644 --- a/tests/fixtures/functions.py +++ b/tests/fixtures/functions.py @@ -1,30 +1,33 @@ from typing import Callable -import ape import pytest +from boa.vyper.contract import VyperContract + +from tests.utils import get_deployed_contract + # ---- Factories ---- @pytest.fixture(scope="module") def curve_pool(project) -> Callable: - def _initialise(_pool: str) -> ape.Contract: - return project.CurvePool.at(_pool) + def _initialise(_pool: str) -> VyperContract: + return get_deployed_contract('CurvePool', _pool) return _initialise @pytest.fixture(scope="module") def curve_pool_v2(project) -> Callable: - def _initialise(_pool: str) -> ape.Contract: - return project.CurvePoolV2.at(_pool) + def _initialise(_pool: str) -> VyperContract: + return get_deployed_contract('CurvePoolV2', _pool) return _initialise @pytest.fixture(scope="module") def liquidity_gauge(project) -> Callable: - def _initialise(_gauge: str) -> ape.Contract: - return project.LiquidityGauge.at(_gauge) + def _initialise(_gauge: str) -> VyperContract: + return get_deployed_contract('LiquidityGauge', _gauge) return _initialise diff --git a/tests/mainnet/metaregistry/api/test_get_admin_balances.py b/tests/mainnet/metaregistry/api/test_get_admin_balances.py index cd28d04..2346257 100644 --- a/tests/mainnet/metaregistry/api/test_get_admin_balances.py +++ b/tests/mainnet/metaregistry/api/test_get_admin_balances.py @@ -8,7 +8,7 @@ def pre_test_checks(metaregistry, pool): pytest.skip("empty pool: skipping") try: - if ape.Contract(metaregistry.get_lp_token(pool)).totalSupply() == 0: + if VyperContract(metaregistry.get_lp_token(pool)).totalSupply() == 0: pytest.skip("lp token supply is zero") except ape.exceptions.SignatureError: pytest.skip( @@ -50,14 +50,14 @@ def test_stable_factory_pools( def _get_crypto_pool_admin_fees( - populated_metaregistry, pool, fee_receiver, project, alice, chain + populated_metaregistry, pool, fee_receiver, project, alice_address, chain ): - lp_token = ape.Contract(populated_metaregistry.get_lp_token(pool)) + lp_token = VyperContract(populated_metaregistry.get_lp_token(pool)) fee_receiver_token_balance_before = lp_token.balanceOf(fee_receiver) chain.snapshot() - pool.claim_admin_fees(sender=alice) + pool.claim_admin_fees(sender=alice_address) claimed_lp_token_as_fee = ( lp_token.balanceOf(fee_receiver) - fee_receiver_token_balance_before @@ -81,7 +81,7 @@ def test_crypto_registry_pools( populated_metaregistry, crypto_registry_pool, curve_pool_v2, - alice, + alice_address, chain, project, ): @@ -91,7 +91,7 @@ def test_crypto_registry_pools( pool = curve_pool_v2(crypto_registry_pool) fee_receiver = pool.admin_fee_receiver() admin_balances = _get_crypto_pool_admin_fees( - populated_metaregistry, pool, fee_receiver, project, alice, chain + populated_metaregistry, pool, fee_receiver, project, alice_address, chain ) metaregistry_output = populated_metaregistry.get_admin_balances(pool) @@ -104,7 +104,7 @@ def test_crypto_factory_pools( crypto_factory_pool, crypto_factory, curve_pool_v2, - alice, + alice_address, chain, project, ): @@ -114,7 +114,7 @@ def test_crypto_factory_pools( pool = curve_pool_v2(crypto_factory_pool) fee_receiver = crypto_factory.fee_receiver() admin_balances = _get_crypto_pool_admin_fees( - populated_metaregistry, pool, fee_receiver, project, alice, chain + populated_metaregistry, pool, fee_receiver, project, alice_address, chain ) metaregistry_output = populated_metaregistry.get_admin_balances(pool) diff --git a/tests/mainnet/metaregistry/api/test_get_pool_name.py b/tests/mainnet/metaregistry/api/test_get_pool_name.py index b95d3d1..a1fca59 100644 --- a/tests/mainnet/metaregistry/api/test_get_pool_name.py +++ b/tests/mainnet/metaregistry/api/test_get_pool_name.py @@ -29,7 +29,7 @@ def test_stable_factory_pools(populated_metaregistry, stable_factory_pool): assert ( populated_metaregistry.get_pool_name(stable_factory_pool) - == ape.Contract(stable_factory_pool).name() + == VyperContract(stable_factory_pool).name() ) elif num_registry_handlers == 2: @@ -38,12 +38,12 @@ def test_stable_factory_pools(populated_metaregistry, stable_factory_pool): assert ( populated_metaregistry.get_pool_name(stable_factory_pool) - == ape.Contract(stable_factory_pool).name() + == VyperContract(stable_factory_pool).name() ) assert ( populated_metaregistry.get_pool_name(stable_factory_pool, 1) - == ape.Contract(stable_factory_pool).name() + == VyperContract(stable_factory_pool).name() ) else: @@ -66,5 +66,5 @@ def test_crypto_factory_pools( assert ( populated_metaregistry.get_pool_name(crypto_factory_pool) - == ape.Contract(crypto_factory.get_token(crypto_factory_pool)).name() + == VyperContract(crypto_factory.get_token(crypto_factory_pool)).name() ) diff --git a/tests/mainnet/metaregistry/api/test_get_underlying_balances.py b/tests/mainnet/metaregistry/api/test_get_underlying_balances.py index dd22621..e413fd8 100644 --- a/tests/mainnet/metaregistry/api/test_get_underlying_balances.py +++ b/tests/mainnet/metaregistry/api/test_get_underlying_balances.py @@ -34,7 +34,7 @@ def _get_underlying_balances( if base_pool != ape.utils.ZERO_ADDRESS: basepool_lp_token_balance = balances[idx] - coin_contract = ape.Contract(coin) + coin_contract = VyperContract(coin) try: lp_token_supply = coin_contract.totalSupply() except (ape.exceptions.SignatureError, AttributeError): diff --git a/tests/mainnet/metaregistry/api/test_get_underlying_decimals.py b/tests/mainnet/metaregistry/api/test_get_underlying_decimals.py index 4824ede..ef101f1 100644 --- a/tests/mainnet/metaregistry/api/test_get_underlying_decimals.py +++ b/tests/mainnet/metaregistry/api/test_get_underlying_decimals.py @@ -32,7 +32,7 @@ def _test_underlying_decimals_getter(metaregistry, registry, pool): continue try: - token_contract = ape.Contract(underlying_coins[i]) + token_contract = VyperContract(underlying_coins[i]) actual_output.append(token_contract.decimals()) except ape.exceptions.ChainError: pytest.skip("Unverified contract. Skipping test.") diff --git a/tests/mainnet/metaregistry/api/test_get_virtual_price.py b/tests/mainnet/metaregistry/api/test_get_virtual_price.py index b92b9b1..594dc4c 100644 --- a/tests/mainnet/metaregistry/api/test_get_virtual_price.py +++ b/tests/mainnet/metaregistry/api/test_get_virtual_price.py @@ -39,7 +39,7 @@ def _check_skem_tokens_with_weird_decimals( if ( coin_decimals[i] == 0 - and ape.Contract(metaregistry.get_coins(pool)[0]).decimals() == 0 + and VyperContract(metaregistry.get_coins(pool)[0]).decimals() == 0 ): with ape.reverts(): metaregistry.get_virtual_price_from_lp_token(lp_token) diff --git a/tests/mainnet/metaregistry/test_add_remove_update_registry.py b/tests/mainnet/metaregistry/test_add_remove_update_registry.py index 4844c5e..f5a81ab 100644 --- a/tests/mainnet/metaregistry/test_add_remove_update_registry.py +++ b/tests/mainnet/metaregistry/test_add_remove_update_registry.py @@ -1,22 +1,22 @@ -import ape +import boa def test_revert_unauthorised_add_registry_handler( - metaregistry, unauthorised_account, random_address + metaregistry, unauthorised_address, random_address ): - with ape.reverts(): + with boa.reverts(): tx = metaregistry.add_registry_handler( - random_address, sender=unauthorised_account + random_address, sender=unauthorised_address ) assert tx.revert_msg == "dev: only owner" def test_revert_unauthorised_update_registry_handler( - populated_metaregistry, unauthorised_account, random_address + populated_metaregistry, unauthorised_address, random_address ): - with ape.reverts(): + with boa.reverts(): tx = populated_metaregistry.update_registry_handler( - 0, random_address, sender=unauthorised_account + 0, random_address, sender=unauthorised_address ) assert tx.revert_msg == "dev: only owner" @@ -24,7 +24,7 @@ def test_revert_unauthorised_update_registry_handler( def test_update_registry_handler_invalid_registry( populated_metaregistry, random_address, owner ): - with ape.reverts(): + with boa.reverts(): populated_metaregistry.update_registry_handler( 10, random_address, sender=owner ) diff --git a/tests/mainnet/metaregistry/test_base_registry_tracking.py b/tests/mainnet/metaregistry/test_base_registry_tracking.py index 6e716ce..557cf76 100644 --- a/tests/mainnet/metaregistry/test_base_registry_tracking.py +++ b/tests/mainnet/metaregistry/test_base_registry_tracking.py @@ -2,7 +2,7 @@ def test_new_crypto_factory_pool( - metaregistry, crypto_factory, tokens, lp_tokens, alice + metaregistry, crypto_factory, tokens, lp_tokens, alice_address ): test_pool_name = "test_pool" @@ -27,7 +27,7 @@ def test_new_crypto_factory_pool( 5000000000, 600, 994000214704046300, - sender=alice, + sender=alice_address, ) new_pool = crypto_factory.pool_list(crypto_factory.pool_count() - 1) lp_token = crypto_factory.get_token(new_pool) @@ -48,7 +48,7 @@ def test_new_crypto_factory_pool( def test_new_stable_factory_pool( - metaregistry, stable_factory, lp_tokens, alice + metaregistry, stable_factory, lp_tokens, alice_address ): test_pool_name = "test_pool" @@ -72,7 +72,7 @@ def test_new_stable_factory_pool( 4000000, 0, 0, - sender=alice, + sender=alice_address, ) new_pool = stable_factory.pool_list(stable_factory.pool_count() - 1) diff --git a/tests/mainnet/registries/test_add_remove_basepool.py b/tests/mainnet/registries/test_add_remove_basepool.py index 85bbbf0..2747749 100644 --- a/tests/mainnet/registries/test_add_remove_basepool.py +++ b/tests/mainnet/registries/test_add_remove_basepool.py @@ -2,7 +2,7 @@ def test_revert_unauthorised_add_base_pool( - owner, unauthorised_account, base_pools + owner, unauthorised_address, base_pools ): base_pool_registry = ape.project.BasePoolRegistry.deploy(sender=owner) @@ -16,7 +16,7 @@ def test_revert_unauthorised_add_base_pool( base_pool_data["is_legacy"], base_pool_data["is_lending"], base_pool_data["is_v2"], - sender=unauthorised_account, + sender=unauthorised_address, ) @@ -92,7 +92,7 @@ def test_add_basepool_with_legacy_abi(owner, base_pools, tokens): def test_revert_unauthorised_remove_base_pool( - populated_base_pool_registry, unauthorised_account, base_pools + populated_base_pool_registry, unauthorised_address, base_pools ): tripool_address = base_pools["tripool"]["pool"] @@ -103,7 +103,7 @@ def test_revert_unauthorised_remove_base_pool( ) with ape.reverts(): populated_base_pool_registry.remove_base_pool( - tripool_address, sender=unauthorised_account + tripool_address, sender=unauthorised_address ) diff --git a/tests/mainnet/registries/test_add_remove_pool.py b/tests/mainnet/registries/test_add_remove_pool.py index 5b42fd1..bb2653b 100644 --- a/tests/mainnet/registries/test_add_remove_pool.py +++ b/tests/mainnet/registries/test_add_remove_pool.py @@ -2,7 +2,7 @@ def test_revert_unauthorised_add_pool( - crypto_registry, unauthorised_account, crypto_registry_pools + crypto_registry, unauthorised_address, crypto_registry_pools ): pool_data = crypto_registry_pools["tricrypto2"] @@ -17,7 +17,7 @@ def test_revert_unauthorised_add_pool( pool_data["name"], pool_data["base_pool"], pool_data["has_positive_rebasing_tokens"], - sender=unauthorised_account, + sender=unauthorised_address, ) @@ -140,13 +140,13 @@ def test_add_pool( def test_revert_unauthorised_remove_pool( - crypto_registry, unauthorised_account, crypto_registry_pools + crypto_registry, unauthorised_address, crypto_registry_pools ): with ape.reverts(): crypto_registry.remove_pool( crypto_registry_pools["tricrypto2"]["pool"], - sender=unauthorised_account, + sender=unauthorised_address, ) diff --git a/tests/utils.py b/tests/utils.py new file mode 100644 index 0000000..5e7ff62 --- /dev/null +++ b/tests/utils.py @@ -0,0 +1,35 @@ +from os import path +from typing import Union + +import boa +from boa.vyper.contract import VyperContract +from eth_account.signers.local import LocalAccount + +BASE_DIR = path.join(path.dirname(path.abspath(__file__)), "..") + + +def get_contract_pools(contract: str, address: str) -> list[str]: + """ + Retrieves the list of pools from a deployed contract with the given address. + :param contract: The name of the contract to load. + :param address: The address of the deployed contract. + """ + registry = get_deployed_contract(contract, address) + return [registry.pool_list(i) for i in range(registry.pool_count())] + + +def get_deployed_contract(contract_abi: str, address: str) -> VyperContract: + """ + Loads a contract and retrieves a deployed instance of it with the given address. + TODO: Refactor calls to use fixtures instead of re-loading multiple times. + :param contract_abi: The name of the contract to load. + :param address: The address of the deployed contract. + """ + file_name = path.join(BASE_DIR, f"contracts/mainnet/abi/{contract_abi}.json") + return boa.load_abi(file_name).at(address) + + +def deploy_contract(contract: str, *args, sender: Union[LocalAccount, str], directory: str = ".", **kwargs): + file_name = path.join(BASE_DIR, f"contracts/mainnet/{directory}/{contract}.vy") + boa.env.eoa = sender if isinstance(sender, str) else sender.address + return boa.load(file_name, *args, **kwargs)