Skip to content

Commit 436bff4

Browse files
authored
Graph: Round-off error buffer (#111)
* Upgrade packages * Graph: Round-off errors * Graph: Integration test for round-off
1 parent ef63791 commit 436bff4

File tree

2 files changed

+38
-1
lines changed

2 files changed

+38
-1
lines changed

contracts/tenderizer/integrations/graph/Graph.sol

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,8 +131,16 @@ contract Graph is Tenderizer {
131131
} else {
132132
// Check that gov withdrawal for that unstake has occured
133133
require(_unstakeLockID < governanceLastProcessedUnstakeLockID, "GOV_WITHDRAW_PENDING");
134+
134135
// Transfer amount from unbondingLock to _account
135-
steak.transfer(_account, amount);
136+
try steak.transfer(_account, amount) {
137+
} catch {
138+
// Account for roundoff errors in shares calculations
139+
uint256 steakBal = steak.balanceOf(address(this));
140+
if (amount > steakBal) {
141+
steak.transfer(_account, steakBal);
142+
}
143+
}
136144
}
137145

138146
emit Withdraw(account, amount, _unstakeLockID);

test/integration/graph.test.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -472,6 +472,35 @@ describe('Graph Integration Test', () => {
472472
it('should emit Withdraw event from Tenderizer', async () => {
473473
expect(tx).to.emit(Tenderizer, 'Withdraw').withArgs(deployer, withdrawAmount, unbondLockID)
474474
})
475+
476+
it('should withdraw tenderizer GRT balance if < requested amount', async () => {
477+
await Controller.connect(signers[2]).unlock(secondDeposit)
478+
let txData = ethers.utils.arrayify(Tenderizer.interface.encodeFunctionData('unstake',
479+
[Controller.address, ethers.utils.parseEther('0')]))
480+
await Controller.execute(Tenderizer.address, 0, txData)
481+
txData = txData = ethers.utils.arrayify(Tenderizer.interface.encodeFunctionData('withdraw',
482+
[Controller.address, 3]))
483+
await Controller.execute(Tenderizer.address, 0, txData)
484+
const amountToBurn = (await GraphToken.balanceOf(Tenderizer.address)).sub(secondDeposit).add(1)
485+
await hre.network.provider.request({
486+
method: 'hardhat_impersonateAccount',
487+
params: [Tenderizer.address]
488+
}
489+
)
490+
const signer = await ethers.provider.getSigner(Tenderizer.address)
491+
await hre.network.provider.send('hardhat_setBalance', [
492+
Tenderizer.address,
493+
`0x${ethers.utils.parseEther('10')}`
494+
])
495+
await GraphToken.connect(signer).transfer(deployer, amountToBurn)
496+
await hre.network.provider.request({
497+
method: 'hardhat_stopImpersonatingAccount',
498+
params: [Tenderizer.address]
499+
}
500+
)
501+
await Controller.connect(signers[2]).withdraw(2)
502+
expect(await GraphToken.balanceOf(signers[2].address)).to.eq(secondDeposit.sub(1))
503+
})
475504
})
476505
})
477506

0 commit comments

Comments
 (0)