-
Notifications
You must be signed in to change notification settings - Fork 78
feat: hubpool third iteration. Add dispute logic and refine bitmap structure. #14
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
24 commits
Select commit
Hold shift + click to select a range
ba54cb9
nit
chrismaree 84aad83
nit
chrismaree e971ff7
nit
chrismaree 7a24fba
Update contracts/HubPool.sol
chrismaree 2f99c84
review nit
chrismaree dcb052a
review nit
chrismaree 487e7ea
feat(hubpool): Refactor hub pool to use 1D bitmap integer
chrismaree 39ea052
nit
chrismaree febc4a6
WIP
chrismaree 1ba6779
review nit
chrismaree 1886cfd
Merge branch 'master' into chrismaree/third-pass-replayment-claim
chrismaree 439138b
review nit
chrismaree b7e3ae2
nit
chrismaree 1f6fc17
nit
chrismaree f64bf85
nit
chrismaree 8bdcec7
nit
chrismaree 89e642a
nit
chrismaree d6bc9bd
nit
chrismaree 8de1b8f
nit
chrismaree 98b2b52
nit
chrismaree eefd0c0
WIP
chrismaree 5de87a2
WIP
chrismaree 9d75d36
nit
chrismaree 8f01372
nit
chrismaree File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,64 +1,136 @@ | ||
| import { expect } from "chai"; | ||
| import { Contract } from "ethers"; | ||
|
|
||
| import { ethers } from "hardhat"; | ||
| import { ZERO_ADDRESS } from "@uma/common"; | ||
| import { ZERO_ADDRESS, parseAncillaryData } from "@uma/common"; | ||
| import { getContractFactory, SignerWithAddress, createRandomBytes32, seedWallet } from "./utils"; | ||
| import { depositDestinationChainId, bondAmount, refundProposalLiveness } from "./constants"; | ||
| import { hubPoolFixture } from "./HubPool.Fixture"; | ||
| import * as consts from "./constants"; | ||
| import { hubPoolFixture, enableTokensForLiquidityProvision } from "./HubPool.Fixture"; | ||
|
|
||
| let hubPool: Contract, weth: Contract, optimisticOracle: Contract; | ||
| let owner: SignerWithAddress, dataWorker: SignerWithAddress, liquidityProvider: SignerWithAddress; | ||
|
|
||
| let hubPool: Contract, weth: Contract, usdc: Contract; | ||
| let owner: SignerWithAddress, dataWorker: SignerWithAddress; | ||
| const mockBundleEvaluationBlockNumbers = [1, 2, 3]; | ||
| const mockPoolRebalanceLeafCount = 5; | ||
| const mockPoolRebalanceRoot = createRandomBytes32(); | ||
| const mockDestinationDistributionRoot = createRandomBytes32(); | ||
|
|
||
| describe("HubPool Relayer Refund", function () { | ||
| before(async function () { | ||
| [owner, dataWorker] = await ethers.getSigners(); | ||
| ({ weth, hubPool, usdc } = await hubPoolFixture()); | ||
| await seedWallet(dataWorker, [], weth, bondAmount); | ||
| beforeEach(async function () { | ||
| [owner, dataWorker, liquidityProvider] = await ethers.getSigners(); | ||
| ({ weth, hubPool, optimisticOracle } = await hubPoolFixture()); | ||
| await seedWallet(dataWorker, [], weth, consts.bondAmount); | ||
| await seedWallet(owner, [], weth, consts.bondAmount); | ||
| await seedWallet(dataWorker, [], weth, consts.bondAmount.add(consts.finalFee).mul(2)); | ||
| await seedWallet(liquidityProvider, [], weth, consts.amountToLp); | ||
|
|
||
| await enableTokensForLiquidityProvision(owner, hubPool, [weth]); | ||
| await weth.connect(liquidityProvider).approve(hubPool.address, consts.amountToLp); | ||
| await hubPool.connect(liquidityProvider).addLiquidity(weth.address, consts.amountToLp); | ||
| }); | ||
|
|
||
| it("Initialization of a relay correctly stores data, emits events and pulls the bond", async function () { | ||
| const bundleEvaluationBlockNumbers = [1, 2, 3]; | ||
| const poolRebalanceLeafCount = 5; | ||
| const poolRebalanceProof = createRandomBytes32(); | ||
| const destinationDistributionProof = createRandomBytes32(); | ||
| const expectedRequestExpirationTimestamp = Number(await hubPool.getCurrentTime()) + consts.refundProposalLiveness; | ||
| await weth.connect(dataWorker).approve(hubPool.address, consts.bondAmount); | ||
| const dataWorkerWethBalancerBefore = await weth.callStatic.balanceOf(dataWorker.address); | ||
|
|
||
| const expectedRequestExpirationTimestamp = Number(await hubPool.getCurrentTime()) + refundProposalLiveness; | ||
| await weth.connect(dataWorker).approve(hubPool.address, bondAmount); | ||
| await expect( | ||
| hubPool | ||
| .connect(dataWorker) | ||
| .initiateRelayerRefund( | ||
| bundleEvaluationBlockNumbers, | ||
| poolRebalanceLeafCount, | ||
| poolRebalanceProof, | ||
| destinationDistributionProof | ||
| mockBundleEvaluationBlockNumbers, | ||
| mockPoolRebalanceLeafCount, | ||
| mockPoolRebalanceRoot, | ||
| mockDestinationDistributionRoot | ||
| ) | ||
| ) | ||
| .to.emit(hubPool, "InitiateRefundRequested") | ||
| .withArgs( | ||
| 0, | ||
| expectedRequestExpirationTimestamp, | ||
| poolRebalanceLeafCount, | ||
| bundleEvaluationBlockNumbers, | ||
| poolRebalanceProof, | ||
| destinationDistributionProof, | ||
| mockPoolRebalanceLeafCount, | ||
| mockBundleEvaluationBlockNumbers, | ||
| mockPoolRebalanceRoot, | ||
| mockDestinationDistributionRoot, | ||
| dataWorker.address | ||
| ); | ||
| // Balances of the hubPool should have incremented by the bond and the dataWorker should have decremented by the bond. | ||
| expect(await weth.balanceOf(hubPool.address)).to.equal(bondAmount); | ||
| expect(await weth.balanceOf(dataWorker.address)).to.equal(0); | ||
| expect(await weth.balanceOf(hubPool.address)).to.equal(consts.bondAmount.add(consts.amountToLp)); | ||
| expect(await weth.balanceOf(dataWorker.address)).to.equal(dataWorkerWethBalancerBefore.sub(consts.bondAmount)); | ||
|
|
||
| const refundRequest = await hubPool.refundRequest(); | ||
| expect(refundRequest.requestExpirationTimestamp).to.equal(expectedRequestExpirationTimestamp); | ||
| expect(refundRequest.unclaimedPoolRebalanceLeafCount).to.equal(mockPoolRebalanceLeafCount); | ||
| expect(refundRequest.poolRebalanceRoot).to.equal(mockPoolRebalanceRoot); | ||
| expect(refundRequest.destinationDistributionRoot).to.equal(mockDestinationDistributionRoot); | ||
| expect(refundRequest.claimedBitMap).to.equal(0); // no claims yet so everything should be marked at 0. | ||
| expect(refundRequest.proposer).to.equal(dataWorker.address); | ||
| expect(refundRequest.proposerBondRepaid).to.equal(false); | ||
|
|
||
| // Can not re-initialize if the previous bundle has unclaimed leaves. | ||
| await expect( | ||
| hubPool | ||
| .connect(dataWorker) | ||
| .initiateRelayerRefund( | ||
| bundleEvaluationBlockNumbers, | ||
| poolRebalanceLeafCount, | ||
| poolRebalanceProof, | ||
| destinationDistributionProof | ||
| mockBundleEvaluationBlockNumbers, | ||
| mockPoolRebalanceLeafCount, | ||
| mockPoolRebalanceRoot, | ||
| mockDestinationDistributionRoot | ||
| ) | ||
| ).to.be.revertedWith("Last bundle has unclaimed leafs"); | ||
| ).to.be.revertedWith("Active request has unclaimed leafs"); | ||
| }); | ||
| it("Dispute relayer refund correctly deletes the active request and enqueues a price request with the OO", async function () { | ||
| await weth.connect(dataWorker).approve(hubPool.address, consts.bondAmount.mul(10)); | ||
| await hubPool | ||
| .connect(dataWorker) | ||
| .initiateRelayerRefund( | ||
| mockBundleEvaluationBlockNumbers, | ||
| mockPoolRebalanceLeafCount, | ||
| mockPoolRebalanceRoot, | ||
| mockDestinationDistributionRoot | ||
| ); | ||
|
|
||
| const preCallAncillaryData = await hubPool._getRefundProposalAncillaryData(); | ||
|
|
||
| await hubPool.connect(dataWorker).disputeRelayerRefund(); | ||
|
|
||
| // Data should be deleted from the contracts refundRequest struct. | ||
| const refundRequest = await hubPool.refundRequest(); | ||
| expect(refundRequest.requestExpirationTimestamp).to.equal(0); | ||
| expect(refundRequest.unclaimedPoolRebalanceLeafCount).to.equal(0); | ||
| expect(refundRequest.poolRebalanceRoot).to.equal(consts.zeroBytes32); | ||
| expect(refundRequest.destinationDistributionRoot).to.equal(consts.zeroBytes32); | ||
| expect(refundRequest.claimedBitMap).to.equal(0); // no claims yet so everything should be marked at 0. | ||
| expect(refundRequest.proposer).to.equal(consts.zeroAddress); | ||
| expect(refundRequest.proposerBondRepaid).to.equal(false); | ||
|
|
||
| const priceProposalEvent = (await optimisticOracle.queryFilter(optimisticOracle.filters.ProposePrice()))[0].args; | ||
|
|
||
| expect(priceProposalEvent?.requester).to.equal(hubPool.address); | ||
| expect(priceProposalEvent?.identifier).to.equal(consts.identifier); | ||
| expect(priceProposalEvent?.ancillaryData).to.equal(preCallAncillaryData); | ||
|
|
||
| const parsedAncillaryData = parseAncillaryData(priceProposalEvent?.ancillaryData); | ||
| expect(parsedAncillaryData?.requestExpirationTimestamp).to.equal( | ||
| Number(await hubPool.getCurrentTime()) + consts.refundProposalLiveness | ||
| ); | ||
| expect(parsedAncillaryData?.unclaimedPoolRebalanceLeafCount).to.equal(mockPoolRebalanceLeafCount); | ||
| expect("0x" + parsedAncillaryData?.poolRebalanceRoot).to.equal(mockPoolRebalanceRoot); | ||
| expect("0x" + parsedAncillaryData?.destinationDistributionRoot).to.equal(mockDestinationDistributionRoot); | ||
| expect(parsedAncillaryData?.claimedBitMap).to.equal(0); | ||
| expect(ethers.utils.getAddress("0x" + parsedAncillaryData?.proposer)).to.equal(dataWorker.address); | ||
| }); | ||
| it("Can not dispute after proposal liveness", async function () { | ||
| await weth.connect(dataWorker).approve(hubPool.address, consts.bondAmount.mul(10)); | ||
| await hubPool | ||
| .connect(dataWorker) | ||
| .initiateRelayerRefund( | ||
| mockBundleEvaluationBlockNumbers, | ||
| mockPoolRebalanceLeafCount, | ||
| mockPoolRebalanceRoot, | ||
| mockDestinationDistributionRoot | ||
| ); | ||
|
|
||
| await hubPool.setCurrentTime(Number(await hubPool.getCurrentTime()) + consts.refundProposalLiveness + 1); | ||
|
|
||
| await expect(hubPool.connect(dataWorker).disputeRelayerRefund()).to.be.revertedWith("Request passed liveness"); | ||
| }); | ||
| }); |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
these are the new merkleLib methods I added. v simple and adapted from the original ones to take in a
uint256 claimedBitMaprather thanmapping(uint256 => uint256) storage claimedBitMap