Skip to content

Commit 5099ed5

Browse files
feat: umbrella (#608)
* feat: added umbrella actions + stake token service * feat: stake token tests + wrapper * feat: changed to import from index * feat: simplify parameters for use cases * feat: added rewards distributor * feat: import from index * feat: stake gateway * feat: fixed gas estimations * feat: stake data provider * fix: ignore index * fix: import * fix: export * feat: gas est * feat: preview * Feat/data provider (#625) * feat: reward price * fix: totalAssets * feat: umbrella batch helper * feat: updated rewards controller --------- Co-authored-by: Joaquin Battilana <[email protected]>
1 parent 10582e1 commit 5099ed5

22 files changed

+7534
-3
lines changed

packages/contract-helpers/src/commons/types.ts

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { BigNumber, BytesLike, PopulatedTransaction } from 'ethers';
1+
import { BigNumber } from '@ethersproject/bignumber';
2+
import { BytesLike, PopulatedTransaction } from 'ethers';
23
import {
34
LPBorrowParamsType,
45
LPRepayParamsType,
@@ -158,6 +159,26 @@ export enum ProtocolAction {
158159
batchMetaDelegate = 'batchMetaDelegate',
159160
updateRepresentatives = 'updateRepresentatives',
160161
migrateABPT = 'migrateABPT',
162+
umbrellaStake = 'umbrellaStake',
163+
umbrellaStakeWithPermit = 'umbrellaStakeWithPermit',
164+
umbrellaStakeWithATokens = 'umbrellaStakeWithATokens',
165+
umbrellaStakeWithATokensWithPermit = 'umbrellaStakeWithATokensWithPermit',
166+
umbrellaRedeem = 'umbrellaRedeem',
167+
umbrellaRedeemATokens = 'umbrellaRedeemATokens',
168+
umbrellaStakeTokenCooldown = 'umbrellaStakeTokenCooldown',
169+
umbrellaStakeTokenDeposit = 'umbrellaStakeTokenDeposit',
170+
umbrellaStakeTokenDepositWithPermit = 'umbrellaStakeTokenDepositWithPermit',
171+
umbrellaStakeTokenRedeem = 'umbrellaStakeTokenRedeem',
172+
umbrellaClaimAllRewards = 'umbrellaClaimAllRewards',
173+
umbrellaClaimSelectedRewards = 'umbrellaClaimSelectedRewards',
174+
umbrellaStakeGatewayStake = 'umbrellaStakeGatewayStake',
175+
umbrellaStakeGatewayStakeWithPermit = 'umbrellaStakeGatewayStakeWithPermit',
176+
umbrellaStakeGatewayStakeATokens = 'umbrellaStakeGatewayStakeATokens',
177+
umbrellaStakeGatewayStakeATokensWithPermit = 'umbrellaStakeGatewayStakeATokensWithPermit',
178+
umbrellaStakeGatewayStakeNativeTokens = 'umbrellaStakeGatewayStakeNativeTokens',
179+
umbrellaStakeGatewayRedeem = 'umbrellaStakeGatewayRedeem',
180+
umbrellaStakeGatewayRedeemATokens = 'umbrellaStakeGatewayRedeemATokens',
181+
umbrellaStakeGatewayRedeemNativeTokens = 'umbrellaStakeGatewayRedeemNativeTokens',
161182
}
162183

163184
export enum GovernanceVote {
@@ -406,3 +427,10 @@ export type RepayWithATokensTxBuilder = {
406427
rateMode,
407428
}: Omit<LPRepayWithATokensType, 'user'>) => Promise<string>;
408429
};
430+
431+
export type DefinedPopulatedTransaction = PopulatedTransaction & {
432+
data: string;
433+
from: string;
434+
to: string;
435+
gasLimit: BigNumber;
436+
};

packages/contract-helpers/src/commons/utils.test.ts

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { BigNumber } from 'ethers';
1+
import { BigNumber, Wallet } from 'ethers';
2+
import { isAddress } from 'ethers/lib/utils';
23
import { transactionType } from './types';
34
import {
45
API_ETH_MOCK_ADDRESS,
@@ -9,6 +10,8 @@ import {
910
getTxValue,
1011
augustusToAmountOffsetFromCalldata,
1112
convertPopulatedTx,
13+
makePair,
14+
generateEIP712PermitMock,
1215
} from './utils';
1316

1417
describe('Utils', () => {
@@ -130,4 +133,35 @@ describe('Utils', () => {
130133
expect(convertedTx.value).toEqual(BigNumber.from('0'));
131134
});
132135
});
136+
137+
describe('makePair', () => {
138+
it('Generates a valid pair', () => {
139+
const { address, privateKey } = makePair('test_id');
140+
expect(isAddress(address)).toBeTruthy();
141+
expect(privateKey).toHaveLength(66);
142+
const wallet = new Wallet(privateKey);
143+
expect(wallet.address).toEqual(address);
144+
});
145+
it('Generate always the same pair with same id', () => {
146+
const { address: address1, privateKey: privateKey1 } =
147+
makePair('test_id');
148+
const { address: address2, privateKey: privateKey2 } =
149+
makePair('test_id');
150+
expect(address1).toEqual(address2);
151+
expect(privateKey1).toEqual(privateKey2);
152+
});
153+
});
154+
155+
describe('generateEIP712PermitMock', () => {
156+
it('Generates valid EIP712 Permit values', () => {
157+
const { value } = generateEIP712PermitMock('0x0', '0x1', '100', '1');
158+
expect(value).toEqual({
159+
owner: '0x0',
160+
spender: '0x1',
161+
value: '100',
162+
nonce: '0',
163+
deadline: '1',
164+
});
165+
});
166+
});
133167
});

packages/contract-helpers/src/commons/utils.ts

Lines changed: 126 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { BigNumber as BigNumberJs } from 'bignumber.js';
2-
import { BigNumber, constants, PopulatedTransaction } from 'ethers';
2+
import { BigNumber, constants, PopulatedTransaction, utils } from 'ethers';
33
import {
44
GasRecommendationType,
55
ProtocolAction,
@@ -150,6 +150,86 @@ export const gasLimitRecommendations: GasRecommendationType = {
150150
limit: '750000',
151151
recommended: '750000',
152152
},
153+
[ProtocolAction.umbrellaStake]: {
154+
limit: '400000',
155+
recommended: '400000',
156+
},
157+
[ProtocolAction.umbrellaStakeWithPermit]: {
158+
limit: '310000',
159+
recommended: '310000',
160+
},
161+
[ProtocolAction.umbrellaStakeWithATokens]: {
162+
limit: '310000',
163+
recommended: '310000',
164+
},
165+
[ProtocolAction.umbrellaStakeWithATokensWithPermit]: {
166+
limit: '310000',
167+
recommended: '310000',
168+
},
169+
[ProtocolAction.umbrellaRedeem]: {
170+
limit: '310000',
171+
recommended: '310000',
172+
},
173+
[ProtocolAction.umbrellaRedeemATokens]: {
174+
limit: '310000',
175+
recommended: '310000',
176+
},
177+
[ProtocolAction.umbrellaStakeTokenCooldown]: {
178+
limit: '60000',
179+
recommended: '60000',
180+
},
181+
[ProtocolAction.umbrellaStakeTokenDeposit]: {
182+
limit: '200000',
183+
recommended: '200000',
184+
},
185+
[ProtocolAction.umbrellaStakeTokenDepositWithPermit]: {
186+
limit: '300000',
187+
recommended: '300000',
188+
},
189+
[ProtocolAction.umbrellaStakeTokenRedeem]: {
190+
limit: '200000',
191+
recommended: '200000',
192+
},
193+
[ProtocolAction.umbrellaClaimAllRewards]: {
194+
limit: '310000',
195+
recommended: '310000',
196+
},
197+
[ProtocolAction.umbrellaClaimSelectedRewards]: {
198+
limit: '310000',
199+
recommended: '310000',
200+
},
201+
[ProtocolAction.umbrellaStakeGatewayStake]: {
202+
limit: '310000',
203+
recommended: '310000',
204+
},
205+
[ProtocolAction.umbrellaStakeGatewayStakeWithPermit]: {
206+
limit: '310000',
207+
recommended: '310000',
208+
},
209+
[ProtocolAction.umbrellaStakeGatewayStakeATokens]: {
210+
limit: '310000',
211+
recommended: '310000',
212+
},
213+
[ProtocolAction.umbrellaStakeGatewayStakeATokensWithPermit]: {
214+
limit: '310000',
215+
recommended: '310000',
216+
},
217+
[ProtocolAction.umbrellaStakeGatewayStakeNativeTokens]: {
218+
limit: '310000',
219+
recommended: '310000',
220+
},
221+
[ProtocolAction.umbrellaStakeGatewayRedeem]: {
222+
limit: '310000',
223+
recommended: '310000',
224+
},
225+
[ProtocolAction.umbrellaStakeGatewayRedeemATokens]: {
226+
limit: '310000',
227+
recommended: '310000',
228+
},
229+
[ProtocolAction.umbrellaStakeGatewayRedeemNativeTokens]: {
230+
limit: '310000',
231+
recommended: '310000',
232+
},
153233
};
154234

155235
export const mintAmountsPerToken: Record<string, string> = {
@@ -232,3 +312,48 @@ export const convertPopulatedTx = (
232312
value: tx.value ? BigNumber.from(tx.value) : BigNumber.from('0'),
233313
};
234314
};
315+
316+
export const makePair = (id: string) => {
317+
const privateKey = utils.id(id);
318+
const address = utils.computeAddress(privateKey);
319+
return { privateKey, address };
320+
};
321+
322+
export const DEFAULT_MOCK_VERIFYING_CONTRACT =
323+
'0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC';
324+
325+
export const generateEIP712PermitMock = (
326+
owner: string,
327+
spender: string,
328+
amount: string,
329+
deadline: string,
330+
) => {
331+
const domain = {
332+
name: 'Mocked token',
333+
version: '1',
334+
chainId: 1,
335+
verifyingContract: DEFAULT_MOCK_VERIFYING_CONTRACT,
336+
};
337+
const types = {
338+
Permit: [
339+
{ name: 'owner', type: 'address' },
340+
{ name: 'spender', type: 'address' },
341+
{ name: 'value', type: 'uint256' },
342+
{ name: 'nonce', type: 'uint256' },
343+
{ name: 'deadline', type: 'uint256' },
344+
],
345+
};
346+
const value = {
347+
owner,
348+
spender,
349+
value: amount,
350+
nonce: '0',
351+
deadline,
352+
};
353+
354+
return { domain, types, value };
355+
};
356+
357+
export function expectToBeDefined<T>(value: T | undefined): asserts value is T {
358+
expect(value).toBeDefined();
359+
}

packages/contract-helpers/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ export * from './governance-v3/aave-token-v3';
4141
export * from './governance-v3/payloads-data-helper';
4242
export * from './governance-v3/delegate-helper';
4343
export * from './abpt-migration';
44+
export * from './umbrella';
4445

4546
// commons
4647
export * from './commons/types';
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
import { ProtocolAction } from '../commons/types';
2+
import {
3+
expectToBeDefined,
4+
gasLimitRecommendations,
5+
makePair,
6+
} from '../commons/utils';
7+
import { IRewardsDistributor__factory } from './typechain/IRewardsDistributor__factory';
8+
import { RewardsDistributorService } from './';
9+
10+
describe('Umbrella Rewards distributor', () => {
11+
const { address: STAKE_TOKEN } = makePair('STAKE_TOKEN');
12+
const { address: STAKE_TOKEN_2 } = makePair('STAKE_TOKEN_2');
13+
const { address: ALICE } = makePair('ALICE');
14+
15+
const REWARD_1 = makePair('REWARD_1').address;
16+
const REWARD_2 = makePair('REWARD_2').address;
17+
18+
const stakeTokenService = new RewardsDistributorService(STAKE_TOKEN);
19+
const stakeTokenInterface = IRewardsDistributor__factory.createInterface();
20+
describe('claimAllAvailableRewards', () => {
21+
it('should properly create the transaction', () => {
22+
const tx = stakeTokenService.claimAllAvailableRewards({
23+
stakeTokens: [STAKE_TOKEN, STAKE_TOKEN_2],
24+
sender: ALICE,
25+
});
26+
expect(tx.from).toEqual(ALICE);
27+
expect(tx.to).toEqual(STAKE_TOKEN);
28+
expectToBeDefined(tx.gasLimit);
29+
expectToBeDefined(tx.data);
30+
expect(tx.gasLimit.toString()).toEqual(
31+
gasLimitRecommendations[ProtocolAction.umbrellaClaimAllRewards]
32+
.recommended,
33+
);
34+
const decoded = stakeTokenInterface.decodeFunctionData(
35+
'claimAllRewards(address[],address)',
36+
tx.data,
37+
);
38+
expect(decoded).toHaveLength(2);
39+
expect(decoded[0]).toEqual([STAKE_TOKEN, STAKE_TOKEN_2]);
40+
expect(decoded[1]).toEqual(ALICE);
41+
});
42+
});
43+
describe('claimAllRewards', () => {
44+
it('should properly create the transaction', () => {
45+
const tx = stakeTokenService.claimAllRewards({
46+
stakeToken: STAKE_TOKEN,
47+
sender: ALICE,
48+
});
49+
expect(tx.from).toEqual(ALICE);
50+
expect(tx.to).toEqual(STAKE_TOKEN);
51+
expectToBeDefined(tx.gasLimit);
52+
expectToBeDefined(tx.data);
53+
expect(tx.gasLimit.toString()).toEqual(
54+
gasLimitRecommendations[ProtocolAction.umbrellaClaimAllRewards]
55+
.recommended,
56+
);
57+
const decoded = stakeTokenInterface.decodeFunctionData(
58+
'claimAllRewards(address,address)',
59+
tx.data,
60+
);
61+
expect(decoded).toHaveLength(2);
62+
expect(decoded[0]).toEqual(STAKE_TOKEN);
63+
expect(decoded[1]).toEqual(ALICE);
64+
});
65+
});
66+
describe('claimSelectedRewards', () => {
67+
it('should properly create the transaction', () => {
68+
const rewards = [REWARD_1, REWARD_2];
69+
const tx = stakeTokenService.claimSelectedRewards({
70+
stakeToken: STAKE_TOKEN,
71+
rewards,
72+
sender: ALICE,
73+
});
74+
expect(tx.from).toEqual(ALICE);
75+
expect(tx.to).toEqual(STAKE_TOKEN);
76+
expectToBeDefined(tx.gasLimit);
77+
expectToBeDefined(tx.data);
78+
expect(tx.gasLimit.toString()).toEqual(
79+
gasLimitRecommendations[ProtocolAction.umbrellaClaimSelectedRewards]
80+
.recommended,
81+
);
82+
const decoded = stakeTokenInterface.decodeFunctionData(
83+
'claimSelectedRewards(address,address[],address)',
84+
tx.data,
85+
);
86+
expect(decoded).toHaveLength(3);
87+
expect(decoded[0]).toEqual(STAKE_TOKEN);
88+
expect(decoded[1]).toEqual(rewards);
89+
expect(decoded[2]).toEqual(ALICE);
90+
});
91+
});
92+
});

0 commit comments

Comments
 (0)