Skip to content

Commit dc0d52d

Browse files
committed
updated curve adapter + added new one
1 parent 722a45f commit dc0d52d

File tree

4 files changed

+189
-23
lines changed

4 files changed

+189
-23
lines changed

contracts/adapters/CurveAdapter.sol renamed to contracts/adapters/CurveCompoundAdapter.sol

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,21 @@ import { Component } from "../Structs.sol";
66
import { ERC20 } from "../ERC20.sol";
77

88

9+
/**
10+
* @dev CToken contract interface.
11+
* Only the functions required for CurveCompoundAdapter contract are added.
12+
* The CToken contract is available here
13+
* https://github.com/compound-finance/compound-protocol/blob/master/contracts/CToken.sol.
14+
*/
15+
interface CToken {
16+
function underlying() external view returns (address);
17+
function exchangeRateStored() external view returns (uint256);
18+
}
19+
20+
921
/**
1022
* @dev stableswap contract interface.
11-
* Only the functions required for CurveAdapter contract are added.
23+
* Only the functions required for CurveCompoundAdapter contract are added.
1224
* The stableswap contract is available here
1325
* https://github.com/curvefi/curve-contract/blob/compounded/vyper/stableswap.vy.
1426
*/
@@ -20,10 +32,10 @@ interface stableswap {
2032

2133

2234
/**
23-
* @title Adapter for Curve.fi protocol.
35+
* @title Adapter for Curve protocol.
2436
* @dev Implementation of Adapter interface.
2537
*/
26-
contract CurveAdapter is Adapter {
38+
contract CurveCompoundAdapter is Adapter {
2739

2840
address constant internal SS = 0x2e60CF74d81ac34eB21eEff58Db4D385920ef419;
2941

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

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

5567
for (uint256 i = 0; i < 2; i++) {
68+
CToken cToken = CToken(ss.coins(int128(i)));
5669
components[i] = Component({
57-
underlying: ss.coins(int128(i)),
58-
rate: ss.balances(int128(i)) * 1e18 / ERC20(asset).totalSupply()
70+
underlying: cToken.underlying(),
71+
rate: ss.balances(int128(i)) * cToken.exchangeRateStored() / ERC20(asset).totalSupply()
5972
});
6073
}
6174

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
pragma solidity 0.6.2;
2+
pragma experimental ABIEncoderV2;
3+
4+
import { Adapter } from "./Adapter.sol";
5+
import { Component } from "../Structs.sol";
6+
import { ERC20 } from "../ERC20.sol";
7+
8+
9+
/**
10+
* @dev YToken contract interface.
11+
* Only the functions required for CurveYAdapter contract are added.
12+
* The YToken contracts are available here
13+
* https://github.com/iearn-finance/itoken/tree/master/contracts.
14+
*/
15+
interface YToken {
16+
function token() external view returns (address);
17+
function getPricePerFullShare() external view returns (uint256);
18+
}
19+
20+
21+
/**
22+
* @dev stableswap contract interface.
23+
* Only the functions required for CurveYAdapter contract are added.
24+
* The stableswap contract is available here
25+
* https://github.com/curvefi/curve-contract/blob/compounded/vyper/stableswap.vy.
26+
*/
27+
// solhint-disable-next-line contract-name-camelcase
28+
interface stableswap {
29+
function coins(int128) external view returns (address);
30+
function balances(int128) external view returns(uint256);
31+
}
32+
33+
34+
/**
35+
* @title Adapter for Curve protocol.
36+
* @dev Implementation of Adapter interface.
37+
*/
38+
contract CurveYAdapter is Adapter {
39+
40+
address constant internal SS = 0x45F783CCE6B7FF23B2ab2D70e416cdb7D6055f51;
41+
42+
/**
43+
* @return Name of the protocol.
44+
* @dev Implementation of Adapter function.
45+
*/
46+
function getProtocolName() external pure override returns (string memory) {
47+
return("Curve ∙ Y pool");
48+
}
49+
50+
/**
51+
* @return Amount of stableswapToken locked on the protocol by the given user.
52+
* @dev Implementation of Adapter function.
53+
*/
54+
function getAssetAmount(address asset, address user) external view override returns (int256) {
55+
return int256(ERC20(asset).balanceOf(user));
56+
}
57+
58+
/**
59+
* @return Struct with underlying assets rates for the given asset.
60+
* @dev Implementation of Adapter function.
61+
* Repeats calculations made in stableswap contract.
62+
*/
63+
function getUnderlyingRates(address asset) external view override returns (Component[] memory) {
64+
Component[] memory components = new Component[](4);
65+
stableswap ss = stableswap(SS);
66+
67+
for (uint256 i = 0; i < 4; i++) {
68+
YToken yToken = YToken(ss.coins(int128(i)));
69+
components[i] = Component({
70+
underlying: yToken.token(),
71+
rate: ss.balances(int128(i)) * yToken.getPricePerFullShare() / ERC20(asset).totalSupply()
72+
});
73+
}
74+
75+
return components;
76+
}
77+
}

test/CurveAdapter.js renamed to test/CurveCompoundAdapter.js

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
const { BN } = web3.utils;
22
const AdapterRegistry = artifacts.require('./AdapterRegistry');
3-
const CurveAdapter = artifacts.require('./CurveAdapter');
3+
const CurveAdapter = artifacts.require('./CurveCompoundAdapter');
44

5-
contract('CurveAdapter', () => {
5+
contract('CurveCompoundAdapter', () => {
66
const ssTokenAddress = '0x3740fb63ab7a09891d7c0d4299442A551D06F5fD';
7-
const cDAIAddress = '0x5d3a536E4D6DbD6114cc1Ead35777bAB948E3643';
8-
const cUSDCAddress = '0x39AA39c021dfbaE8faC545936693aC917d5E7563';
9-
const testAddress = '0x98f365b8215189f547E0f77d84aF1A2Cb0820c72';
7+
const DAIAddress = '0x6B175474E89094C44Da98b954EedeAC495271d0F';
8+
const USDCAddress = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48';
9+
const testAddress = '0x42b9dF65B219B3dD36FF330A4dD8f327A6Ada990';
1010

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

4242
// eslint-disable-next-line no-console
4343
console.log(`Deposited ssToken amount: ${ssTokenAmount.toString()}`);
4444
assert.equal(result[0].balances[0].decimals, 18);
4545
assert.equal(result[0].balances[0].asset, ssTokenAddress);
4646
assert.equal(result[0].rates[0].asset, ssTokenAddress);
47-
assert.equal(result[0].rates[0].components[0].underlying, cDAIAddress);
47+
assert.equal(result[0].rates[0].components[0].underlying, DAIAddress);
4848
// eslint-disable-next-line no-console
49-
console.log(`cDAI rate: ${cDAIRate.toString()}`);
49+
console.log(`DAI rate: ${DAIRate.toString()}`);
5050
// eslint-disable-next-line no-console
51-
console.log(`Means its: ${cDAIAmount} DAI locked`);
52-
assert.equal(result[0].rates[0].components[1].underlying, cUSDCAddress);
51+
console.log(`Means its: ${DAIAmount} DAI locked`);
52+
assert.equal(result[0].rates[0].components[1].underlying, USDCAddress);
5353
// eslint-disable-next-line no-console
54-
console.log(`cUSDC rate: ${cUSDCRate.toString()}`);
54+
console.log(`USDC rate: ${USDCRate.toString()}`);
5555
// eslint-disable-next-line no-console
56-
console.log(`Means its: ${cUSDCAmount} USDC locked`);
57-
assert.equal(result[0].name, 'Curve.fi');
56+
console.log(`Means its: ${USDCAmount} USDC locked`);
57+
assert.equal(result[0].name, 'Curve ∙ Compound pool');
5858
});
5959
});
6060
});

test/CurveYAdapter.js

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
const { BN } = web3.utils;
2+
const AdapterRegistry = artifacts.require('./AdapterRegistry');
3+
const CurveAdapter = artifacts.require('./CurveYAdapter');
4+
5+
contract('CurveYAdapter', () => {
6+
const ssTokenAddress = '0xdF5e0e81Dff6FAF3A7e52BA697820c5e32D806A8';
7+
const DAIAddress = '0x6B175474E89094C44Da98b954EedeAC495271d0F';
8+
const USDCAddress = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48';
9+
const USDTAddress = '0xdAC17F958D2ee523a2206206994597C13D831ec7';
10+
const TUSDAddress = '0x0000000000085d4780B73119b644AE5ecd22b376';
11+
const testAddress = '0x42b9dF65B219B3dD36FF330A4dD8f327A6Ada990';
12+
13+
let accounts;
14+
let adapterRegistry;
15+
let curveAdapter;
16+
17+
beforeEach(async () => {
18+
accounts = await web3.eth.getAccounts();
19+
await CurveAdapter.new({ from: accounts[0] })
20+
.then((result) => {
21+
curveAdapter = result.contract;
22+
});
23+
await AdapterRegistry.new(
24+
[curveAdapter.options.address],
25+
[[ssTokenAddress]],
26+
{ from: accounts[0] },
27+
)
28+
.then((result) => {
29+
adapterRegistry = result.contract;
30+
});
31+
});
32+
33+
it('should return correct balances and rates', async () => {
34+
await adapterRegistry.methods['getBalancesAndRates(address)'](testAddress)
35+
.call()
36+
.then((result) => {
37+
const base = new BN(10).pow(new BN(18));
38+
const ssTokenAmount = new BN(result[0].balances[0].amount);
39+
const DAIRate = new BN(result[0].rates[0].components[0].rate);
40+
const DAIAmount = DAIRate.mul(ssTokenAmount).div(base).toString();
41+
const USDCRate = new BN(result[0].rates[0].components[1].rate);
42+
const USDCAmount = USDCRate.mul(ssTokenAmount).div(base).toString();
43+
const USDTRate = new BN(result[0].rates[0].components[2].rate);
44+
const USDTAmount = USDTRate.mul(ssTokenAmount).div(base).toString();
45+
const TUSDRate = new BN(result[0].rates[0].components[3].rate);
46+
const TUSDAmount = TUSDRate.mul(ssTokenAmount).div(base).toString();
47+
48+
// eslint-disable-next-line no-console
49+
console.log(`Deposited ssToken amount: ${ssTokenAmount.toString()}`);
50+
assert.equal(result[0].balances[0].decimals, 18);
51+
assert.equal(result[0].balances[0].asset, ssTokenAddress);
52+
assert.equal(result[0].rates[0].asset, ssTokenAddress);
53+
assert.equal(result[0].rates[0].components[0].underlying, DAIAddress);
54+
// eslint-disable-next-line no-console
55+
console.log(`DAI rate: ${DAIRate.toString()}`);
56+
// eslint-disable-next-line no-console
57+
console.log(`Means its: ${DAIAmount} DAI locked`);
58+
assert.equal(result[0].rates[0].components[1].underlying, USDCAddress);
59+
// eslint-disable-next-line no-console
60+
console.log(`USDC rate: ${USDCRate.toString()}`);
61+
// eslint-disable-next-line no-console
62+
console.log(`Means its: ${USDCAmount} USDC locked`);
63+
assert.equal(result[0].rates[0].components[2].underlying, USDTAddress);
64+
// eslint-disable-next-line no-console
65+
console.log(`USDT rate: ${USDTRate.toString()}`);
66+
// eslint-disable-next-line no-console
67+
console.log(`Means its: ${USDTAmount} USDT locked`);
68+
assert.equal(result[0].rates[0].components[3].underlying, TUSDAddress);
69+
// eslint-disable-next-line no-console
70+
console.log(`TUSD rate: ${TUSDRate.toString()}`);
71+
// eslint-disable-next-line no-console
72+
console.log(`Means its: ${TUSDAmount} TUSD locked`);
73+
assert.equal(result[0].name, 'Curve ∙ Y pool');
74+
});
75+
});
76+
});

0 commit comments

Comments
 (0)