forked from balancer/balancer-api
-
Notifications
You must be signed in to change notification settings - Fork 0
/
helpers.ts
152 lines (134 loc) · 4.58 KB
/
helpers.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
import config from '@/config';
import { Vault__factory } from '@balancer-labs/typechain';
import { TokenWithSlot } from '@/constants/addresses';
import { hexlify, hexValue, zeroPad } from '@ethersproject/bytes';
import { keccak256 } from '@ethersproject/solidity';
import { JsonRpcSigner } from '@ethersproject/providers';
import { Contract } from '@ethersproject/contracts';
import { Token, Address } from '@balancer-labs/sdk';
import { BigNumber, BigNumberish } from '@ethersproject/bignumber';
import { Network } from '@/constants';
const ERC20ABI = require('./abis/ERC20.json');
export async function getBalances(
signer: JsonRpcSigner,
tokens: Token[]
): Promise<Record<string, string>> {
const balances = await Promise.all(
tokens.map(async token => {
const contract = new Contract(token.address, ERC20ABI, signer);
const balance = await contract.balanceOf(await signer.getAddress());
return [token.symbol, balance];
})
);
const ethBalance = await signer.getBalance();
balances.unshift(['ETH', ethBalance]);
return Object.fromEntries(balances);
}
export async function printBalances(
signer: JsonRpcSigner,
tokens: Token[]
): Promise<void> {
const balances = await getBalances(signer, tokens);
console.log('Token Balances:');
Object.entries(balances).forEach(([symbol, balance]) => {
console.log(`${symbol}: ${balance}`);
});
}
/**
* Setup local fork with approved token balance for a given account
*
* @param {JsonRpcSigner} signer Account that will have token balance set and approved
* @param {string[]} tokens Token addresses which balance will be set and approved
* @param {number[]} slots Slot that stores token balance in memory - use npm package `slot20` to identify which slot to provide
* @param {string[]} balances Balances in EVM amounts
* @param {string} jsonRpcUrl Url with remote node to be forked locally
* @param {number} blockNumber Number of the block that the fork will happen
*/
export const forkSetup = async (
signer: JsonRpcSigner,
jsonRpcUrl: string,
blockNumber?: number
): Promise<void> => {
await signer.provider.send('hardhat_reset', [
{
forking: {
jsonRpcUrl,
blockNumber,
},
},
]);
};
export async function setEthBalance(
signer: JsonRpcSigner,
balance: BigNumberish
) {
const walletAddress = await signer.getAddress();
const params = [
walletAddress,
hexValue(balance), // hex encoded wei amount
];
await signer.provider.send('hardhat_setBalance', params);
}
/**
* Set token balance for a given account
*
* @param {JsonRpcSigner} signer Account that will have token balance set
* @param {string} token Token address which balance will be set
* @param {number} slot Slot memory that stores balance - use npm package `slot20` to identify which slot to provide
* @param {string} balance Balance in EVM amounts
*/
export const setTokenBalance = async (
signer: JsonRpcSigner,
token: TokenWithSlot,
balance: BigNumberish,
isVyperMapping = false
): Promise<void> => {
const toBytes32 = (bn: BigNumber) => {
return hexlify(zeroPad(bn.toHexString(), 32));
};
const setStorageAt = async (token: string, index: string, value: string) => {
await signer.provider.send('hardhat_setStorageAt', [token, index, value]);
await signer.provider.send('evm_mine', []); // Just mines to the next block
};
const signerAddress = await signer.getAddress();
// Get storage slot index
let index;
if (isVyperMapping) {
index = keccak256(
['uint256', 'uint256'],
[token.slot, signerAddress] // slot, key
);
} else {
index = keccak256(
['uint256', 'uint256'],
[signerAddress, token.slot] // key, slot
);
}
// Manipulate local balance (needs to be bytes32 string)
await setStorageAt(
token.address,
index,
toBytes32(BigNumber.from(balance)).toString()
);
};
export async function approveToken(
signer: JsonRpcSigner,
token: Address,
amount: BigNumberish,
spender: Address
): Promise<void> {
const tokenContract = new Contract(token, ERC20ABI, signer);
const tx = await tokenContract.approve(spender, amount);
await tx.wait();
}
export async function approveRelayer(
signer: JsonRpcSigner,
): Promise<void> {
const walletAddress = await signer.getAddress();
const vaultAddress = config[Network.MAINNET].addresses.vault;
const relayerAddress = config[Network.MAINNET].addresses.batchRelayer;
const vaultContract = new Contract(vaultAddress, Vault__factory.abi, signer);
await vaultContract.setRelayerApproval(
walletAddress, relayerAddress, true
);
}