-
Notifications
You must be signed in to change notification settings - Fork 1
SOV-4106 Feat: Fee sharing collector with direct transfer #2
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
base: bobDevelopment
Are you sure you want to change the base?
Changes from 4 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,6 +6,7 @@ import '../libraries/Directives.sol'; | |
| import '../libraries/Encoding.sol'; | ||
| import '../libraries/TokenFlow.sol'; | ||
| import '../libraries/PriceGrid.sol'; | ||
| import '../libraries/ProtocolCmd.sol'; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why do you need it here? |
||
| import '../mixins/MarketSequencer.sol'; | ||
| import '../mixins/SettleLayer.sol'; | ||
| import '../mixins/PoolRegistry.sol'; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| // SPDX-License-Identifier: GPL-2.0-or-later | ||
| pragma solidity 0.8.19; | ||
|
|
||
| /// @title Minimal ERC20 interface for Uniswap | ||
| /// @notice Contains a subset of the full ERC20 interface that is used in Uniswap V3 | ||
| interface IFeeProtocolCollector { | ||
| function transferTokens(address _token, uint96 _amount) external; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| // SPDX-License-Identifier: GPL-2.0-or-later | ||
| pragma solidity 0.8.19; | ||
|
|
||
| import "../libraries/PoolSpecs.sol"; | ||
|
|
||
| interface ISdexQuery { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this interface is not used anywhere |
||
| function queryPoolParams (address base, address quote, uint256 poolIdx) external view returns (PoolSpecs.Pool memory pool); | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| # SdexConvertLib | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. there is no SdexConvertLib |
||
| This SdexConvertLib is meant to be used for inside & outside integration to do the swap to this Sdex protocol (which support both direct & multihop swap) | ||
| This libraray is not 100% ready to be used, since it's still in progress and not fully tested & covered by unit tests. | ||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -7,6 +7,8 @@ import '../libraries/TokenFlow.sol'; | |||||
| import '../libraries/SafeCast.sol'; | ||||||
| import './StorageLayout.sol'; | ||||||
|
|
||||||
| import '../interfaces/IFeeProtocolCollector.sol'; | ||||||
|
|
||||||
| /* @title Protocol Account Mixin | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the ProtocolAccount contract is inherited in WarmPath, but seems not to be used there. |
||||||
| * @notice Tracks and pays out the accumulated protocol fees across the entire exchange | ||||||
| * These are the fees belonging to the SdexSwap protocol, not the liquidity | ||||||
|
|
@@ -36,13 +38,20 @@ contract ProtocolAccount is StorageLayout { | |||||
|
|
||||||
| /* @notice Pays out the earned, but unclaimed protocol fees in the pool. | ||||||
| * @param recv - The receiver of the protocol fees. | ||||||
| * @param token - The token address of the quote token. */ | ||||||
| * @param token - The token address of the quote token. | ||||||
| * @return withdrawn tokens */ | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. in doesn't return anything |
||||||
| function disburseProtocolFees (address recv, address token) internal { | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we don't need a receiver (recv) here. also see comments below for clarity.
Suggested change
|
||||||
| uint128 collected = feesAccum_[token]; | ||||||
| feesAccum_[token] = 0; | ||||||
| if (collected > 0) { | ||||||
| /** | ||||||
| * directly deposit token to fee protocol collector | ||||||
| */ | ||||||
| bytes32 payoutKey = keccak256(abi.encode(recv, token)); | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. add a constant PROTOCOL_FEES_RECEIVER_HASH - hash of 'PROTOCOL_FEES_RECEIVER' + some nonce - can be a hardcoded hash and use instead of recv because should we replace the FeeSharingCollector, the fees collected should be paid out to the new FSC, otherwise this portion will stuck or we would need to call from the previous FSC which is tricky - need not to forget to do it. once replaced - we should only transfer all the fees to he new FSC - one time operation.
Suggested change
|
||||||
| userBals_[payoutKey].surplusCollateral_ += collected; | ||||||
| require(userBals_[payoutKey].surplusCollateral_ <= type(uint96).max, "Value exceeds uint96 range"); | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not really related to this change, but uint96 can theoretically overflow with something like POWA (where the total potential supply is 1 000 000 000 000 tokens with 18 decimals, or 1e30. uint96 max value is only around ~7.9e28)
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. good catch |
||||||
| IFeeProtocolCollector(treasury_).transferTokens(token, uint96(userBals_[payoutKey].surplusCollateral_)); | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||||||
| userBals_[payoutKey].surplusCollateral_ = 0; | ||||||
| } | ||||||
| } | ||||||
| } | ||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -148,44 +148,39 @@ describe('Pool Governance', () => { | |
| }) | ||
|
|
||
|
|
||
| it("collect treasury", async() => { | ||
| it("successfully collect treasury without time delay", async() => { | ||
| await test.testRevisePool(feeRate, 128, 1) // Turn on protocol fee | ||
| await pool.connect(await test.auth).protocolCmd(test.COLD_PROXY, transferCmd(policy.address), true) | ||
| await pool.connect(await test.auth).protocolCmd(test.COLD_PROXY, transferCmd(policy2.address), true) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why is policy replaced with policy2 here? |
||
| await test.testMintAmbient(10000) | ||
| await test.testSwap(true, false, 100000, MAX_PRICE) | ||
|
|
||
| await treasury.treasuryResolution(pool.address, test.COLD_PROXY, treasurySetCmd(policy2.address), true) | ||
| await hre.ethers.provider.send("evm_increaseTime", [3600*24*7+1]) // 7 days | ||
| await treasury2.treasuryResolution(pool.address, test.COLD_PROXY, treasurySetCmd(treasury2.address), true) | ||
|
|
||
| // Unauthorized attempts to collect treasury | ||
| await expect(pool.protocolCmd(test.COLD_PROXY, collectCmd(), true)).to.be.reverted | ||
| await expect(ops.opsResolution(pool.address, test.COLD_PROXY, collectCmd())).to.be.reverted | ||
| await expect(ops.treasuryResolution(pool.address, test.COLD_PROXY, collectCmd(), true)).to.be.reverted | ||
| await expect(treasury.userCmd(pool.address, test.COLD_PROXY, collectCmd())).to.be.revertedWith("Only Treasury") | ||
|
|
||
| // Successful treasury payout | ||
| let snap = await (await test.query).querySurplus(policy2.address, baseToken.address) | ||
| await treasury.treasuryResolution(pool.address, test.COLD_PROXY, collectCmd(), true) | ||
| expect(await (await test.query).querySurplus(policy2.address, baseToken.address)).to.gt(snap); | ||
| let snap = await (await test.query).querySurplus(treasury2.address, baseToken.address) | ||
| await treasury2.userCmd(pool.address, test.COLD_PROXY, collectCmd()) | ||
| expect(await (await test.query).querySurplus(treasury2.address, baseToken.address)).to.gt(snap); | ||
| }) | ||
|
|
||
| it("collect treasury time delay", async() => { | ||
| it("successfully collect treasury with time delay", async() => { | ||
| await test.testRevisePool(feeRate, 128, 1) // Turn on protocol fee | ||
| await pool.connect(await test.auth).protocolCmd(test.COLD_PROXY, transferCmd(policy.address), true) | ||
| await pool.connect(await test.auth).protocolCmd(test.COLD_PROXY, transferCmd(policy2.address), true) | ||
| await test.testMintAmbient(10000) | ||
| await test.testSwap(true, false, 100000, MAX_PRICE) | ||
|
|
||
| await treasury.treasuryResolution(pool.address, test.COLD_PROXY, treasurySetCmd(policy2.address), true) | ||
| await treasury2.treasuryResolution(pool.address, test.COLD_PROXY, treasurySetCmd(treasury2.address), true) | ||
|
|
||
| // Will fail because treasury can only be collected 7 days after treasury address is set | ||
| await expect(treasury.treasuryResolution(pool.address, test.COLD_PROXY, collectCmd(), true)).to.be.reverted | ||
| await hre.ethers.provider.send("evm_increaseTime", [3600*24*6]) // 6 days | ||
| await expect(treasury.treasuryResolution(pool.address, test.COLD_PROXY, collectCmd(), true)).to.be.reverted | ||
| await hre.ethers.provider.send("evm_increaseTime", [3600*24+1]) // One more day... treasury valid | ||
| // Unauthorized attempts to collect treasury | ||
| await expect(treasury.userCmd(pool.address, test.COLD_PROXY, collectCmd())).to.be.revertedWith("Only Treasury") | ||
|
|
||
| await hre.ethers.provider.send("evm_increaseTime", [3600*24*6]) // 6 days | ||
| // Successful treasury payout | ||
| let snap = await (await test.query).querySurplus(policy2.address, baseToken.address) | ||
| await treasury.treasuryResolution(pool.address, test.COLD_PROXY, collectCmd(), true) | ||
| expect(await (await test.query).querySurplus(policy2.address, baseToken.address)).to.gt(snap); | ||
| let snap = await (await test.query).querySurplus(treasury2.address, baseToken.address) | ||
| await treasury2.userCmd(pool.address, test.COLD_PROXY, collectCmd()) | ||
| expect(await (await test.query).querySurplus(treasury2.address, baseToken.address)).to.gt(snap); | ||
| }) | ||
|
|
||
|
|
||
|
|
||
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.
to keep it universal i suggest to restore the original code
but replace
7 dayswith a constantTREASURY_START_TIME_OFFSETto have this option if needed on other chains.The BOB and default implementation should have it set to 0.