Skip to content

Commit

Permalink
updated curve adapter + added new one
Browse files Browse the repository at this point in the history
  • Loading branch information
sobolev-igor committed Feb 28, 2020
1 parent 722a45f commit dc0d52d
Show file tree
Hide file tree
Showing 4 changed files with 189 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,21 @@ import { Component } from "../Structs.sol";
import { ERC20 } from "../ERC20.sol";


/**
* @dev CToken contract interface.
* Only the functions required for CurveCompoundAdapter contract are added.
* The CToken contract is available here
* https://github.com/compound-finance/compound-protocol/blob/master/contracts/CToken.sol.
*/
interface CToken {
function underlying() external view returns (address);
function exchangeRateStored() external view returns (uint256);
}


/**
* @dev stableswap contract interface.
* Only the functions required for CurveAdapter contract are added.
* Only the functions required for CurveCompoundAdapter contract are added.
* The stableswap contract is available here
* https://github.com/curvefi/curve-contract/blob/compounded/vyper/stableswap.vy.
*/
Expand All @@ -20,10 +32,10 @@ interface stableswap {


/**
* @title Adapter for Curve.fi protocol.
* @title Adapter for Curve protocol.
* @dev Implementation of Adapter interface.
*/
contract CurveAdapter is Adapter {
contract CurveCompoundAdapter is Adapter {

address constant internal SS = 0x2e60CF74d81ac34eB21eEff58Db4D385920ef419;

Expand All @@ -32,7 +44,7 @@ contract CurveAdapter is Adapter {
* @dev Implementation of Adapter function.
*/
function getProtocolName() external pure override returns (string memory) {
return("Curve.fi");
return("Curve ∙ Compound pool");
}

/**
Expand All @@ -53,9 +65,10 @@ contract CurveAdapter is Adapter {
stableswap ss = stableswap(SS);

for (uint256 i = 0; i < 2; i++) {
CToken cToken = CToken(ss.coins(int128(i)));
components[i] = Component({
underlying: ss.coins(int128(i)),
rate: ss.balances(int128(i)) * 1e18 / ERC20(asset).totalSupply()
underlying: cToken.underlying(),
rate: ss.balances(int128(i)) * cToken.exchangeRateStored() / ERC20(asset).totalSupply()
});
}

Expand Down
77 changes: 77 additions & 0 deletions contracts/adapters/CurveYAdapter.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
pragma solidity 0.6.2;
pragma experimental ABIEncoderV2;

import { Adapter } from "./Adapter.sol";
import { Component } from "../Structs.sol";
import { ERC20 } from "../ERC20.sol";


/**
* @dev YToken contract interface.
* Only the functions required for CurveYAdapter contract are added.
* The YToken contracts are available here
* https://github.com/iearn-finance/itoken/tree/master/contracts.
*/
interface YToken {
function token() external view returns (address);
function getPricePerFullShare() external view returns (uint256);
}


/**
* @dev stableswap contract interface.
* Only the functions required for CurveYAdapter contract are added.
* The stableswap contract is available here
* https://github.com/curvefi/curve-contract/blob/compounded/vyper/stableswap.vy.
*/
// solhint-disable-next-line contract-name-camelcase
interface stableswap {
function coins(int128) external view returns (address);
function balances(int128) external view returns(uint256);
}


/**
* @title Adapter for Curve protocol.
* @dev Implementation of Adapter interface.
*/
contract CurveYAdapter is Adapter {

address constant internal SS = 0x45F783CCE6B7FF23B2ab2D70e416cdb7D6055f51;

/**
* @return Name of the protocol.
* @dev Implementation of Adapter function.
*/
function getProtocolName() external pure override returns (string memory) {
return("Curve ∙ Y pool");
}

/**
* @return Amount of stableswapToken locked on the protocol by the given user.
* @dev Implementation of Adapter function.
*/
function getAssetAmount(address asset, address user) external view override returns (int256) {
return int256(ERC20(asset).balanceOf(user));
}

/**
* @return Struct with underlying assets rates for the given asset.
* @dev Implementation of Adapter function.
* Repeats calculations made in stableswap contract.
*/
function getUnderlyingRates(address asset) external view override returns (Component[] memory) {
Component[] memory components = new Component[](4);
stableswap ss = stableswap(SS);

for (uint256 i = 0; i < 4; i++) {
YToken yToken = YToken(ss.coins(int128(i)));
components[i] = Component({
underlying: yToken.token(),
rate: ss.balances(int128(i)) * yToken.getPricePerFullShare() / ERC20(asset).totalSupply()
});
}

return components;
}
}
34 changes: 17 additions & 17 deletions test/CurveAdapter.js → test/CurveCompoundAdapter.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
const { BN } = web3.utils;
const AdapterRegistry = artifacts.require('./AdapterRegistry');
const CurveAdapter = artifacts.require('./CurveAdapter');
const CurveAdapter = artifacts.require('./CurveCompoundAdapter');

contract('CurveAdapter', () => {
contract('CurveCompoundAdapter', () => {
const ssTokenAddress = '0x3740fb63ab7a09891d7c0d4299442A551D06F5fD';
const cDAIAddress = '0x5d3a536E4D6DbD6114cc1Ead35777bAB948E3643';
const cUSDCAddress = '0x39AA39c021dfbaE8faC545936693aC917d5E7563';
const testAddress = '0x98f365b8215189f547E0f77d84aF1A2Cb0820c72';
const DAIAddress = '0x6B175474E89094C44Da98b954EedeAC495271d0F';
const USDCAddress = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48';
const testAddress = '0x42b9dF65B219B3dD36FF330A4dD8f327A6Ada990';

let accounts;
let adapterRegistry;
Expand All @@ -32,29 +32,29 @@ contract('CurveAdapter', () => {
await adapterRegistry.methods['getBalancesAndRates(address)'](testAddress)
.call()
.then((result) => {
const base = new BN(10).pow(new BN(24));
const base = new BN(10).pow(new BN(18));
const ssTokenAmount = new BN(result[0].balances[0].amount);
const cDAIRate = new BN(result[0].rates[0].components[0].rate);
const cDAIAmount = cDAIRate.mul(ssTokenAmount).div(base).toNumber() / 100;
const cUSDCRate = new BN(result[0].rates[0].components[1].rate);
const cUSDCAmount = cUSDCRate.mul(ssTokenAmount).div(base).toNumber() / 100;
const DAIRate = new BN(result[0].rates[0].components[0].rate);
const DAIAmount = DAIRate.mul(ssTokenAmount).div(base).toString();
const USDCRate = new BN(result[0].rates[0].components[1].rate);
const USDCAmount = USDCRate.mul(ssTokenAmount).div(base).toString();

// eslint-disable-next-line no-console
console.log(`Deposited ssToken amount: ${ssTokenAmount.toString()}`);
assert.equal(result[0].balances[0].decimals, 18);
assert.equal(result[0].balances[0].asset, ssTokenAddress);
assert.equal(result[0].rates[0].asset, ssTokenAddress);
assert.equal(result[0].rates[0].components[0].underlying, cDAIAddress);
assert.equal(result[0].rates[0].components[0].underlying, DAIAddress);
// eslint-disable-next-line no-console
console.log(`cDAI rate: ${cDAIRate.toString()}`);
console.log(`DAI rate: ${DAIRate.toString()}`);
// eslint-disable-next-line no-console
console.log(`Means its: ${cDAIAmount} DAI locked`);
assert.equal(result[0].rates[0].components[1].underlying, cUSDCAddress);
console.log(`Means its: ${DAIAmount} DAI locked`);
assert.equal(result[0].rates[0].components[1].underlying, USDCAddress);
// eslint-disable-next-line no-console
console.log(`cUSDC rate: ${cUSDCRate.toString()}`);
console.log(`USDC rate: ${USDCRate.toString()}`);
// eslint-disable-next-line no-console
console.log(`Means its: ${cUSDCAmount} USDC locked`);
assert.equal(result[0].name, 'Curve.fi');
console.log(`Means its: ${USDCAmount} USDC locked`);
assert.equal(result[0].name, 'Curve ∙ Compound pool');
});
});
});
76 changes: 76 additions & 0 deletions test/CurveYAdapter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
const { BN } = web3.utils;
const AdapterRegistry = artifacts.require('./AdapterRegistry');
const CurveAdapter = artifacts.require('./CurveYAdapter');

contract('CurveYAdapter', () => {
const ssTokenAddress = '0xdF5e0e81Dff6FAF3A7e52BA697820c5e32D806A8';
const DAIAddress = '0x6B175474E89094C44Da98b954EedeAC495271d0F';
const USDCAddress = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48';
const USDTAddress = '0xdAC17F958D2ee523a2206206994597C13D831ec7';
const TUSDAddress = '0x0000000000085d4780B73119b644AE5ecd22b376';
const testAddress = '0x42b9dF65B219B3dD36FF330A4dD8f327A6Ada990';

let accounts;
let adapterRegistry;
let curveAdapter;

beforeEach(async () => {
accounts = await web3.eth.getAccounts();
await CurveAdapter.new({ from: accounts[0] })
.then((result) => {
curveAdapter = result.contract;
});
await AdapterRegistry.new(
[curveAdapter.options.address],
[[ssTokenAddress]],
{ from: accounts[0] },
)
.then((result) => {
adapterRegistry = result.contract;
});
});

it('should return correct balances and rates', async () => {
await adapterRegistry.methods['getBalancesAndRates(address)'](testAddress)
.call()
.then((result) => {
const base = new BN(10).pow(new BN(18));
const ssTokenAmount = new BN(result[0].balances[0].amount);
const DAIRate = new BN(result[0].rates[0].components[0].rate);
const DAIAmount = DAIRate.mul(ssTokenAmount).div(base).toString();
const USDCRate = new BN(result[0].rates[0].components[1].rate);
const USDCAmount = USDCRate.mul(ssTokenAmount).div(base).toString();
const USDTRate = new BN(result[0].rates[0].components[2].rate);
const USDTAmount = USDTRate.mul(ssTokenAmount).div(base).toString();
const TUSDRate = new BN(result[0].rates[0].components[3].rate);
const TUSDAmount = TUSDRate.mul(ssTokenAmount).div(base).toString();

// eslint-disable-next-line no-console
console.log(`Deposited ssToken amount: ${ssTokenAmount.toString()}`);
assert.equal(result[0].balances[0].decimals, 18);
assert.equal(result[0].balances[0].asset, ssTokenAddress);
assert.equal(result[0].rates[0].asset, ssTokenAddress);
assert.equal(result[0].rates[0].components[0].underlying, DAIAddress);
// eslint-disable-next-line no-console
console.log(`DAI rate: ${DAIRate.toString()}`);
// eslint-disable-next-line no-console
console.log(`Means its: ${DAIAmount} DAI locked`);
assert.equal(result[0].rates[0].components[1].underlying, USDCAddress);
// eslint-disable-next-line no-console
console.log(`USDC rate: ${USDCRate.toString()}`);
// eslint-disable-next-line no-console
console.log(`Means its: ${USDCAmount} USDC locked`);
assert.equal(result[0].rates[0].components[2].underlying, USDTAddress);
// eslint-disable-next-line no-console
console.log(`USDT rate: ${USDTRate.toString()}`);
// eslint-disable-next-line no-console
console.log(`Means its: ${USDTAmount} USDT locked`);
assert.equal(result[0].rates[0].components[3].underlying, TUSDAddress);
// eslint-disable-next-line no-console
console.log(`TUSD rate: ${TUSDRate.toString()}`);
// eslint-disable-next-line no-console
console.log(`Means its: ${TUSDAmount} TUSD locked`);
assert.equal(result[0].name, 'Curve ∙ Y pool');
});
});
});

0 comments on commit dc0d52d

Please sign in to comment.