diff --git a/README.md b/README.md index 5e686096..91bb5ba2 100755 --- a/README.md +++ b/README.md @@ -230,6 +230,7 @@ All the deployed contracts' addresses are available [here](../../wiki/Addresses) | [Synthetix](./contracts/adapters/synthetix) | Synthetic assets protocol. Asset adapter returns amount of SNX locked as collateral. | [Asset adapter](./contracts/adapters/synthetix/SynthetixAssetAdapter.sol)
[Debt adapter](./contracts/adapters/synthetix/SynthetixDebtAdapter.sol) | — | | [TokenSets](./contracts/adapters/tokenSets) | Automated asset management strategies. | [Asset adapter](./contracts/adapters/tokenSets/TokenSetsAdapter.sol)
[Asset adapter V2](./contracts/adapters/tokenSets/TokenSetsV2Adapter.sol) | ["SetToken"](./contracts/adapters/tokenSets/TokenSetsTokenAdapter.sol)
["SetToken V2"](./contracts/adapters/tokenSets/TokenSetsV2TokenAdapter.sol) | | [Unagii](./contracts/adapters/unagii) | DeFi yields on auto-pilot. | [Asset adapter](./contracts/adapters/unagii/UnagiiVaultAdapter.sol) | — | +| [Unagii V2](./contracts/adapters/unagii) | DeFi yields on auto-pilot. | [Asset adapter](./contracts/adapters/unagii/UnagiiVaultV2Adapter.sol) | — | | [Uniswap V1](./contracts/adapters/uniswap) | Automated liquidity protocol. | [Asset adapter](./contracts/adapters/uniswap/UniswapV1Adapter.sol) supports all Uniswap V1 pools | ["Uniswap V1 pool token"](./contracts/adapters/uniswap/UniswapV1TokenAdapter.sol) | | [Uniswap V2](./contracts/adapters/uniswap) | Automated liquidity protocol. | [Asset adapter](./contracts/adapters/uniswap/UniswapV2Adapter.sol) supports all Uniswap V2 pools | ["Uniswap V2 pool token"](./contracts/adapters/uniswap/UniswapV2TokenAdapter.sol) | | [0x Staking](./contracts/adapters/zrx) | Liquidity rewards for staking ZRX. | [Asset adapter](./contracts/adapters/zrx/ZrxAdapter.sol) | — | diff --git a/contracts/adapters/unagii/UnagiiVaultV2Adapter.sol b/contracts/adapters/unagii/UnagiiVaultV2Adapter.sol new file mode 100644 index 00000000..333e7446 --- /dev/null +++ b/contracts/adapters/unagii/UnagiiVaultV2Adapter.sol @@ -0,0 +1,46 @@ +// Copyright (C) 2020 Zerion Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity 0.6.5; +pragma experimental ABIEncoderV2; + +import { ERC20 } from "../../ERC20.sol"; +import { ProtocolAdapter } from "../ProtocolAdapter.sol"; + +interface UnagiiVaultV2 { + function uToken() external view returns (address); +} + +/** + * @title Adapter for Unagii V2 protocol. + * @dev Implementation of ProtocolAdapter interface. + * @author Igor Sobolev + */ +contract UnagiiVaultV2Adapter is ProtocolAdapter { + + string public constant override adapterType = "Asset"; + + string public constant override tokenType = "UnagiiV2 token"; + + /** + * @return Amount of Unagii Vault V2 Tokens owned by the given account. + * @param token Address of the vault token. + * @dev Implementation of ProtocolAdapter interface function. + */ + function getBalance(address token, address account) external view override returns (uint256) { + address uToken = UnagiiVaultV2(token).uToken(); + return ERC20(uToken).balanceOf(account); + } +} diff --git a/contracts/adapters/unagii/UnagiiVaultV2TokenAdapter.sol b/contracts/adapters/unagii/UnagiiVaultV2TokenAdapter.sol new file mode 100644 index 00000000..0fc4ae34 --- /dev/null +++ b/contracts/adapters/unagii/UnagiiVaultV2TokenAdapter.sol @@ -0,0 +1,67 @@ +// Copyright (C) 2020 Zerion Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity 0.6.5; +pragma experimental ABIEncoderV2; + +import { ERC20 } from "../../ERC20.sol"; +import { TokenMetadata, Component } from "../../Structs.sol"; +import { TokenAdapter } from "../TokenAdapter.sol"; + +interface UnagiiVaultV2 { + function token() external view returns (address); + + function calcWithdraw(uint256) external view returns (uint256); +} + +/** + * @title Token adapter for Unagii Vaults V2. + * @dev Implementation of TokenAdapter interface. + * @author Igor Sobolev + */ +contract UnagiiVaultV2TokenAdapter is TokenAdapter { + + /** + * @return TokenMetadata struct with ERC20-style token info. + * @dev Implementation of TokenAdapter interface function. + */ + function getMetadata(address token) external view override returns (TokenMetadata memory) { + return TokenMetadata({ + token: token, + name: ERC20(token).name(), + symbol: ERC20(token).symbol(), + decimals: ERC20(token).decimals() + }); + } + + /** + * @return Array of Component structs with underlying tokens rates for the given token. + * @dev Implementation of TokenAdapter abstract contract function. + */ + function getComponents(address token) external view override returns (Component[] memory) { + address underlying = UnagiiVaultV2(token).token(); + uint256 pricing = UnagiiVaultV2(token).calcWithdraw(1e18); + + Component[] memory underlyingTokens = new Component[](1); + + underlyingTokens[0] = Component({ + token: underlying, + tokenType: "ERC20", + rate: pricing + }); + + return underlyingTokens; + } +} diff --git a/migrations_scripts/1_deploy_registry_and_add_adapters.js b/migrations_scripts/1_deploy_registry_and_add_adapters.js index b430c18a..c73ba9ed 100755 --- a/migrations_scripts/1_deploy_registry_and_add_adapters.js +++ b/migrations_scripts/1_deploy_registry_and_add_adapters.js @@ -98,6 +98,8 @@ const UniswapV1TokenAdapter = artifacts.require('UniswapV1TokenAdapter'); const UniswapV2TokenAdapter = artifacts.require('UniswapV2TokenAdapter'); const UnagiiVaultAdapter = artifacs.require('UnagiiVaultAdapter'); const UnagiiVaultTokenAdapter = artifacs.require('UnagiiVaultTokenAdapter'); +const UnagiiVaultV2Adapter = artifacs.require('UnagiiVaultV2Adapter'); +const UnagiiVaultV2TokenAdapter = artifacs.require('UnagiiVaultV2TokenAdapter'); const AdapterRegistry = artifacts.require('AdapterRegistry'); const antAddress = '0x960b236A07cf122663c4303350609A66A7B288C0'; @@ -454,6 +456,12 @@ const unagiiVaultUSDTAddress = '0x178Bf8fD04b47D2De3eF3f6b3D112106375ad584'; const unagiiVaultWBTCAddress = '0x3aF5Ba94C29a8407785f5f6d90eF5d69a8EB2436'; const unagiiVaultETHAddress = '0x77607588222e01bf892a29Abab45796A2047fc7b'; +const unagiiVaultV2USDCAddress = '0x7f75d72886D6A8677321E5602d18948aBCb4281A'; +const unagiiVaultV2DAIAddress = '0x9ce3018375d305CE3C3303A26eF62D3d2EB8561A'; +const unagiiVaultV2USDTAddress = '0x1Eb06EaE3263a35619dC87812a8e7Ec811B59E63'; +const unagiiVaultV2WBTCAddress = '0xB088D7C71ea9eBAed981c103Fc3019B59950d2C9'; +const unagiiVaultV2ETHAddress = '0x8eF11c51a666C53Aeeec504f120cd1435E451342'; + const aaveAssetAdapterTokens = [ aDaiAddress, aTusdAddress, @@ -979,6 +987,14 @@ const unagiiVaultAdapterTokens = [ unagiiVaultETHAddress, ]; +const unagiiVaultV2AdapterTokens = [ + unagiiVaultV2USDCAddress, + unagiiVaultV2DAIAddress, + unagiiVaultV2USDTAddress, + unagiiVaultV2WBTCAddress, + unagiiVaultV2ETHAddress, +]; + let protocolNames = []; let metadata = []; let adapters = []; @@ -1635,6 +1651,18 @@ module.exports = async (deployer, network, accounts) => { '0', ]); + await deployer.deploy(UnagiiVaultV2Adapter, { from: accounts[0] }); + adapters.push([UnagiiVaultV2Adapter.address]); + tokens.push([unagiiVaultV2AdapterTokens]); + protocolNames.push('Unagii V2'); + metadata.push([ + 'Unagii V2', + 'DeFi yields on auto-pilot.', + 'unagii.com', + 'protocol-icons.s3.amazonaws.com/unagii.png', + '0', + ]); + await deployer.deploy(ERC20TokenAdapter, { from: accounts[0] }) .then(() => { tokenAdapters.push( @@ -1785,6 +1813,12 @@ module.exports = async (deployer, network, accounts) => { UnagiiVaultTokenAdapter.address, ); }); + await deployer.deploy(UnagiiVaultV2TokenAdapter, { from: accounts[0] }) + .then(() => { + tokenAdapters.push( + UnagiiVaultV2TokenAdapter.address, + ); + }); await deployer.deploy(LinkswapTokenAdapter, { from: accounts[0] }) .then(() => { tokenAdapters.push( diff --git a/test/UnagiiV2Adapter.js b/test/UnagiiV2Adapter.js new file mode 100644 index 00000000..ec37bf97 --- /dev/null +++ b/test/UnagiiV2Adapter.js @@ -0,0 +1,41 @@ +const TokenAdapter = artifacts.require('UnagiiVaultTokenAdapter'); + +contract('UnagiiVaultTokenAdapter', () => { + const uDAIV2Address = '0x9ce3018375d305CE3C3303A26eF62D3d2EB8561A'; + const daiAddress = '0x6B175474E89094C44Da98b954EedeAC495271d0F'; + + let accounts; + let tokenAdapter; + const uDAIV2 = [ + uDAIV2Address, + 'unagii_Dai Stablecoin_v2', + 'uDAIv2', + '18', + ]; + + beforeEach(async () => { + accounts = await web3.eth.getAccounts(); + + await TokenAdapter.new({ from: accounts[0] }) + .then((result) => { + tokenAdapter = result.contract; + }); + }); + + it('should return correct components', async () => { + await tokenAdapter.methods['getComponents(address)'](uDAIV2Address) + .call() + .then((result) => { + assert.equal(result[0][0], daiAddress); + assert.equal(result[0][1], 'ERC20'); + }); + }); + + it('should return correct metadata', async () => { + await tokenAdapter.methods['getMetadata(address)'](uDAIV2Address) + .call() + .then((result) => { + assert.deepEqual(result, uDAIV2); + }); + }); +});