Skip to content

Commit

Permalink
feat: finish implemnting WooFiV2
Browse files Browse the repository at this point in the history
  • Loading branch information
Verisana committed Mar 14, 2023
1 parent 73b2838 commit a314978
Show file tree
Hide file tree
Showing 16 changed files with 601 additions and 255 deletions.
1 change: 1 addition & 0 deletions dex-template/__DexName__-e2e.test.ts.template
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable no-console */
import dotenv from 'dotenv';
dotenv.config();

Expand Down
1 change: 1 addition & 0 deletions dex-template/__DexName__-events.test.ts.template
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable no-console */
import dotenv from 'dotenv';
dotenv.config();

Expand Down
1 change: 1 addition & 0 deletions dex-template/__DexName__-integration.test.ts.template
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable no-console */
import dotenv from 'dotenv';
dotenv.config();

Expand Down
116 changes: 116 additions & 0 deletions src/abi/woo-fi-v2/IntegrationHelper.abi.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
[
{
"inputs": [
{ "internalType": "address", "name": "_quoteToken", "type": "address" },
{
"internalType": "address[]",
"name": "_baseTokens",
"type": "address[]"
}
],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "previousOwner",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "newOwner",
"type": "address"
}
],
"name": "OwnershipTransferred",
"type": "event"
},
{
"inputs": [
{ "internalType": "address", "name": "token", "type": "address" }
],
"name": "addBaseToken",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "allBaseTokens",
"outputs": [
{ "internalType": "address[]", "name": "", "type": "address[]" }
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "allBaseTokensLength",
"outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "getSupportTokens",
"outputs": [
{ "internalType": "address", "name": "", "type": "address" },
{ "internalType": "address[]", "name": "", "type": "address[]" }
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "owner",
"outputs": [{ "internalType": "address", "name": "", "type": "address" }],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "quoteToken",
"outputs": [{ "internalType": "address", "name": "", "type": "address" }],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{ "internalType": "address", "name": "token", "type": "address" }
],
"name": "removeBaseToken",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "renounceOwnership",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{ "internalType": "address", "name": "_quoteToken", "type": "address" }
],
"name": "setQutoeToken",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{ "internalType": "address", "name": "newOwner", "type": "address" }
],
"name": "transferOwnership",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
}
]
3 changes: 3 additions & 0 deletions src/dex/simple-exchange.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Address, SimpleExchangeParam, NumberAsString } from '../types';
import { CACHE_PREFIX, ETHER_ADDRESS } from '../constants';
import SimpleSwapHelperABI from '../abi/SimpleSwapHelperRouter.json';
import ERC20ABI from '../abi/erc20.json';
import augustusABI from '../abi/augustus.json';
import { isETHAddress } from '../utils';
import { MAX_UINT } from '../constants';
import Web3 from 'web3';
Expand All @@ -18,6 +19,7 @@ export class SimpleExchange {
isFeeOnTransferSupported = false;

protected augustusAddress: Address;
protected augustusInterface: Interface;
private provider: Web3;

protected network: number;
Expand All @@ -32,6 +34,7 @@ export class SimpleExchange {

this.network = dexHelper.config.data.network;
this.augustusAddress = dexHelper.config.data.augustusAddress;
this.augustusInterface = new Interface(augustusABI);
this.provider = dexHelper.web3Provider;

this.dexmapKey =
Expand Down
61 changes: 60 additions & 1 deletion src/dex/woo-fi-v2/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,66 @@ import { Network, SwapSide } from '../../constants';

export const WooFiV2Config: DexConfigMap<DexParams> = {
WooFiV2: {
// TODO: complete me!
[Network.OPTIMISM]: {
wooPPV2Address: '0xd1778F9DF3eee5473A9640f13682e3846f61fEbC',
wooOracleV2Address: '0x464959aD46e64046B891F562cFF202a465D522F3',
integrationHelperAddress: '0x96329d66074EB8386Ae8bFD6698B2E3FDA87e15E',
// USDC
quoteToken: {
address: '0x7F5c764cBc14f9669B88837ca1490cCa17c31607',
decimals: 6,
},
},
[Network.BSC]: {
wooPPV2Address: '0xEc054126922a9a1918435c9072c32f1B60cB2B90',
wooOracleV2Address: '0x747f99D619D5612399010Ec5706F13e3345c4a9E',
integrationHelperAddress: '0xe12dC1F01ccB71ef00ADd1D8A5116b905261D879',
// BUSD
quoteToken: {
address: '0xe9e7CEA3DedcA5984780Bafc599bD69ADd087D56',
decimals: 18,
},
},
[Network.POLYGON]: {
wooPPV2Address: '0x7081A38158BD050Ae4a86e38E0225Bc281887d7E',
wooOracleV2Address: '0xeFF23B4bE1091b53205E35f3AfCD9C7182bf3062',
integrationHelperAddress: '0x7Ba560eB735AbDCf9a3a5692272652A0cc81850d',
// USDC
quoteToken: {
address: '0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174',
decimals: 6,
},
},
[Network.FANTOM]: {
wooPPV2Address: '0x286ab107c5E9083dBed35A2B5fb0242538F4f9bf',
wooOracleV2Address: '0x8840e26e0ebf7D100A0644DD8576DC62B03cbf04',
integrationHelperAddress: '0x6641959FE5EED7166F2254cF04b0d20c96776D9A',
// USDC
quoteToken: {
address: '0x04068DA6C83AFCFA0e13ba15A6696662335D5B75',
decimals: 6,
},
},
[Network.ARBITRUM]: {
wooPPV2Address: '0xeFF23B4bE1091b53205E35f3AfCD9C7182bf3062',
wooOracleV2Address: '0x37a9dE70b6734dFCA54395D8061d9411D9910739',
integrationHelperAddress: '0x28D2B949024FE50627f1EbC5f0Ca3Ca721148E40',
// USDC
quoteToken: {
address: '0xFF970A61A04b1cA14834A43f5dE4533eBDDB5CC8',
decimals: 6,
},
},
[Network.AVALANCHE]: {
wooPPV2Address: '0x3b3E4b4741e91aF52d0e9ad8660573E951c88524',
wooOracleV2Address: '0x9ACA557590F5020BDA4Ba63065Fc3A1253Bf8000',
integrationHelperAddress: '0x020630613E296c3E9b06186f630D1bF97A2B6Ad1',
// USDC
quoteToken: {
address: '0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E',
decimals: 6,
},
},
},
};

Expand Down
3 changes: 2 additions & 1 deletion src/dex/woo-fi-v2/constants.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { PoolState } from './types';

export const WOO_FI_GAS_COST = 150 * 1000;
// TODO: UPDATE GAS COST!
export const WOO_FI_V2_GAS_COST = 150 * 1000;

export const USD_PRECISION = 2;

Expand Down
45 changes: 45 additions & 0 deletions src/dex/woo-fi-v2/decoders.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { BytesLike } from 'ethers';
import { defaultAbiCoder } from 'ethers/lib/utils';
import { extractSuccessAndValue, generalDecoder } from '../../lib/decoders';
import { MultiResult } from '../../lib/multi-wrapper';
import { DecimalInfo, TokenInfo, TokenState } from './types';

export function tokenInfoDecoder(
result: MultiResult<BytesLike> | BytesLike,
): TokenInfo {
return generalDecoder(result, ['uint192', 'uint16'], undefined, value => ({
reserve: value[0].toBigInt(),
feeRate: value[1].toBigInt(),
}));
}

export function decimalInfoDecoder(
result: MultiResult<BytesLike> | BytesLike,
): DecimalInfo {
return generalDecoder(
result,
['tuple(uint64 priceDec, uint64 quoteDec, uint64 baseDec)'],
undefined,
value => ({
priceDec: value[0].priceDec.toBigInt(),
quoteDec: value[0].quoteDec.toBigInt(),
baseDec: value[0].baseDec.toBigInt(),
}),
);
}

// This is state from WooOracleV2 contract
export function stateDecoder(
result: MultiResult<BytesLike> | BytesLike,
): TokenState {
return generalDecoder(
result,
['tuple(uint128 price, uint64 spread, uint64 coeff, bool woFeasible)'],
undefined,
value => ({
price: value[0].toBigInt(),
spread: value[0].toBigInt(),
coeff: value[0].toBigInt(),
}),
);
}
23 changes: 18 additions & 5 deletions src/dex/woo-fi-v2/types.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { Interface } from 'ethers/lib/utils';
import { Address, Token } from '../../types';

export type PoolState = {
Expand All @@ -11,7 +12,7 @@ export type PoolState = {

// fetched from WooPPV2.decimalInfo(address baseToken)
// https://arbiscan.io/address/0x8693F9701D6DB361Fe9CC15Bc455Ef4366E39AE0
decimals: Record<Address, Decimals>;
decimals: Record<Address, DecimalInfo>;
oracleTimestamp: bigint;
isPaused: boolean;
};
Expand All @@ -21,9 +22,8 @@ export type WooFiV2Data = {};
export type DexParams = {
wooPPV2Address: Address;
wooOracleV2Address: Address;
integrationHelperAddress: Address;
quoteToken: Token;
baseTokens: Record<string, Token>;
rebateTo: Address;
};

export type TokenInfo = {
Expand All @@ -37,7 +37,7 @@ export type TokenState = {
coeff: bigint;
};

export type Decimals = {
export type DecimalInfo = {
priceDec: bigint;
quoteDec: bigint;
baseDec: bigint;
Expand All @@ -47,4 +47,17 @@ export type LatestRoundData = {
answer: bigint;
};

export type MulticallResultOutputs = number;
export type MulticallResultOutputs =
| boolean
| bigint
| TokenInfo
| DecimalInfo
| TokenState;

export type WooFiV2Interfaces = {
PPV2: Interface;
oracleV2: Interface;
integrationHelper: Interface;
chainlink: Interface;
erc20BalanceOf: Interface;
};
19 changes: 19 additions & 0 deletions src/dex/woo-fi-v2/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { Interface } from 'ethers/lib/utils';
import wooPPV2ABI from '../../abi/woo-fi-v2/WooPPV2.abi.json';
import wooOracleV2ABI from '../../abi/woo-fi-v2/WooOracleV2.abi.json';
import wooIntegrationHelper from '../../abi/woo-fi-v2/IntegrationHelper.abi.json';
import { WooFiV2Interfaces } from './types';

export const ifaces: WooFiV2Interfaces = {
PPV2: new Interface(wooPPV2ABI),
oracleV2: new Interface(wooOracleV2ABI),
integrationHelper: new Interface(wooIntegrationHelper),
chainlink: new Interface([
'function latestRoundData() view returns (tuple(uint80 roundId, ' +
'int256 answer, uint256 startedAt, uint256 updatedAt, ' +
'uint80 answeredInRound))',
]),
erc20BalanceOf: new Interface([
'function balanceOf(address) view returns (uint256)',
]),
};
39 changes: 0 additions & 39 deletions src/dex/woo-fi-v2/woo-fi-v2-e2e.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,45 +11,6 @@ import { Network, ContractMethod, SwapSide } from '../../constants';
import { StaticJsonRpcProvider } from '@ethersproject/providers';
import { generateConfig } from '../../config';

/*
README
======
This test script should add e2e tests for WooFiV2. The tests
should cover as many cases as possible. Most of the DEXes follow
the following test structure:
- DexName
- ForkName + Network
- ContractMethod
- ETH -> Token swap
- Token -> ETH swap
- Token -> Token swap
The template already enumerates the basic structure which involves
testing simpleSwap, multiSwap, megaSwap contract methods for
ETH <> TOKEN and TOKEN <> TOKEN swaps. You should replace tokenA and
tokenB with any two highly liquid tokens on WooFiV2 for the tests
to work. If the tokens that you would like to use are not defined in
Tokens or Holders map, you can update the './tests/constants-e2e'
Other than the standard cases that are already added by the template
it is highly recommended to add test cases which could be specific
to testing WooFiV2 (Eg. Tests based on poolType, special tokens,
etc).
You can run this individual test script by running:
`npx jest src/dex/<dex-name>/<dex-name>-e2e.test.ts`
e2e tests use the Tenderly fork api. Please add the following to your
.env file:
TENDERLY_TOKEN=Find this under Account>Settings>Authorization.
TENDERLY_ACCOUNT_ID=Your Tenderly account name.
TENDERLY_PROJECT=Name of a Tenderly project you have created in your
dashboard.
(This comment should be removed from the final implementation)
*/

function testForNetwork(
network: Network,
dexKey: string,
Expand Down
Loading

0 comments on commit a314978

Please sign in to comment.