Skip to content

Commit 7d20a34

Browse files
Merge pull request #49 from BirthdayResearch/cuong/removeBurnData2
Add documentation, remove burn data and upgrade ethers
2 parents 7130834 + e8ca839 commit 7d20a34

23 files changed

+2060
-1037
lines changed

Diff for: .vscode/settings.json

+3-4
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,8 @@
1414
],
1515
"files.exclude": {
1616
"**/node_modules": true,
17-
"**/.git": true,
17+
"**/.git": true
1818
},
1919
"prettier.bracketSameLine": false,
20-
"prettier.bracketSpacing": true,
21-
22-
}
20+
"prettier.bracketSpacing": true
21+
}

Diff for: Dockerfile

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ RUN apk add --no-cache --virtual .gyp python3 make g++
66

77
WORKDIR /staterelayer
88

9-
COPY package.json hardhat.config.ts .solhint.json ./
9+
COPY package.json hardhat.config.ts .solhint.json tsconfig.json tsconfig.build.json ./
1010
COPY contracts ./contracts
1111

1212
RUN npm install

Diff for: README.md

+2-12
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,3 @@
1-
# Sample Hardhat Project
1+
# DeFiChain <-> DeFiMetaChain State Relayer
22

3-
This project demonstrates a basic Hardhat use case. It comes with a sample contract, a test for that contract, and a script that deploys that contract.
4-
5-
Try running some of the following tasks:
6-
7-
```shell
8-
npx hardhat help
9-
npx hardhat test
10-
REPORT_GAS=true npx hardhat test
11-
npx hardhat node
12-
npx hardhat run scripts/deploy.ts
13-
```
3+
A project comprising of smart contracts and scripts to port certain information from DeFiChain to DeFiMetaChain

Diff for: bot/StateRelayerBot.ts

+29-105
Original file line numberDiff line numberDiff line change
@@ -1,144 +1,70 @@
1-
// @ts-ignore
21
import { getWhaleClient } from '@waveshq/walletkit-bot';
3-
import { BigNumber } from 'bignumber.js';
42
import { ethers } from 'ethers';
53

6-
import { StateRelayer, StateRelayer__factory } from '../generated';
7-
import {
8-
BurnedInformation,
9-
DataStore,
10-
MasterNodeData,
11-
PairData,
12-
StateRelayerHandlerProps,
13-
VaultData,
14-
} from './utils/types';
4+
import { StateRelayer__factory } from '../generated';
5+
import { tranformPairData, transformDataMasternode, transformDataVault } from './utils/transformData';
6+
import { DataStore, MasterNodeData, StateRelayerHandlerProps, VaultData } from './utils/types';
7+
import { ApiPagedResponse} from '@defichain/whale-api-client'
8+
import { PoolPairData } from '@defichain/whale-api-client/dist/api/poolpairs'
159

1610
const DENOMINATION = 'USDT';
17-
const DECIMALS = 10;
18-
19-
const transformToEthersBigNumber = (str: string, decimals: number): ethers.BigNumber =>
20-
ethers.BigNumber.from(
21-
new BigNumber(str).multipliedBy(new BigNumber('10').pow(decimals)).integerValue(BigNumber.ROUND_FLOOR).toString(),
22-
);
11+
const PAGESIZE = 50;
2312

2413
export async function handler(props: StateRelayerHandlerProps): Promise<DFCData | undefined> {
2514
const { urlNetwork, envNetwork, signer, contractAddress } = props;
26-
const stateRelayerContract = new ethers.Contract(contractAddress, StateRelayer__factory.abi, signer) as StateRelayer;
15+
const stateRelayerContract = StateRelayer__factory.connect(contractAddress, signer);
2716
const dataStore = {} as DataStore;
28-
const burnedData = {} as BurnedInformation;
29-
const dataVault = {} as VaultData;
30-
const dataMasterNode = {} as MasterNodeData;
3117
try {
3218
// TODO: Check if Function should run (blockHeight > 30 from previous)
3319
// Get Data from OCEAN API
3420
const client = getWhaleClient(urlNetwork, envNetwork);
3521
const statsData = await client.stats.get();
36-
const rawPoolPairData = await client.poolpairs.list(200);
37-
const dexPriceData = await client.poolpairs.listDexPrices(DENOMINATION);
38-
39-
// sanitize response data
40-
const poolPairData = rawPoolPairData.filter((pair: any) => !pair.displaySymbol.includes('/'));
4122

42-
/* ------------ Data from /dex ----------- */
43-
// totalValueLockInPoolPair
44-
const totalValueLockInPoolPair = transformToEthersBigNumber(statsData.tvl.dex.toString(), DECIMALS);
45-
// total24HVolume
46-
const total24HVolume = transformToEthersBigNumber(
47-
poolPairData.reduce((acc:any, currPair:any) => acc + (currPair.volume?.h24 ?? 0), 0).toString(),
48-
DECIMALS,
49-
);
23+
let rawPoolPairData : Array<PoolPairData> = [];
24+
let pagedPoolPairData: ApiPagedResponse<PoolPairData> = await client.poolpairs.list(PAGESIZE);
25+
rawPoolPairData = rawPoolPairData.concat(pagedPoolPairData);
26+
while (pagedPoolPairData.hasNext) {
27+
pagedPoolPairData = await client.paginate(pagedPoolPairData);
28+
rawPoolPairData = rawPoolPairData.concat(pagedPoolPairData);
29+
}
30+
31+
const dexPriceData = await client.poolpairs.listDexPrices(DENOMINATION);
5032

51-
// /dex/pair
52-
const pair = poolPairData.reduce<PairData>((acc:any, currPair:any) => {
53-
let tokenPrice = new BigNumber(0);
54-
// price ratio is
55-
const priceRatio = currPair.priceRatio.ba;
56-
const { symbol } = currPair.tokenB;
57-
if (symbol === DENOMINATION || new BigNumber(priceRatio).isZero()) {
58-
tokenPrice = new BigNumber(priceRatio);
59-
} else {
60-
const dexPricePerToken = new BigNumber(dexPriceData.dexPrices[symbol]?.denominationPrice ?? 0);
61-
tokenPrice = dexPricePerToken.multipliedBy(currPair.priceRatio.ba);
62-
}
63-
return {
64-
...acc,
65-
[currPair.displaySymbol]: {
66-
primaryTokenPrice: transformToEthersBigNumber(tokenPrice.toString(), DECIMALS),
67-
volume24H: transformToEthersBigNumber(currPair.volume?.h24.toString() ?? '0', DECIMALS),
68-
totalLiquidity: transformToEthersBigNumber(currPair.totalLiquidity.usd ?? '0', DECIMALS),
69-
APR: transformToEthersBigNumber(currPair.apr?.total.toString() ?? '0', DECIMALS),
70-
firstTokenBalance: transformToEthersBigNumber(currPair.tokenA.reserve, DECIMALS),
71-
secondTokenBalance: transformToEthersBigNumber(currPair.tokenB.reserve, DECIMALS),
72-
rewards: transformToEthersBigNumber(currPair.apr?.reward.toString() ?? '0', DECIMALS),
73-
commissions: transformToEthersBigNumber(currPair.commission, DECIMALS),
74-
decimals: DECIMALS,
75-
},
76-
} as PairData;
77-
}, {} as PairData);
78-
dataStore.pair = pair;
33+
const inputForDexUpdate = tranformPairData(rawPoolPairData, statsData, dexPriceData);
7934

8035
// Data from vaults
81-
const totalLoanValue = statsData.loan.value.loan;
82-
const totalCollateralValue = statsData.loan.value.collateral;
83-
dataVault.noOfVaults = transformToEthersBigNumber(statsData.loan.count.openVaults.toString(), 0);
84-
dataVault.totalLoanValue = transformToEthersBigNumber(totalLoanValue.toString(), DECIMALS);
85-
dataVault.totalCollateralValue = transformToEthersBigNumber(totalCollateralValue.toString(), DECIMALS);
86-
dataVault.totalCollateralizationRatio = transformToEthersBigNumber(
87-
((totalCollateralValue / totalLoanValue) * 100).toFixed(3).toString(),
88-
DECIMALS,
89-
);
90-
dataVault.activeAuctions = transformToEthersBigNumber(statsData.loan.count.openAuctions.toString(), 0);
91-
dataVault.decimals = DECIMALS;
36+
const dataVault = transformDataVault(statsData);
9237

9338
// Data from Master Nodes
94-
dataMasterNode.totalValueLockedInMasterNodes = transformToEthersBigNumber(
95-
statsData.tvl.masternodes.toString(),
96-
DECIMALS,
97-
);
98-
dataMasterNode.zeroYearLocked = transformToEthersBigNumber(statsData.masternodes.locked[0].count.toString(), 0);
99-
dataMasterNode.fiveYearLocked = transformToEthersBigNumber(statsData.masternodes.locked[2].count.toString(), 0);
100-
dataMasterNode.tenYearLocked = transformToEthersBigNumber(statsData.masternodes.locked[1].count.toString(), 0);
101-
dataMasterNode.decimals = DECIMALS;
39+
const dataMasterNode = transformDataMasternode(statsData);
10240

103-
// Get Data from all burns in ecosystem
104-
burnedData.fee = transformToEthersBigNumber(statsData.burned.fee.toString(), DECIMALS);
105-
burnedData.auction = transformToEthersBigNumber(statsData.burned.auction.toString(), DECIMALS);
106-
burnedData.payback = transformToEthersBigNumber(statsData.burned.payback.toString(), DECIMALS);
107-
burnedData.emission = transformToEthersBigNumber(statsData.burned.emission.toString(), DECIMALS);
108-
burnedData.total = transformToEthersBigNumber(statsData.burned.total.toString(), DECIMALS);
109-
burnedData.decimals = DECIMALS;
11041
// Call SC Function to update Data
11142
// Update Dex information
11243
const dexInfoTx = await stateRelayerContract.updateDEXInfo(
113-
Object.keys(dataStore.pair),
114-
Object.values(dataStore.pair),
115-
totalValueLockInPoolPair,
116-
total24HVolume,
44+
inputForDexUpdate.dex,
45+
inputForDexUpdate.dexInfo,
46+
inputForDexUpdate.totalValueLocked.toString(),
47+
inputForDexUpdate.total24HVolume.toString(),
11748
);
11849

11950
// Update Master Node information
12051
const masterDataTx = await stateRelayerContract.updateMasterNodeInformation(dataMasterNode);
12152
// Update Vault general information
12253
const vaultTx = await stateRelayerContract.updateVaultGeneralInformation(dataVault);
123-
// Update Burn information
124-
const burnTx = await stateRelayerContract.updateBurnInfo(burnedData);
12554
if (!props.testGasCost) {
12655
return {
12756
dataStore,
12857
dataVault,
12958
dataMasterNode,
130-
burnedData,
13159
};
13260
}
13361
return {
13462
dataStore,
13563
dataVault,
13664
dataMasterNode,
137-
burnedData,
138-
dexInfoTxReceipt: await dexInfoTx.wait(),
139-
masterDataTxReceipt: await masterDataTx.wait(),
140-
vaultTxReceipt: await vaultTx.wait(),
141-
burnTxReceipt: await burnTx.wait(),
65+
dexInfoTxReceipt: (await dexInfoTx.wait()) || undefined,
66+
masterDataTxReceipt: (await masterDataTx.wait()) || undefined,
67+
vaultTxReceipt: (await vaultTx.wait()) || undefined,
14268
};
14369
} catch (e) {
14470
console.error((e as Error).message);
@@ -150,9 +76,7 @@ interface DFCData {
15076
dataStore: DataStore;
15177
dataVault: VaultData;
15278
dataMasterNode: MasterNodeData;
153-
burnedData: BurnedInformation;
154-
dexInfoTxReceipt?: ethers.providers.TransactionReceipt;
155-
masterDataTxReceipt?: ethers.providers.TransactionReceipt;
156-
vaultTxReceipt?: ethers.providers.TransactionReceipt;
157-
burnTxReceipt?: ethers.providers.TransactionReceipt;
79+
dexInfoTxReceipt?: ethers.ContractTransactionReceipt;
80+
masterDataTxReceipt?: ethers.ContractTransactionReceipt;
81+
vaultTxReceipt?: ethers.ContractTransactionReceipt;
15882
}

Diff for: bot/test-i9n/StateRelayerBot.unit.ts

+42-41
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
1+
import { getWhaleClient } from '@waveshq/walletkit-bot';
12
import { EnvironmentNetwork } from '@waveshq/walletkit-core';
23
import { ethers } from 'ethers';
34

45
import { HardhatNetwork, HardhatNetworkContainer, StartedHardhatNetworkContainer } from '../../containers';
56
import { StateRelayer, StateRelayer__factory, StateRelayerProxy__factory } from '../../generated';
67
import { handler } from '../StateRelayerBot';
8+
import { tranformPairData } from '../utils/transformData';
79
import {
8-
expectedBurnedInfo,
9-
expectedDexInfo,
1010
expectedMasterNodeData,
11-
expectedPairData,
1211
expectedVaultData,
1312
mockedDexPricesData,
1413
mockedPoolPairData,
@@ -30,8 +29,8 @@ jest.mock('@defichain/whale-api-client', () => ({
3029
describe('State Relayer Bot Tests', () => {
3130
let startedHardhatContainer: StartedHardhatNetworkContainer;
3231
let hardhatNetwork: HardhatNetwork;
33-
let admin: ethers.providers.JsonRpcSigner;
34-
let bot: ethers.providers.JsonRpcSigner;
32+
let admin: ethers.Signer;
33+
let bot: ethers.Signer;
3534
let proxy: StateRelayer;
3635

3736
beforeEach(async () => {
@@ -41,26 +40,26 @@ describe('State Relayer Bot Tests', () => {
4140
})
4241
.start();
4342
hardhatNetwork = await startedHardhatContainer.ready();
44-
const stateRelayerImplementation = await hardhatNetwork.contracts.deployContract({
43+
const stateRelayerImplementation = await hardhatNetwork?.contracts?.deployContract({
4544
deploymentName: 'StateRelayerImplementation',
4645
contractName: 'StateRelayer',
4746
abi: StateRelayer__factory.abi,
4847
});
49-
admin = hardhatNetwork.getHardhatTestWallet(0).testWalletSigner;
50-
bot = hardhatNetwork.getHardhatTestWallet(1).testWalletSigner;
51-
const stateRelayerProxy = await hardhatNetwork.contracts.deployContract({
48+
admin = (await hardhatNetwork.getHardhatTestWallet(0)).testWalletSigner;
49+
bot = (await hardhatNetwork.getHardhatTestWallet(1)).testWalletSigner;
50+
const stateRelayerProxy = await hardhatNetwork?.contracts?.deployContract({
5251
deploymentName: 'StateRelayerProxy',
5352
contractName: 'StateRelayerProxy',
5453
abi: StateRelayerProxy__factory.abi,
5554
deployArgs: [
56-
stateRelayerImplementation.address,
55+
await stateRelayerImplementation?.getAddress(),
5756
StateRelayer__factory.createInterface().encodeFunctionData('initialize', [
5857
await admin.getAddress(),
5958
await bot.getAddress(),
6059
]),
6160
],
6261
});
63-
proxy = StateRelayer__factory.connect(stateRelayerProxy.address, bot);
62+
proxy = StateRelayer__factory.connect((await stateRelayerProxy?.getAddress()) || '', bot);
6463
});
6564

6665
afterEach(async () => {
@@ -72,59 +71,61 @@ describe('State Relayer Bot Tests', () => {
7271
testGasCost: false,
7372
envNetwork: EnvironmentNetwork.LocalPlayground,
7473
urlNetwork: '',
75-
contractAddress: proxy.address,
74+
contractAddress: await proxy.getAddress(),
7675
signer: bot,
7776
});
7877

78+
const client = getWhaleClient('', EnvironmentNetwork.LocalPlayground);
79+
const testPoolPairData = await client.poolpairs.list(200);
7980
if (output !== undefined) {
80-
const { dexInfoTxReceipt, masterDataTxReceipt, vaultTxReceipt, burnTxReceipt } = output;
81+
const { dexInfoTxReceipt, masterDataTxReceipt, vaultTxReceipt } = output;
8182
expect(dexInfoTxReceipt).toBeUndefined();
8283
expect(masterDataTxReceipt).toBeUndefined();
8384
expect(vaultTxReceipt).toBeUndefined();
84-
expect(burnTxReceipt).toBeUndefined();
8585
}
8686

87-
const receivedBurnedInfo = await proxy.getBurnedInfo();
88-
expect(receivedBurnedInfo[1].fee.toString()).toEqual(expectedBurnedInfo.fee);
89-
expect(receivedBurnedInfo[1].auction.toString()).toEqual(expectedBurnedInfo.auction);
90-
expect(receivedBurnedInfo[1].payback.toString()).toEqual(expectedBurnedInfo.payback);
91-
expect(receivedBurnedInfo[1].emission.toString()).toEqual(expectedBurnedInfo.emission);
92-
expect(receivedBurnedInfo[1].total.toString()).toEqual(expectedBurnedInfo.total);
93-
9487
// Checking the /dex/dex-pair info
9588
const dETH = await proxy.getDexPairInfo('dETH-DFI');
96-
expect(dETH[1].primaryTokenPrice.toString()).toEqual(Object.values(expectedPairData['dETH-DFI'])[0]);
97-
expect(dETH[1].volume24H.toString()).toEqual(Object.values(expectedPairData['dETH-DFI'])[1]);
98-
expect(dETH[1].totalLiquidity.toString()).toEqual(Object.values(expectedPairData['dETH-DFI'])[2]);
99-
expect(dETH[1].APR.toString()).toEqual(Object.values(expectedPairData['dETH-DFI'])[3]);
100-
expect(dETH[1].firstTokenBalance.toString()).toEqual(Object.values(expectedPairData['dETH-DFI'])[4]);
101-
expect(dETH[1].secondTokenBalance.toString()).toEqual(Object.values(expectedPairData['dETH-DFI'])[5]);
102-
expect(dETH[1].rewards.toString()).toEqual(Object.values(expectedPairData['dETH-DFI'])[6]);
103-
expect(dETH[1].commissions.toString()).toEqual(Object.values(expectedPairData['dETH-DFI'])[7]);
104-
expect(dETH[1].decimals.toString()).toEqual(Object.values(expectedPairData['dETH-DFI'])[8]);
89+
const expectedDexInfo = tranformPairData(testPoolPairData, mockedStatsData, mockedDexPricesData);
90+
const lastETHDFIInfo = expectedDexInfo.dexInfo[expectedDexInfo.dex.indexOf('dETH-DFI')];
91+
// for sure both two sides have the same type as bigint
92+
expect(dETH[1].primaryTokenPrice).toStrictEqual(lastETHDFIInfo.primaryTokenPrice);
93+
expect(dETH[1].volume24H).toStrictEqual(lastETHDFIInfo.volume24H);
94+
expect(dETH[1].totalLiquidity).toStrictEqual(lastETHDFIInfo.totalLiquidity);
95+
expect(dETH[1].APR).toStrictEqual(lastETHDFIInfo.APR);
96+
expect(dETH[1].firstTokenBalance).toStrictEqual(lastETHDFIInfo.firstTokenBalance);
97+
expect(dETH[1].secondTokenBalance).toStrictEqual(lastETHDFIInfo.secondTokenBalance);
98+
expect(dETH[1].rewards).toStrictEqual(lastETHDFIInfo.rewards);
99+
expect(dETH[1].commissions).toStrictEqual(lastETHDFIInfo.commissions);
105100

106101
// Checking /dex info
107102
const dex = await proxy.getDexInfo();
108-
expect(dex[2].toString()).toEqual(expectedDexInfo.totalValueLockInPoolPair);
109-
expect(dex[1].toString()).toEqual(expectedDexInfo.total24HVolume);
103+
expect(dex[2]).toStrictEqual(expectedDexInfo.totalValueLocked);
104+
expect(dex[1]).toStrictEqual(expectedDexInfo.total24HVolume);
110105

111106
// Checking MasterNode information
112107
const receivedMasterNodeData = await proxy.getMasterNodeInfo();
113-
expect(receivedMasterNodeData[1].totalValueLockedInMasterNodes.toString()).toEqual(
108+
expect(receivedMasterNodeData[1].totalValueLockedInMasterNodes).toStrictEqual(
114109
expectedMasterNodeData.totalValueLockedInMasterNodes,
115110
);
116-
expect(receivedMasterNodeData[1].zeroYearLocked.toString()).toEqual(expectedMasterNodeData.zeroYearLocked);
117-
expect(receivedMasterNodeData[1].fiveYearLocked.toString()).toEqual(expectedMasterNodeData.fiveYearLocked);
118-
expect(receivedMasterNodeData[1].tenYearLocked.toString()).toEqual(expectedMasterNodeData.tenYearLocked);
111+
expect(receivedMasterNodeData[1].zeroYearLockedNoDecimals).toStrictEqual(
112+
expectedMasterNodeData.zeroYearLockedNoDecimals,
113+
);
114+
expect(receivedMasterNodeData[1].fiveYearLockedNoDecimals).toStrictEqual(
115+
expectedMasterNodeData.fiveYearLockedNoDecimals,
116+
);
117+
expect(receivedMasterNodeData[1].tenYearLockedNoDecimals).toStrictEqual(
118+
expectedMasterNodeData.tenYearLockedNoDecimals,
119+
);
119120

120121
// Checking VaultInfo
121122
const receivedVaultData = await proxy.getVaultInfo();
122-
expect(receivedVaultData[1].noOfVaults.toString()).toEqual(expectedVaultData.noOfVaults);
123-
expect(receivedVaultData[1].totalLoanValue.toString()).toEqual(expectedVaultData.totalLoanValue);
124-
expect(receivedVaultData[1].totalCollateralValue.toString()).toEqual(expectedVaultData.totalCollateralValue);
125-
expect(receivedVaultData[1].totalCollateralizationRatio.toString()).toEqual(
123+
expect(receivedVaultData[1].noOfVaultsNoDecimals).toStrictEqual(expectedVaultData.noOfVaultsNoDecimals);
124+
expect(receivedVaultData[1].totalLoanValue).toStrictEqual(expectedVaultData.totalLoanValue);
125+
expect(receivedVaultData[1].totalCollateralValue).toStrictEqual(expectedVaultData.totalCollateralValue);
126+
expect(receivedVaultData[1].totalCollateralizationRatio).toStrictEqual(
126127
expectedVaultData.totalCollateralizationRatio,
127128
);
128-
expect(receivedVaultData[1].activeAuctions.toString()).toEqual(expectedVaultData.activeAuctions);
129+
expect(receivedVaultData[1].activeAuctionsNoDecimals).toStrictEqual(expectedVaultData.activeAuctionsNoDecimals);
129130
});
130131
});

0 commit comments

Comments
 (0)