Skip to content
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

Allowing reward donations to option #315

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions abi/AaveIncentives.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,19 @@
"name": "RewardsClaimed",
"type": "event"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "donate",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "rewardAsset",
Expand Down
13 changes: 13 additions & 0 deletions abi/AavePodCall.json
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,19 @@
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "donate",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
Expand Down
13 changes: 13 additions & 0 deletions abi/AavePodPut.json
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,19 @@
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "donate",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
Expand Down
13 changes: 13 additions & 0 deletions abi/OptionAMMPool.json
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,19 @@
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "donate",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "feePoolA",
Expand Down
14 changes: 13 additions & 1 deletion contracts/options/rewards/AaveIncentives.sol
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,18 @@ abstract contract AaveIncentives is Conversion {
function _claimRewards(address[] memory assets) internal {
IAaveIncentivesController distributor = IAaveIncentivesController(rewardContract);
uint256 amountToClaim = distributor.getRewardsBalance(assets, address(this));
distributor.claimRewards(assets, amountToClaim, address(this));
uint256 rewardBalance = _rewardBalance();

// Don't call "claim" if we have enough to pay option writers
if (rewardBalance < amountToClaim) {
distributor.claimRewards(assets, amountToClaim, address(this));
}
}

/**
* @notice Donate rewards to the option
*/
function donate(uint256 amount) external {
require(IERC20(rewardAsset).transferFrom(msg.sender, address(this), amount), "Donation Failed");
}
}
42 changes: 36 additions & 6 deletions test/options/rewards/AavePodCall.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,14 @@ describe('AavePodCall', () => {
const strikePrice = ethers.BigNumber.from(300e18.toString())
const claimable = ethers.BigNumber.from(20e18.toString())

const setupClaimable = async () => {
await aaveRewardDistributor.mock.getRewardsBalance.returns(claimable)
await aaveRewardDistributor.mock.claimRewards.returns(claimable)

await rewardToken.connect(deployer).mint(claimable)
await rewardToken.connect(deployer).transfer(option.address, claimable)
}

before(async () => {
;[deployer, minter0, minter1] = await ethers.getSigners()
;[AavePodCall, MintableInterestBearing, configurationManager, aaveRewardDistributor] = await Promise.all([
Expand All @@ -39,9 +47,6 @@ describe('AavePodCall', () => {
ethers.utils.formatBytes32String('REWARD_CONTRACT'),
aaveRewardDistributor.address
)

await aaveRewardDistributor.mock.getRewardsBalance.returns(claimable)
await aaveRewardDistributor.mock.claimRewards.returns(claimable)
})

beforeEach(async () => {
Expand All @@ -58,16 +63,15 @@ describe('AavePodCall', () => {
24 * 60 * 60, // 24h
configurationManager.address
)

await rewardToken.connect(deployer).mint(claimable)
await rewardToken.connect(deployer).transfer(option.address, claimable)
})

afterEach(async () => {
await revertToSnapshot(snapshotId)
})

it('unmints entirely and gets the rewards', async () => {
await setupClaimable()

await mintOptions(option, amountToMint, minter0)
await option.connect(minter0).unmint(amountToMint)
expect(await option.balanceOf(minter0.address)).to.be.equal(0)
Expand All @@ -76,6 +80,8 @@ describe('AavePodCall', () => {
})

it('unmints partially and gets partial rewards', async () => {
await setupClaimable()

await mintOptions(option, amountToMint, minter0)
await mintOptions(option, amountToMint, minter1)

Expand All @@ -96,8 +102,32 @@ describe('AavePodCall', () => {
})

it('withdraws and gets the rewards', async () => {
await setupClaimable()

await mintOptions(option, amountToMint, minter0)
await skipToWithdrawWindow(option)
await option.connect(minter0).withdraw()
expect(await option.shares(minter0.address)).to.be.equal(0)
expect(await underlyingAsset.balanceOf(minter0.address)).to.be.equal(amountToMint)
expect(await rewardToken.balanceOf(minter0.address)).to.be.equal(claimable)
})

it('accepts donations', async () => {
// Setup Distributor to fail when claiming rewards
await aaveRewardDistributor.mock.getRewardsBalance.returns(claimable)
await aaveRewardDistributor.mock.claimRewards.reverts()

await mintOptions(option, amountToMint, minter0)
await skipToWithdrawWindow(option)
// Withdrawing with failing distributor
const tx = option.connect(minter0).withdraw()
await expect(tx).to.be.reverted

// Subsidizing rewards
await rewardToken.connect(deployer).mint(claimable)
await rewardToken.connect(deployer).approve(option.address, claimable)
await option.connect(deployer).donate(claimable)

await option.connect(minter0).withdraw()
expect(await option.shares(minter0.address)).to.be.equal(0)
expect(await underlyingAsset.balanceOf(minter0.address)).to.be.equal(amountToMint)
Expand Down
40 changes: 34 additions & 6 deletions test/options/rewards/AavePodPut.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,14 @@ describe('AavePodPut', () => {
const strikePrice = ethers.BigNumber.from(300e18.toString())
const claimable = ethers.BigNumber.from(20e18.toString())

const setupClaimable = async () => {
await aaveRewardDistributor.mock.getRewardsBalance.returns(claimable)
await aaveRewardDistributor.mock.claimRewards.returns(claimable)

await rewardToken.connect(deployer).mint(claimable)
await rewardToken.connect(deployer).transfer(option.address, claimable)
}

before(async () => {
;[deployer, minter0, minter1] = await ethers.getSigners()
;[AavePodPut, MintableInterestBearing, configurationManager, aaveRewardDistributor] = await Promise.all([
Expand All @@ -39,9 +47,6 @@ describe('AavePodPut', () => {
ethers.utils.formatBytes32String('REWARD_CONTRACT'),
aaveRewardDistributor.address
)

await aaveRewardDistributor.mock.getRewardsBalance.returns(claimable)
await aaveRewardDistributor.mock.claimRewards.returns(claimable)
})

beforeEach(async () => {
Expand All @@ -58,16 +63,15 @@ describe('AavePodPut', () => {
24 * 60 * 60, // 24h
configurationManager.address
)

await rewardToken.connect(deployer).mint(claimable)
await rewardToken.connect(deployer).transfer(option.address, claimable)
})

afterEach(async () => {
await revertToSnapshot(snapshotId)
})

it('unmints entirely and gets the rewards', async () => {
await setupClaimable()

await mintOptions(option, amountToMint, minter0)
await option.connect(minter0).unmint(amountToMint)
expect(await option.balanceOf(minter0.address)).to.be.equal(0)
Expand All @@ -76,6 +80,7 @@ describe('AavePodPut', () => {
})

it('unmints partially and gets partial rewards', async () => {
await setupClaimable()
await mintOptions(option, amountToMint, minter0)
await mintOptions(option, amountToMint, minter1)

Expand All @@ -96,11 +101,34 @@ describe('AavePodPut', () => {
})

it('withdraws and gets the rewards', async () => {
await setupClaimable()
await mintOptions(option, amountToMint, minter0)
await skipToWithdrawWindow(option)
await option.connect(minter0).withdraw()
expect(await option.shares(minter0.address)).to.be.equal(0)
expect(await strikeAsset.balanceOf(minter0.address)).to.be.equal(strikePrice)
expect(await rewardToken.balanceOf(minter0.address)).to.be.equal(claimable)
})

it('accepts donations', async () => {
// Setup Distributor to fail when claiming rewards
await aaveRewardDistributor.mock.getRewardsBalance.returns(claimable)
await aaveRewardDistributor.mock.claimRewards.reverts()

await mintOptions(option, amountToMint, minter0)
await skipToWithdrawWindow(option)
// Withdrawing with failing distributor
const tx = option.connect(minter0).withdraw()
await expect(tx).to.be.reverted

// Subsidizing rewards
await rewardToken.connect(deployer).mint(claimable)
await rewardToken.connect(deployer).approve(option.address, claimable)
await option.connect(deployer).donate(claimable)

await option.connect(minter0).withdraw()
expect(await option.shares(minter0.address)).to.be.equal(0)
expect(await strikeAsset.balanceOf(minter0.address)).to.be.equal(strikePrice)
expect(await rewardToken.balanceOf(minter0.address)).to.be.equal(claimable)
})
})