-
Notifications
You must be signed in to change notification settings - Fork 106
Adding CompClaimAdapter #88
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
Changes from all 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 |
---|---|---|
@@ -0,0 +1,84 @@ | ||
/* | ||
Copyright 2021 Set Labs Inc. | ||
|
||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
|
||
http://www.apache.org/licenses/LICENSE-2.0 | ||
|
||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
|
||
SPDX-License-Identifier: Apache License, Version 2.0 | ||
*/ | ||
|
||
pragma solidity 0.6.10; | ||
pragma experimental "ABIEncoderV2"; | ||
|
||
import { IComptroller } from "../../../interfaces/external/IComptroller.sol"; | ||
|
||
/** | ||
* @title CompClaimAdapter | ||
* @author bronco.eth | ||
* | ||
* Claim adapter that allows managers to claim COMP from assets deposited on Compound. | ||
*/ | ||
contract CompClaimAdapter { | ||
|
||
/* ============ State Variables ============ */ | ||
|
||
// Compound Comptroller contract has a claimComp function | ||
// https://compound.finance/docs/comptroller#claim-comp | ||
IComptroller public immutable comptroller; | ||
|
||
/* ============ Constructor ============ */ | ||
|
||
/** | ||
* Set state variables | ||
* | ||
* @param _comptroller Address of the Compound Comptroller contract with a claimComp function | ||
*/ | ||
constructor(IComptroller _comptroller) public { | ||
comptroller = _comptroller; | ||
} | ||
|
||
/* ============ External Getter Functions ============ */ | ||
|
||
/** | ||
* Generates the calldata for claiming all COMP tokens for the SetToken. | ||
* https://compound.finance/docs/comptroller#claim-comp | ||
* | ||
* @param _setToken Set token address | ||
* | ||
* @return address Comptroller holding claimable COMP (aka RewardPool) | ||
* @return uint256 Unused, since it claims total claimable balance | ||
* @return bytes Claim calldata | ||
*/ | ||
function getClaimCallData(address _setToken, address /* _rewardPool */) external view returns (address, uint256, bytes memory) { | ||
bytes memory callData = abi.encodeWithSignature("claimComp(address)", _setToken); | ||
|
||
return (address(comptroller), 0, callData); | ||
} | ||
|
||
/** | ||
* Returns balance of COMP for SetToken | ||
* | ||
* @return uint256 Claimable COMP balance | ||
*/ | ||
function getRewards(address _setToken, address /* _rewardPool */) external view returns(uint256) { | ||
return comptroller.compAccrued(_setToken); | ||
} | ||
|
||
/** | ||
* Returns COMP token address | ||
* | ||
* @return address COMP token address | ||
*/ | ||
function getTokenAddress(address /* _rewardPool */) external view returns(address) { | ||
return comptroller.getCompAddress(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,183 @@ | ||
import "module-alias/register"; | ||
import { waffle } from "hardhat"; | ||
import { Contract, BigNumber } from "ethers"; | ||
import { Address } from "@utils/types"; | ||
import { Account } from "@utils/test/types"; | ||
import { ADDRESS_ZERO } from "@utils/constants"; | ||
import { | ||
CompClaimAdapter, | ||
ClaimModule, | ||
SetToken, | ||
StandardTokenMock, | ||
} from "@utils/contracts"; | ||
import DeployHelper from "@utils/deploys"; | ||
import { ether } from "@utils/index"; | ||
import { | ||
addSnapshotBeforeRestoreAfterEach, | ||
getAccounts, | ||
getSystemFixture, | ||
getWaffleExpect, | ||
} from "@utils/test/index"; | ||
import { SystemFixture } from "@utils/fixtures"; | ||
|
||
const ComptrollerArtifact = require("../../../external/abi/compound/Comptroller.json"); | ||
const expect = getWaffleExpect(); | ||
const { deployMockContract } = waffle; | ||
|
||
describe("CompClaimAdapter", function() { | ||
let owner: Account; | ||
let compoundAdmin: Account; | ||
let deployer: DeployHelper; | ||
let comptroller: Contract; | ||
let compClaimAdapter: CompClaimAdapter; | ||
|
||
before(async function() { | ||
[ | ||
owner, | ||
compoundAdmin, | ||
] = await getAccounts(); | ||
|
||
deployer = new DeployHelper(owner.wallet); | ||
}); | ||
|
||
context("unit tests", async function() { | ||
|
||
before(async function() { | ||
comptroller = await deployMockContract(owner.wallet, ComptrollerArtifact.abi); | ||
compClaimAdapter = await deployer.adapters.deployCompClaimAdapter(comptroller.address); | ||
}); | ||
|
||
describe("#getClaimCallData", async function() { | ||
let claimCallData: string; | ||
|
||
before(function() { | ||
claimCallData = comptroller.interface.encodeFunctionData("claimComp(address)", [ADDRESS_ZERO]); | ||
}); | ||
|
||
function subject(): Promise<[Address, BigNumber, string]> { | ||
return compClaimAdapter.connect(owner.wallet).getClaimCallData(ADDRESS_ZERO, ADDRESS_ZERO); | ||
} | ||
|
||
it("should return claim callData", async function() { | ||
const callData = await subject(); | ||
|
||
expect(callData[0]).to.eq(comptroller.address); | ||
expect(callData[1]).to.eq(ether(0)); | ||
expect(callData[2]).to.eq(claimCallData); | ||
}); | ||
}); | ||
|
||
describe("#getRewards", async function() { | ||
const rewards: BigNumber = ether(1); | ||
|
||
before(async function() { | ||
await comptroller.mock.compAccrued.returns(rewards); | ||
}); | ||
|
||
function subject(): Promise<BigNumber> { | ||
return compClaimAdapter.connect(owner.wallet).getRewards(ADDRESS_ZERO, ADDRESS_ZERO); | ||
} | ||
|
||
it("should return rewards", async function() { | ||
expect(await subject()).to.eq(rewards); | ||
}); | ||
}); | ||
|
||
describe("#getTokenAddress", async function() { | ||
before(async function() { | ||
await comptroller.mock.getCompAddress.returns(ADDRESS_ZERO); | ||
}); | ||
|
||
function subject(): Promise<Address> { | ||
return compClaimAdapter.connect(owner.wallet).getTokenAddress(ADDRESS_ZERO); | ||
} | ||
|
||
it("should return comp address", async function() { | ||
const address = await subject(); | ||
|
||
expect(address).to.eq(ADDRESS_ZERO); | ||
}); | ||
}); | ||
}); | ||
|
||
context("integration with ClaimModule", async function() { | ||
let comp: StandardTokenMock, cToken: StandardTokenMock; | ||
let claimModule: ClaimModule; | ||
let setToken: SetToken; | ||
let setup: SystemFixture; | ||
|
||
const amount: BigNumber = ether(10); | ||
const anyoneClaim: boolean = true; | ||
const compClaimAdapterIntegrationName: string = "COMP_CLAIM"; | ||
const integrations: string[] = [compClaimAdapterIntegrationName]; | ||
|
||
before(async function() { | ||
comp = await deployer.mocks.deployTokenMock(compoundAdmin.address, amount, 18); | ||
cToken = await deployer.mocks.deployTokenMock(compoundAdmin.address, amount, 18); | ||
comptroller = await deployer.mocks.deployComptrollerMock(comp.address, amount, cToken.address); | ||
compClaimAdapter = await deployer.adapters.deployCompClaimAdapter(comptroller.address); | ||
|
||
setup = getSystemFixture(owner.address); | ||
await setup.initialize(); | ||
|
||
claimModule = await deployer.modules.deployClaimModule(setup.controller.address); | ||
await setup.controller.addModule(claimModule.address); | ||
await setup.integrationRegistry.addIntegration(claimModule.address, compClaimAdapterIntegrationName, compClaimAdapter.address); | ||
|
||
setToken = await setup.createSetToken( | ||
[setup.weth.address], | ||
[ether(1)], | ||
[claimModule.address] | ||
); | ||
|
||
await claimModule.connect(owner.wallet).initialize(setToken.address, anyoneClaim, [comptroller.address], integrations); | ||
}); | ||
|
||
addSnapshotBeforeRestoreAfterEach(); | ||
|
||
describe("ClaimModule#getRewards", async function() { | ||
const amount: BigNumber = ether(0.1); | ||
|
||
before(async () => { | ||
await comptroller.setCompAccrued(setToken.address, amount); | ||
}); | ||
|
||
async function subject(): Promise<any> { | ||
return claimModule.connect(owner.wallet).getRewards(setToken.address, comptroller.address, compClaimAdapterIntegrationName); | ||
} | ||
|
||
it("should return accrued amount", async () => { | ||
const result: number = await subject(); | ||
|
||
expect(result).to.eq(amount); | ||
}); | ||
}); | ||
|
||
describe("ClaimModule#claim", async function() { | ||
const amount: BigNumber = ether(0.1); | ||
|
||
before(async function() { | ||
await comp.mint(comptroller.address, amount); | ||
await comptroller.setCompAccrued(setToken.address, amount); | ||
}); | ||
|
||
function subject(): Promise<any> { | ||
return claimModule.connect(owner.wallet).claim(setToken.address, comptroller.address, compClaimAdapterIntegrationName); | ||
} | ||
|
||
it("should dispatch RewardClaimed event", async function() { | ||
const claim = await subject(); | ||
const receipt = await claim.wait(); | ||
|
||
// Get RewardClaimed event dispatched in a ClaimModule#_claim call | ||
const rewardClaimed: any = receipt.events.find((e: any): any => e.event == "RewardClaimed"); | ||
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. So the actual claimComp doesn't transfer any tokens? Ideally it would be a mock to transfer reward token to the SetToken and check the balance of: 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 point, I used ComptrollerMock that was already in the repo. It's claiming function is triggering a transfer on a mocked Comp ERC20 token. New test is added below and it's checking how the balance changes after the #claim is executed. |
||
|
||
expect(rewardClaimed.args![3]).to.eq(amount); | ||
}); | ||
|
||
it("should claim accrued amount", async function() { | ||
await expect(subject).to.changeTokenBalance(comp, setToken, amount); | ||
}); | ||
}); | ||
}); | ||
}); |
Uh oh!
There was an error while loading. Please reload this page.