@dhedge/v2-sdk 1.1.1 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +60 -3
- package/dist/config.d.ts +7 -0
- package/dist/entities/pool.d.ts +101 -5
- package/dist/entities/utils.d.ts +10 -0
- package/dist/services/claim-balancer/claim.service.d.ts +17 -0
- package/dist/services/claim-balancer/claim.worker.d.ts +4 -0
- package/dist/services/claim-balancer/ipfs.service.d.ts +4 -0
- package/dist/services/claim-balancer/types.d.ts +54 -0
- package/dist/services/uniswap/V3Liquidity.d.ts +9 -0
- package/dist/services/uniswap/V3Trade.d.ts +4 -0
- package/dist/services/uniswap/types.d.ts +3 -0
- package/dist/test/constants.d.ts +12 -0
- package/dist/test/txOptions.d.ts +1 -0
- package/dist/types.d.ts +20 -6
- package/dist/utils/contract.d.ts +14 -0
- package/dist/utils/index.d.ts +7 -0
- package/dist/utils/merkle.d.ts +22 -0
- package/dist/v2-sdk.cjs.development.js +6086 -918
- package/dist/v2-sdk.cjs.development.js.map +1 -1
- package/dist/v2-sdk.cjs.production.min.js +1 -1
- package/dist/v2-sdk.cjs.production.min.js.map +1 -1
- package/dist/v2-sdk.esm.js +6090 -922
- package/dist/v2-sdk.esm.js.map +1 -1
- package/package.json +12 -2
- package/src/abi/IAaveIncentivesController.json +50 -0
- package/src/abi/IBalancerMerkleOrchard.json +353 -0
- package/src/abi/IBalancertV2Vault.json +938 -0
- package/src/abi/IERC20.json +15 -1
- package/src/abi/INonfungiblePositionManager.json +1221 -0
- package/src/abi/ISynthetix.json +139 -0
- package/src/abi/IUniswapV3Quoter.json +195 -0
- package/src/abi/IUniswapV3Router.json +221 -0
- package/src/config.ts +48 -8
- package/src/entities/dhedge.ts +4 -2
- package/src/entities/pool.ts +398 -27
- package/src/entities/utils.ts +147 -0
- package/src/services/claim-balancer/MultiTokenClaim.json +115 -0
- package/src/services/claim-balancer/claim.service.ts +262 -0
- package/src/services/claim-balancer/claim.worker.ts +32 -0
- package/src/services/claim-balancer/ipfs.service.ts +12 -0
- package/src/services/claim-balancer/types.ts +66 -0
- package/src/services/uniswap/V3Liquidity.ts +134 -0
- package/src/services/uniswap/V3Trade.ts +47 -0
- package/src/services/uniswap/types.ts +16 -0
- package/src/test/aave.test.ts +73 -0
- package/src/test/balancer.test.ts +109 -0
- package/src/test/constants.ts +17 -0
- package/src/test/oneInch.test.ts +56 -0
- package/src/test/pool.test.ts +6 -250
- package/src/test/sushi.test.ts +173 -0
- package/src/test/synthetix.test.ts +34 -0
- package/src/test/txOptions.ts +15 -0
- package/src/test/uniswap.test.ts +127 -0
- package/src/test/utils.test.ts +41 -26
- package/src/test/wallet.ts +5 -1
- package/src/types.ts +17 -3
- package/src/utils/contract.ts +95 -0
- package/src/utils/index.ts +38 -0
- package/src/utils/merkle.ts +172 -0
package/src/test/utils.test.ts
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
1
|
+
//import { ethers } from "ethers";
|
|
1
2
|
import { Dhedge } from "..";
|
|
2
|
-
import {
|
|
3
|
+
import { Network } from "../types";
|
|
3
4
|
|
|
4
5
|
import { wallet } from "./wallet";
|
|
5
6
|
|
|
6
|
-
const myPool = "
|
|
7
|
+
const myPool = "0xe3528a438b94e64669def9b875c381c46ef713bf";
|
|
7
8
|
|
|
8
|
-
const usdt = "0xc2132D05D31c914a87C6611C10748AEb04B58e8F";
|
|
9
|
+
// const usdt = "0xc2132D05D31c914a87C6611C10748AEb04B58e8F";
|
|
9
10
|
const usdc = "0x2791bca1f2de4661ed88a30c99a7a9449aa84174";
|
|
10
11
|
const weth = "0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619";
|
|
11
|
-
const
|
|
12
|
+
const wbtc = "0x1BFD67037B42Cf73acF2047067bd4F2C47D9BfD6";
|
|
13
|
+
// const lpUsdcWeth = "0x34965ba0ac2451A34a0471F04CCa3F990b8dea27";
|
|
12
14
|
|
|
13
15
|
let dhedge: Dhedge;
|
|
14
16
|
|
|
@@ -19,28 +21,41 @@ describe("utils", () => {
|
|
|
19
21
|
dhedge = new Dhedge(wallet, Network.POLYGON);
|
|
20
22
|
});
|
|
21
23
|
|
|
22
|
-
it("gets lp ratio of the USDT/USDC pool", async () => {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
it("gets pool id of sushi LP pool for USDC/WETH", async () => {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
it("gets USDC balance of a pool", async () => {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
});
|
|
36
|
-
it("gets minumum amount out of WETH for 1 USDC", async () => {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
24
|
+
// it("gets lp ratio of the USDT/USDC pool", async () => {
|
|
25
|
+
// const result = await dhedge.utils.getLpReserves(Dapp.SUSHISWAP, usdc, usdt);
|
|
26
|
+
// expect(Number(result.assetA) / Number(result.assetB)).toBeGreaterThan(0.9);
|
|
27
|
+
// });
|
|
28
|
+
|
|
29
|
+
// it("gets pool id of sushi LP pool for USDC/WETH", async () => {
|
|
30
|
+
// const result = await dhedge.utils.getLpPoolId(Dapp.SUSHISWAP, lpUsdcWeth);
|
|
31
|
+
// expect(result).toBe(1);
|
|
32
|
+
// });
|
|
33
|
+
|
|
34
|
+
// it("gets USDC balance of a pool", async () => {
|
|
35
|
+
// const result = await dhedge.utils.getBalance(usdc, myPool);
|
|
36
|
+
// expect(result.gt(0));
|
|
37
|
+
// });
|
|
38
|
+
// it("gets minumum amount out of WETH for 1 USDC", async () => {
|
|
39
|
+
// const result = await dhedge.utils.getMinAmountOut(
|
|
40
|
+
// Dapp.SUSHISWAP,
|
|
41
|
+
// usdc,
|
|
42
|
+
// weth,
|
|
43
|
+
// "1000000",
|
|
44
|
+
// 0.5
|
|
45
|
+
// );
|
|
46
|
+
// expect(result.gt(0));
|
|
47
|
+
// });
|
|
48
|
+
|
|
49
|
+
it("gets Balancer pool tx data", async () => {
|
|
50
|
+
const pool = await dhedge.loadPool(myPool);
|
|
51
|
+
const assets = [wbtc, usdc, weth];
|
|
52
|
+
const amounts = ["0", "1000000", "0"];
|
|
53
|
+
const result = await dhedge.utils.getBalancerJoinPoolTx(
|
|
54
|
+
pool,
|
|
55
|
+
"0x03cd191f589d12b0582a99808cf19851e468e6b500010000000000000000000a",
|
|
56
|
+
assets,
|
|
57
|
+
amounts
|
|
43
58
|
);
|
|
44
|
-
expect(result
|
|
59
|
+
expect(result);
|
|
45
60
|
});
|
|
46
61
|
});
|
package/src/test/wallet.ts
CHANGED
|
@@ -4,9 +4,13 @@ import { ethers } from "ethers";
|
|
|
4
4
|
require("dotenv").config();
|
|
5
5
|
|
|
6
6
|
const provider = new ethers.providers.JsonRpcProvider(
|
|
7
|
-
`https://
|
|
7
|
+
`https://opt-mainnet.g.alchemy.com/v2/${process.env.ALCHEMY_PROJECT_ID}`
|
|
8
8
|
);
|
|
9
9
|
|
|
10
|
+
// const provider = new ethers.providers.JsonRpcProvider(
|
|
11
|
+
// `https://polygon-mainnet.infura.io/v3/${process.env.INFURA_PROJECT_ID}`
|
|
12
|
+
// );
|
|
13
|
+
|
|
10
14
|
export const wallet = new ethers.Wallet(
|
|
11
15
|
process.env.PRIVATE_KEY as string,
|
|
12
16
|
provider
|
package/src/types.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { ChainId } from "@sushiswap/sdk";
|
|
2
1
|
import { BigNumber } from "ethers";
|
|
3
2
|
|
|
4
3
|
export enum Network {
|
|
5
4
|
POLYGON = "polygon",
|
|
5
|
+
OPTIMISM = "optimism"
|
|
6
6
|
}
|
|
7
7
|
|
|
8
8
|
export enum Dapp {
|
|
@@ -10,6 +10,9 @@ export enum Dapp {
|
|
|
10
10
|
AAVE = "aave",
|
|
11
11
|
ONEINCH = "1inch",
|
|
12
12
|
QUICKSWAP = "quickswap",
|
|
13
|
+
BALANCER = "balancer",
|
|
14
|
+
UNISWAPV3 = "uniswapV3",
|
|
15
|
+
SYNTHETIX = "synthetix"
|
|
13
16
|
}
|
|
14
17
|
|
|
15
18
|
export enum Transaction {
|
|
@@ -17,11 +20,19 @@ export enum Transaction {
|
|
|
17
20
|
ADD_LIQUIDITY = "addLiquidity",
|
|
18
21
|
DEPOSIT = "deposit",
|
|
19
22
|
HARVEST = "harvest",
|
|
20
|
-
|
|
23
|
+
CLAIM_DISTRIBIUTIONS = "claimDistributions",
|
|
24
|
+
CLAIM_REWARDS = "claimRewards",
|
|
21
25
|
REMOVE_LIQUIDITY = "removeLiquidity",
|
|
26
|
+
DECREASE_LIQUIDITY = "decreaseLiquidity",
|
|
27
|
+
INCREASE_LIQUIDITY = "increaseLiquidity",
|
|
28
|
+
COLLECT = "collect",
|
|
29
|
+
MULTI_CALL = "multicall",
|
|
22
30
|
BORROW = "borrow",
|
|
23
31
|
REPAY = "repay",
|
|
24
32
|
WITHDRAW = "withdraw",
|
|
33
|
+
MINT = "mint",
|
|
34
|
+
BURN = "burn",
|
|
35
|
+
SWAP_SYNTHS = "exchangeWithTracking"
|
|
25
36
|
}
|
|
26
37
|
|
|
27
38
|
export type AddressNetworkMap = Readonly<Record<Network, string>>;
|
|
@@ -31,6 +42,9 @@ export type AddressDappMap = {
|
|
|
31
42
|
[Dapp.AAVE]?: string;
|
|
32
43
|
[Dapp.ONEINCH]?: string;
|
|
33
44
|
[Dapp.QUICKSWAP]?: string;
|
|
45
|
+
[Dapp.BALANCER]?: string;
|
|
46
|
+
[Dapp.UNISWAPV3]?: string;
|
|
47
|
+
[Dapp.SYNTHETIX]?: string;
|
|
34
48
|
};
|
|
35
49
|
|
|
36
50
|
export type AddressDappNetworkMap = Readonly<Record<Network, AddressDappMap>>;
|
|
@@ -54,4 +68,4 @@ export type Reserves = {
|
|
|
54
68
|
assetB: BigNumber;
|
|
55
69
|
};
|
|
56
70
|
|
|
57
|
-
export type NetworkChainIdMap = Readonly<Record<Network,
|
|
71
|
+
export type NetworkChainIdMap = Readonly<Record<Network, number>>;
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
|
2
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
3
|
+
import set from "lodash/set";
|
|
4
|
+
import { Interface } from "@ethersproject/abi";
|
|
5
|
+
import { multiCallAddress } from "../config";
|
|
6
|
+
import { ethers, Network } from "..";
|
|
7
|
+
|
|
8
|
+
export async function call(
|
|
9
|
+
provider: ethers.Signer,
|
|
10
|
+
abi: any[],
|
|
11
|
+
call: any[],
|
|
12
|
+
options?: any
|
|
13
|
+
) {
|
|
14
|
+
const contract = new ethers.Contract(call[0], abi, provider);
|
|
15
|
+
try {
|
|
16
|
+
const params = call[2] || [];
|
|
17
|
+
return await contract[call[1]](...params, options || {});
|
|
18
|
+
} catch (e) {
|
|
19
|
+
return Promise.reject(e);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export async function multicall<T>(
|
|
24
|
+
network: Network,
|
|
25
|
+
provider: ethers.Signer,
|
|
26
|
+
abi: any[],
|
|
27
|
+
calls: any[],
|
|
28
|
+
options: any = {},
|
|
29
|
+
requireSuccess = false
|
|
30
|
+
): Promise<(T | null)[]> {
|
|
31
|
+
const multi = new ethers.Contract(
|
|
32
|
+
multiCallAddress[network],
|
|
33
|
+
[
|
|
34
|
+
"function tryAggregate(bool requireSuccess, tuple(address, bytes)[] memory calls) public view returns (tuple(bool, bytes)[] memory returnData)"
|
|
35
|
+
],
|
|
36
|
+
provider
|
|
37
|
+
);
|
|
38
|
+
const itf = new Interface(abi);
|
|
39
|
+
try {
|
|
40
|
+
const res: [boolean, string][] = await multi.tryAggregate(
|
|
41
|
+
// if false, allows individual calls to fail without causing entire multicall to fail
|
|
42
|
+
requireSuccess,
|
|
43
|
+
calls.map(call => [
|
|
44
|
+
call[0].toLowerCase(),
|
|
45
|
+
itf.encodeFunctionData(call[1], call[2])
|
|
46
|
+
]),
|
|
47
|
+
options
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
return res.map(([success, returnData], i) => {
|
|
51
|
+
if (!success) return null;
|
|
52
|
+
const decodedResult = itf.decodeFunctionResult(calls[i][1], returnData);
|
|
53
|
+
// Automatically unwrap any simple return values
|
|
54
|
+
return decodedResult.length > 1 ? decodedResult : decodedResult[0];
|
|
55
|
+
});
|
|
56
|
+
} catch (e) {
|
|
57
|
+
return Promise.reject(e);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export class Multicaller {
|
|
62
|
+
public network: Network;
|
|
63
|
+
public provider: ethers.Signer;
|
|
64
|
+
public abi: any[];
|
|
65
|
+
public options: any = {};
|
|
66
|
+
public calls: any[] = [];
|
|
67
|
+
public paths: any[] = [];
|
|
68
|
+
|
|
69
|
+
constructor(network: Network, provider: ethers.Signer, abi: any[]) {
|
|
70
|
+
this.network = network;
|
|
71
|
+
this.provider = provider;
|
|
72
|
+
this.abi = abi;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
call(path: any, address: any, fn: any, params?: any): Multicaller {
|
|
76
|
+
this.calls.push([address, fn, params]);
|
|
77
|
+
this.paths.push(path);
|
|
78
|
+
return this;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
async execute(from?: any): Promise<any> {
|
|
82
|
+
const obj = from || {};
|
|
83
|
+
const result = await multicall(
|
|
84
|
+
this.network,
|
|
85
|
+
this.provider,
|
|
86
|
+
this.abi,
|
|
87
|
+
this.calls,
|
|
88
|
+
this.options
|
|
89
|
+
);
|
|
90
|
+
result.forEach((r, i) => set(obj, this.paths[i], r));
|
|
91
|
+
this.calls = [];
|
|
92
|
+
this.paths = [];
|
|
93
|
+
return obj;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
|
3
|
+
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
|
4
|
+
import BigNumber from "bignumber.js";
|
|
5
|
+
import { soliditySha3 } from "web3-utils";
|
|
6
|
+
import { MerkleTree } from "./merkle";
|
|
7
|
+
|
|
8
|
+
export function scale(
|
|
9
|
+
input: BigNumber | string,
|
|
10
|
+
decimalPlaces: number
|
|
11
|
+
): BigNumber {
|
|
12
|
+
const unscaled = typeof input === "string" ? new BigNumber(input) : input;
|
|
13
|
+
const scalePow = new BigNumber(decimalPlaces.toString());
|
|
14
|
+
const scaleMul = new BigNumber(10).pow(scalePow);
|
|
15
|
+
return unscaled.times(scaleMul);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function loadTree(
|
|
19
|
+
balances: { [x: string]: string | BigNumber },
|
|
20
|
+
decimals = 18
|
|
21
|
+
) {
|
|
22
|
+
const elements: any[] = [];
|
|
23
|
+
Object.keys(balances).forEach(address => {
|
|
24
|
+
const balance: string = scale(balances[address], decimals).toString(10);
|
|
25
|
+
const leaf = soliditySha3(
|
|
26
|
+
{ t: "address", v: address },
|
|
27
|
+
{ t: "uint", v: balance }
|
|
28
|
+
);
|
|
29
|
+
// @ts-ignore
|
|
30
|
+
elements.push(leaf);
|
|
31
|
+
});
|
|
32
|
+
return new MerkleTree(elements);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function bnum(val: string | number | BigNumber): BigNumber {
|
|
36
|
+
const number = typeof val === "string" ? val : val ? val.toString() : "0";
|
|
37
|
+
return new BigNumber(number);
|
|
38
|
+
}
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
|
2
|
+
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
|
3
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
4
|
+
// Shamelessly adapted from OpenZeppelin-contracts test utils
|
|
5
|
+
import BigNumber from "bignumber.js";
|
|
6
|
+
import { keccak256, keccakFromString, bufferToHex } from "ethereumjs-util";
|
|
7
|
+
import { hexToBytes, soliditySha3 } from "web3-utils";
|
|
8
|
+
import { scale } from "./index";
|
|
9
|
+
|
|
10
|
+
// Merkle tree called with 32 byte hex values
|
|
11
|
+
export class MerkleTree {
|
|
12
|
+
public elements: any;
|
|
13
|
+
public layers: any;
|
|
14
|
+
|
|
15
|
+
constructor(elements: any[]) {
|
|
16
|
+
this.elements = elements
|
|
17
|
+
.filter((el: any) => el)
|
|
18
|
+
.map(el => Buffer.from(hexToBytes(el)));
|
|
19
|
+
|
|
20
|
+
// Sort elements
|
|
21
|
+
this.elements.sort(Buffer.compare);
|
|
22
|
+
// Deduplicate elements
|
|
23
|
+
this.elements = this.bufDedup(this.elements);
|
|
24
|
+
|
|
25
|
+
// Create layers
|
|
26
|
+
this.layers = this.getLayers(this.elements);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
getLayers(elements: string | any[]) {
|
|
30
|
+
if (elements.length === 0) {
|
|
31
|
+
return [[""]];
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const layers = [];
|
|
35
|
+
layers.push(elements);
|
|
36
|
+
|
|
37
|
+
// Get next layer until we reach the root=
|
|
38
|
+
while (layers[layers.length - 1].length > 1) {
|
|
39
|
+
// @ts-ignore
|
|
40
|
+
layers.push(this.getNextLayer(layers[layers.length - 1]));
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return layers;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
getNextLayer(elements: any[]) {
|
|
47
|
+
return elements.reduce(
|
|
48
|
+
(layer: any[], el: any, idx: number, arr: { [x: string]: any }) => {
|
|
49
|
+
if (idx % 2 === 0) {
|
|
50
|
+
// Hash the current element with its pair element
|
|
51
|
+
layer.push(this.combinedHash(el, arr[idx + 1]));
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return layer;
|
|
55
|
+
},
|
|
56
|
+
[]
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
combinedHash(first: any, second: any) {
|
|
61
|
+
if (!first) {
|
|
62
|
+
return second;
|
|
63
|
+
}
|
|
64
|
+
if (!second) {
|
|
65
|
+
return first;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return keccak256(this.sortAndConcat(first, second));
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
getRoot() {
|
|
72
|
+
return this.layers[this.layers.length - 1][0];
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
getHexRoot() {
|
|
76
|
+
return bufferToHex(this.getRoot());
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
getProof(el: any) {
|
|
80
|
+
let idx = this.bufIndexOf(el, this.elements);
|
|
81
|
+
|
|
82
|
+
if (idx === -1) {
|
|
83
|
+
throw new Error("Element does not exist in Merkle tree");
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return this.layers.reduce((proof: any[], layer: any) => {
|
|
87
|
+
const pairElement = this.getPairElement(idx, layer);
|
|
88
|
+
|
|
89
|
+
if (pairElement) {
|
|
90
|
+
proof.push(pairElement);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
idx = Math.floor(idx / 2);
|
|
94
|
+
|
|
95
|
+
return proof;
|
|
96
|
+
}, []);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// external call - convert to buffer
|
|
100
|
+
getHexProof(_el: any) {
|
|
101
|
+
const el = Buffer.from(hexToBytes(_el));
|
|
102
|
+
|
|
103
|
+
const proof = this.getProof(el);
|
|
104
|
+
|
|
105
|
+
return this.bufArrToHexArr(proof);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
getPairElement(idx: number, layer: string | any[]) {
|
|
109
|
+
const pairIdx = idx % 2 === 0 ? idx + 1 : idx - 1;
|
|
110
|
+
|
|
111
|
+
if (pairIdx < layer.length) {
|
|
112
|
+
return layer[pairIdx];
|
|
113
|
+
} else {
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
bufIndexOf(el: string | any[], arr: string | any[]) {
|
|
119
|
+
let hash;
|
|
120
|
+
|
|
121
|
+
// Convert element to 32 byte hash if it is not one already
|
|
122
|
+
if (el.length !== 32 || !Buffer.isBuffer(el)) {
|
|
123
|
+
hash = keccakFromString(el as string);
|
|
124
|
+
} else {
|
|
125
|
+
hash = el;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
for (let i = 0; i < arr.length; i++) {
|
|
129
|
+
if (hash.equals(arr[i])) {
|
|
130
|
+
return i;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return -1;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
bufDedup(elements: any[]) {
|
|
138
|
+
return elements.filter((el: any, idx: number) => {
|
|
139
|
+
return idx === 0 || !elements[idx - 1].equals(el);
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
bufArrToHexArr(arr: any[]) {
|
|
144
|
+
if (arr.some((el: any) => !Buffer.isBuffer(el))) {
|
|
145
|
+
throw new Error("Array is not an array of buffers");
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return arr.map(
|
|
149
|
+
(el: { toString: (arg0: string) => string }) => "0x" + el.toString("hex")
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
sortAndConcat(...args: any[]) {
|
|
154
|
+
return Buffer.concat([...args].sort(Buffer.compare));
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export function loadTree(
|
|
159
|
+
balances: { [x: string]: string | BigNumber },
|
|
160
|
+
decimals = 18
|
|
161
|
+
) {
|
|
162
|
+
const elements: (string | null)[] = [];
|
|
163
|
+
Object.keys(balances).forEach(address => {
|
|
164
|
+
const balance: string = scale(balances[address], decimals).toString(10);
|
|
165
|
+
const leaf = soliditySha3(
|
|
166
|
+
{ t: "address", v: address },
|
|
167
|
+
{ t: "uint", v: balance }
|
|
168
|
+
);
|
|
169
|
+
elements.push(leaf);
|
|
170
|
+
});
|
|
171
|
+
return new MerkleTree(elements);
|
|
172
|
+
}
|