|
1 |
| -import { deployProxy, fp, getSigners, impersonate, instanceAt, toUSDC, ZERO_ADDRESS } from '@mimic-fi/v3-helpers' |
| 1 | +import { |
| 2 | + assertIndirectEvent, |
| 3 | + deployProxy, |
| 4 | + fp, |
| 5 | + getSigners, |
| 6 | + impersonate, |
| 7 | + instanceAt, |
| 8 | + toUSDC, |
| 9 | + ZERO_ADDRESS, |
| 10 | + ZERO_BYTES32, |
| 11 | +} from '@mimic-fi/v3-helpers' |
2 | 12 | import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/dist/src/signer-with-address'
|
3 | 13 | import { expect } from 'chai'
|
4 | 14 | import { BigNumber, Contract } from 'ethers'
|
@@ -76,120 +86,178 @@ describe('BalancerBPTExiter', function () {
|
76 | 86 | })
|
77 | 87 |
|
78 | 88 | context('when the threshold has passed', () => {
|
79 |
| - const threshold = fp(10) |
| 89 | + const threshold = amount |
80 | 90 |
|
81 |
| - const setTokenThreshold = async () => { |
82 |
| - const setDefaultTokenThresholdRole = task.interface.getSighash('setDefaultTokenThreshold') |
83 |
| - await authorizer.connect(owner).authorize(owner.address, task.address, setDefaultTokenThresholdRole, []) |
84 |
| - await task.connect(owner).setDefaultTokenThreshold(pool.address, threshold, 0) |
| 91 | + const setTokenThreshold = () => { |
| 92 | + beforeEach('set default token threshold', async () => { |
| 93 | + const setDefaultTokenThresholdRole = task.interface.getSighash('setDefaultTokenThreshold') |
| 94 | + await authorizer.connect(owner).authorize(owner.address, task.address, setDefaultTokenThresholdRole, []) |
| 95 | + await task.connect(owner).setDefaultTokenThreshold(pool.address, threshold, 0) |
| 96 | + }) |
85 | 97 | }
|
86 | 98 |
|
87 |
| - context('normal pools', () => { |
88 |
| - const itExitsProportionally = () => { |
89 |
| - const getTokenBalances = async (tokens: string[], account: Contract): Promise<BigNumber[]> => { |
90 |
| - return Promise.all( |
91 |
| - tokens.map(async (tokenAddress: string) => { |
92 |
| - const token = await instanceAt('IERC20', tokenAddress) |
93 |
| - return token.balanceOf(account.address) |
94 |
| - }) |
95 |
| - ) |
96 |
| - } |
| 99 | + context('with balance connectors', () => { |
| 100 | + const requestedAmount = 0 |
| 101 | + const prevConnectorId = '0x0000000000000000000000000000000000000000000000000000000000000001' |
| 102 | + |
| 103 | + const setBalanceConnectors = () => { |
| 104 | + beforeEach('set balance connectors', async () => { |
| 105 | + const setBalanceConnectorsRole = task.interface.getSighash('setBalanceConnectors') |
| 106 | + await authorizer.connect(owner).authorize(owner.address, task.address, setBalanceConnectorsRole, []) |
| 107 | + await task.connect(owner).setBalanceConnectors(prevConnectorId, ZERO_BYTES32) |
| 108 | + }) |
97 | 109 |
|
98 |
| - it('exits the BPT proportionally', async () => { |
99 |
| - const { tokens } = await balancer.getPoolTokens(await pool.getPoolId()) |
100 |
| - const previousTokenBalances = await getTokenBalances(tokens, smartVault) |
101 |
| - const previousBptBalance = await pool.balanceOf(smartVault.address) |
| 110 | + beforeEach('authorize task to update balance connectors', async () => { |
| 111 | + const updateBalanceConnectorRole = smartVault.interface.getSighash('updateBalanceConnector') |
| 112 | + await authorizer |
| 113 | + .connect(owner) |
| 114 | + .authorize(task.address, smartVault.address, updateBalanceConnectorRole, []) |
| 115 | + }) |
102 | 116 |
|
103 |
| - await task.call(pool.address, amount) |
| 117 | + beforeEach('assign amount in to previous balance connector', async () => { |
| 118 | + const updateBalanceConnectorRole = smartVault.interface.getSighash('updateBalanceConnector') |
| 119 | + await authorizer |
| 120 | + .connect(owner) |
| 121 | + .authorize(owner.address, smartVault.address, updateBalanceConnectorRole, []) |
| 122 | + await smartVault.connect(owner).updateBalanceConnector(prevConnectorId, pool.address, amount, true) |
| 123 | + }) |
| 124 | + } |
104 | 125 |
|
105 |
| - const currentTokenBalances = await getTokenBalances(tokens, smartVault) |
106 |
| - currentTokenBalances.forEach((currentBalance, i) => |
107 |
| - expect(currentBalance).to.be.gt(previousTokenBalances[i]) |
108 |
| - ) |
| 126 | + const itUpdatesTheBalanceConnectorsProperly = () => { |
| 127 | + it('updates the balance connectors properly', async () => { |
| 128 | + const tx = await task.call(pool.address, requestedAmount) |
109 | 129 |
|
110 |
| - const currentBptBalance = await pool.balanceOf(smartVault.address) |
111 |
| - expect(currentBptBalance).to.be.equal(previousBptBalance.sub(amount)) |
| 130 | + await assertIndirectEvent(tx, smartVault.interface, 'BalanceConnectorUpdated', { |
| 131 | + id: prevConnectorId, |
| 132 | + token: pool.address, |
| 133 | + amount, |
| 134 | + added: false, |
| 135 | + }) |
112 | 136 | })
|
113 | 137 | }
|
114 | 138 |
|
115 |
| - context('weighted pool', () => { |
116 |
| - const POOL = '0x5c6ee304399dbdb9c8ef030ab642b10820db8f56' // BAL-WETH 80/20 |
117 |
| - const WHALE = '0x24faf482304ed21f82c86ed5feb0ea313231a808' |
| 139 | + context('normal pools', () => { |
| 140 | + const itExitsProportionally = () => { |
| 141 | + const getTokenBalances = async (tokens: string[], account: Contract): Promise<BigNumber[]> => { |
| 142 | + return Promise.all( |
| 143 | + tokens.map(async (tokenAddress: string) => { |
| 144 | + const token = await instanceAt('IERC20', tokenAddress) |
| 145 | + return token.balanceOf(account.address) |
| 146 | + }) |
| 147 | + ) |
| 148 | + } |
| 149 | + |
| 150 | + it('exits the BPT proportionally', async () => { |
| 151 | + const { tokens } = await balancer.getPoolTokens(await pool.getPoolId()) |
| 152 | + const previousTokenBalances = await getTokenBalances(tokens, smartVault) |
| 153 | + const previousBptBalance = await pool.balanceOf(smartVault.address) |
| 154 | + |
| 155 | + await task.call(pool.address, requestedAmount) |
| 156 | + |
| 157 | + const currentTokenBalances = await getTokenBalances(tokens, smartVault) |
| 158 | + currentTokenBalances.forEach((currentBalance, i) => |
| 159 | + expect(currentBalance).to.be.gt(previousTokenBalances[i]) |
| 160 | + ) |
| 161 | + |
| 162 | + const currentBptBalance = await pool.balanceOf(smartVault.address) |
| 163 | + expect(currentBptBalance).to.be.equal(previousBptBalance.sub(amount)) |
| 164 | + }) |
| 165 | + } |
118 | 166 |
|
119 |
| - setUpPool('IBalancerPool', POOL, WHALE) |
120 |
| - setTokenThreshold() |
121 |
| - itExitsProportionally() |
122 |
| - }) |
| 167 | + context('weighted pool', () => { |
| 168 | + const POOL = '0x5c6Ee304399DBdB9C8Ef030aB642B10820DB8F56' // BAL-WETH 80/20 |
| 169 | + const WHALE = '0x24faf482304ed21f82c86ed5feb0ea313231a808' |
| 170 | + |
| 171 | + setUpPool('IBalancerPool', POOL, WHALE) |
| 172 | + setTokenThreshold() |
| 173 | + setBalanceConnectors() |
| 174 | + |
| 175 | + itExitsProportionally() |
| 176 | + itUpdatesTheBalanceConnectorsProperly() |
| 177 | + }) |
| 178 | + |
| 179 | + context('stable pool', () => { |
| 180 | + const POOL = '0x06Df3b2bbB68adc8B0e302443692037ED9f91b42' // staBAL3 |
| 181 | + const WHALE = '0xb49d12163334f13c2a1619b6b73659fe6e849e30' |
123 | 182 |
|
124 |
| - context('stable pool', () => { |
125 |
| - const POOL = '0x06df3b2bbb68adc8b0e302443692037ed9f91b42' // staBAL3 |
126 |
| - const WHALE = '0xb49d12163334f13c2a1619b6b73659fe6e849e30' |
| 183 | + setUpPool('IBalancerPool', POOL, WHALE) |
| 184 | + setTokenThreshold() |
| 185 | + setBalanceConnectors() |
127 | 186 |
|
128 |
| - setUpPool('IBalancerPool', POOL, WHALE) |
129 |
| - setTokenThreshold() |
130 |
| - itExitsProportionally() |
| 187 | + itExitsProportionally() |
| 188 | + itUpdatesTheBalanceConnectorsProperly() |
| 189 | + }) |
131 | 190 | })
|
132 |
| - }) |
133 | 191 |
|
134 |
| - context('boosted pools', () => { |
135 |
| - const itSwapsForTheFirstUnderlyingToken = () => { |
136 |
| - it('swaps to the first underlying token', async () => { |
137 |
| - const bptIndex = await pool.getBptIndex() |
138 |
| - const { tokens } = await balancer.getPoolTokens(await pool.getPoolId()) |
139 |
| - const underlying = await instanceAt('IBalancerBoostedPool', tokens[bptIndex.eq(0) ? 1 : 0]) |
| 192 | + context('boosted pools', () => { |
| 193 | + const itSwapsForTheFirstUnderlyingToken = () => { |
| 194 | + it('swaps to the first underlying token', async () => { |
| 195 | + const bptIndex = await pool.getBptIndex() |
| 196 | + const { tokens } = await balancer.getPoolTokens(await pool.getPoolId()) |
| 197 | + const underlying = await instanceAt('IBalancerBoostedPool', tokens[bptIndex.eq(0) ? 1 : 0]) |
140 | 198 |
|
141 |
| - const previousBptBalance = await pool.balanceOf(smartVault.address) |
142 |
| - const previousUnderlyingBalance = await underlying.balanceOf(smartVault.address) |
| 199 | + const previousBptBalance = await pool.balanceOf(smartVault.address) |
| 200 | + const previousUnderlyingBalance = await underlying.balanceOf(smartVault.address) |
143 | 201 |
|
144 |
| - await task.call(pool.address, amount) |
| 202 | + await task.call(pool.address, requestedAmount) |
145 | 203 |
|
146 |
| - const currentBptBalance = await pool.balanceOf(smartVault.address) |
147 |
| - expect(currentBptBalance).to.be.equal(previousBptBalance.sub(amount)) |
| 204 | + const currentBptBalance = await pool.balanceOf(smartVault.address) |
| 205 | + expect(currentBptBalance).to.be.equal(previousBptBalance.sub(amount)) |
148 | 206 |
|
149 |
| - const currentUnderlyingBalance = await underlying.balanceOf(smartVault.address) |
150 |
| - expect(currentUnderlyingBalance).to.be.gt(previousUnderlyingBalance) |
151 |
| - }) |
152 |
| - } |
| 207 | + const currentUnderlyingBalance = await underlying.balanceOf(smartVault.address) |
| 208 | + expect(currentUnderlyingBalance).to.be.gt(previousUnderlyingBalance) |
| 209 | + }) |
| 210 | + } |
153 | 211 |
|
154 |
| - context('linear pool', () => { |
155 |
| - const POOL = '0x2BBf681cC4eb09218BEe85EA2a5d3D13Fa40fC0C' // bb-a-USDT |
156 |
| - const WHALE = '0xc578d755cd56255d3ff6e92e1b6371ba945e3984' |
| 212 | + context('linear pool', () => { |
| 213 | + const POOL = '0x2BBf681cC4eb09218BEe85EA2a5d3D13Fa40fC0C' // bb-a-USDT |
| 214 | + const WHALE = '0xc578d755cd56255d3ff6e92e1b6371ba945e3984' |
157 | 215 |
|
158 |
| - setUpPool('IBalancerLinearPool', POOL, WHALE) |
159 |
| - setTokenThreshold() |
| 216 | + setUpPool('IBalancerLinearPool', POOL, WHALE) |
| 217 | + setTokenThreshold() |
| 218 | + setBalanceConnectors() |
160 | 219 |
|
161 |
| - it('swaps for the first main token', async () => { |
162 |
| - const mainToken = await instanceAt('IERC20', pool.getMainToken()) |
| 220 | + it('swaps for the first main token', async () => { |
| 221 | + const mainToken = await instanceAt('IERC20', pool.getMainToken()) |
163 | 222 |
|
164 |
| - const previousBptBalance = await pool.balanceOf(smartVault.address) |
165 |
| - const previousMainTokenBalance = await mainToken.balanceOf(smartVault.address) |
| 223 | + const previousBptBalance = await pool.balanceOf(smartVault.address) |
| 224 | + const previousMainTokenBalance = await mainToken.balanceOf(smartVault.address) |
166 | 225 |
|
167 |
| - await task.call(pool.address, amount) |
| 226 | + await task.call(pool.address, requestedAmount) |
168 | 227 |
|
169 |
| - const currentBptBalance = await pool.balanceOf(smartVault.address) |
170 |
| - expect(currentBptBalance).to.be.equal(previousBptBalance.sub(amount)) |
| 228 | + const currentBptBalance = await pool.balanceOf(smartVault.address) |
| 229 | + expect(currentBptBalance).to.be.equal(previousBptBalance.sub(amount)) |
171 | 230 |
|
172 |
| - const currentMainTokenBalance = await mainToken.balanceOf(smartVault.address) |
173 |
| - expect(currentMainTokenBalance).to.be.gt(previousMainTokenBalance) |
| 231 | + const currentMainTokenBalance = await mainToken.balanceOf(smartVault.address) |
| 232 | + expect(currentMainTokenBalance).to.be.gt(previousMainTokenBalance) |
| 233 | + }) |
| 234 | + |
| 235 | + itUpdatesTheBalanceConnectorsProperly() |
174 | 236 | })
|
175 |
| - }) |
176 | 237 |
|
177 |
| - context('phantom pool', () => { |
178 |
| - const POOL = '0x7b50775383d3d6f0215a8f290f2c9e2eebbeceb2' // bb-a-USDT bb-a-DAI bb-a-USDC |
179 |
| - const WHALE = '0x575daf04615aef7272b388e3d7fac8adf1974173' |
| 238 | + context('phantom pool', () => { |
| 239 | + const POOL = '0x7B50775383d3D6f0215A8F290f2C9e2eEBBEceb2' // bb-a-USDT bb-a-DAI bb-a-USDC |
| 240 | + const WHALE = '0x575daf04615aef7272b388e3d7fac8adf1974173' |
180 | 241 |
|
181 |
| - setUpPool('IBalancerBoostedPool', POOL, WHALE) |
182 |
| - setTokenThreshold() |
183 |
| - itSwapsForTheFirstUnderlyingToken() |
184 |
| - }) |
| 242 | + setUpPool('IBalancerBoostedPool', POOL, WHALE) |
| 243 | + setTokenThreshold() |
| 244 | + setBalanceConnectors() |
185 | 245 |
|
186 |
| - context('composable pool', () => { |
187 |
| - const POOL = '0xa13a9247ea42d743238089903570127dda72fe44' // bb-a-USD |
188 |
| - const WHALE = '0x43b650399f2e4d6f03503f44042faba8f7d73470' |
| 246 | + itSwapsForTheFirstUnderlyingToken() |
| 247 | + itUpdatesTheBalanceConnectorsProperly() |
| 248 | + }) |
189 | 249 |
|
190 |
| - setUpPool('IBalancerBoostedPool', POOL, WHALE) |
191 |
| - setTokenThreshold() |
192 |
| - itSwapsForTheFirstUnderlyingToken() |
| 250 | + context('composable pool', () => { |
| 251 | + const POOL = '0xA13a9247ea42D743238089903570127DdA72fE44' // bb-a-USD |
| 252 | + const WHALE = '0x43b650399f2e4d6f03503f44042faba8f7d73470' |
| 253 | + |
| 254 | + setUpPool('IBalancerBoostedPool', POOL, WHALE) |
| 255 | + setTokenThreshold() |
| 256 | + setBalanceConnectors() |
| 257 | + |
| 258 | + itSwapsForTheFirstUnderlyingToken() |
| 259 | + itUpdatesTheBalanceConnectorsProperly() |
| 260 | + }) |
193 | 261 | })
|
194 | 262 | })
|
195 | 263 | })
|
|
0 commit comments