Skip to content

Commit 8ed87a7

Browse files
committed
feat: migration with borrow
1 parent 2a14e60 commit 8ed87a7

File tree

4 files changed

+157
-46
lines changed

4 files changed

+157
-46
lines changed

pages/v3-migration.page.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ export default function V3Migration() {
3131
selectCurrentMarketV2Reserves(state, currentTimestamp)
3232
);
3333

34+
const migrateTest = useRootStore((state) => state.migrateBorrowWithoutPermits);
35+
3436
// start refreshing v3 market at the same time
3537
usePoolDataV3Subscription();
3638

@@ -57,10 +59,11 @@ export default function V3Migration() {
5759
onClick={() => toggleSelectedBorrowPosition(reserve.underlyingAsset)}
5860
style={{ color: selectedBorrowAssets[reserve.underlyingAsset] ? 'red' : 'black' }}
5961
>
60-
{reserve.variableBorrowsUSD}
62+
{reserve.variableBorrows}
6163
</button>
6264
))}
6365
<button onClick={openV3Migration}>Migrate</button>
66+
<button onClick={migrateTest}>Borrow positions test</button>
6467
</div>
6568
);
6669
}

src/helpers/useTransactionHandler.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,7 @@ export const useTransactionHandler = ({
270270
}
271271
}
272272
if ((!usePermit || !approvalTxes) && actionTx) {
273+
console.log(action, 'no permit no approvals')
273274
try {
274275
setMainTxState({ ...mainTxState, loading: true });
275276
console.log(actionTx, 'actionTx');

src/store/v3MigrationSelectors.ts

Lines changed: 77 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,89 @@
1-
import { selectUserNonEmtpySummaryAndIncentive } from './poolSelectors';
1+
import { InterestRate } from '@aave/contract-helpers';
2+
import { V3MigrationHelperSignedPermit } from '@aave/contract-helpers/dist/esm/v3-migration-contract/v3MigrationTypes';
3+
import { valueToBigNumber } from '@aave/math-utils';
4+
import { SignatureLike } from '@ethersproject/bytes';
5+
import { BigNumber, BigNumberish, constants } from 'ethers';
6+
import {
7+
selectUserNonEmtpySummaryAndIncentive,
8+
selectUserSummaryAndIncentives,
9+
} from './poolSelectors';
210
import { RootStore } from './root';
311

4-
export const selectedUserReservesForMigration = (store: RootStore, timestamp: number) => {
12+
export const selectedUserSupplyReservesForMigration = (store: RootStore, timestamp: number) => {
513
const user = selectUserNonEmtpySummaryAndIncentive(store, timestamp);
614
const selectedUserReserves = user.userReservesData.filter(
715
(userReserve) => store.selectedMigrationSupplyAssets[userReserve.underlyingAsset]
816
);
917
return selectedUserReserves;
1018
};
1119

20+
export const selectUserSupplyIncreasedReservesForMigrationPermits = (
21+
store: RootStore,
22+
timestamp: number
23+
) => {
24+
console.log('selectUserSupplyIncreasedReservesForMigrationPermits')
25+
return selectedUserSupplyReservesForMigration(store, timestamp).map((userReserve) => {
26+
const increasedAmount = addPercent(userReserve.underlyingBalance);
27+
return { ...userReserve, increasedAmount };
28+
});
29+
};
30+
31+
export const selectUserSupplyAssetsForMigrationNoPermit = (store: RootStore, timestamp: number) => {
32+
const selectedUserReserves = selectedUserSupplyReservesForMigration(store, timestamp);
33+
return selectedUserReserves.map(({ underlyingAsset, reserve }) => {
34+
const deadline = Math.floor(Date.now() / 1000 + 3600);
35+
return {
36+
amount: constants.MaxUint256.toString(),
37+
aToken: reserve.aTokenAddress,
38+
underlyingAsset: underlyingAsset,
39+
deadline,
40+
};
41+
});
42+
};
43+
44+
export const selectUserSupplyAssetsForMigrationWithPermits = (
45+
store: RootStore,
46+
signatures: SignatureLike[],
47+
deadline: BigNumberish
48+
): V3MigrationHelperSignedPermit[] => {
49+
return store.approvalPermitsForMigrationAssets.map(({ amount, underlyingAsset }, index) => {
50+
return {
51+
signedPermit: signatures[index],
52+
deadline,
53+
aToken: underlyingAsset,
54+
value: amount,
55+
};
56+
});
57+
};
58+
59+
const addPercent = (amount: string) => {
60+
const convertedAmount = valueToBigNumber(amount);
61+
return convertedAmount.plus(convertedAmount.div(1000)).toString();
62+
};
63+
64+
export const selectUserBorrowReservesForMigration = (store: RootStore, timestamp: number) => {
65+
const user = selectUserSummaryAndIncentives(store, timestamp);
66+
const selectedUserReserves = user.userReservesData
67+
// should filter for empty positions?
68+
.filter(
69+
(userReserve) =>
70+
valueToBigNumber(userReserve.stableBorrows).isGreaterThan(0) ||
71+
valueToBigNumber(userReserve.variableBorrows).isGreaterThan(0)
72+
)
73+
.filter((userReserve) => store.selectedMigrationBorrowAssets[userReserve.underlyingAsset])
74+
.map(({ reserve, ...userReserve }) => {
75+
const stableBorrows = valueToBigNumber(userReserve.stableBorrows);
76+
if (stableBorrows.isGreaterThan(0)) {
77+
const increasedAmount = addPercent(userReserve.stableBorrows);
78+
return { ...userReserve, reserve, increasedAmount, interestRate: InterestRate.Stable };
79+
}
80+
const increasedAmount = addPercent(userReserve.variableBorrows);
81+
return { ...userReserve, reserve, increasedAmount, interestRate: InterestRate.Variable };
82+
});
83+
84+
return selectedUserReserves;
85+
};
86+
1287
export const selectCurrentMarketV2Reserves = (store: RootStore, timestamp: number) => {
1388
const currentChainId = store.currentChainId;
1489
return store.data.get(currentChainId);

src/store/v3MigrationSlice.ts

Lines changed: 75 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,26 @@ import {
44
EthereumTransactionTypeExtended,
55
V3MigrationHelperService,
66
valueToWei,
7+
Pool,
8+
InterestRate,
79
} from '@aave/contract-helpers';
10+
import { V3MigrationHelperSignedPermit } from '@aave/contract-helpers/dist/esm/v3-migration-contract/v3MigrationTypes';
11+
import { valueToBigNumber } from '@aave/math-utils';
812
import { SignatureLike } from '@ethersproject/bytes';
913
import dayjs from 'dayjs';
10-
import { BigNumberish, constants } from 'ethers';
14+
import { BigNumber, BigNumberish, constants } from 'ethers';
1115
import { produce } from 'immer';
1216
import { Approval } from 'src/helpers/useTransactionHandler';
1317
import { StateCreator } from 'zustand';
1418

1519
import { RootStore } from './root';
16-
import { selectedUserReservesForMigration } from './v3MigrationSelectors';
20+
import {
21+
selectedUserSupplyReservesForMigration,
22+
selectUserBorrowReservesForMigration,
23+
selectUserSupplyAssetsForMigrationNoPermit,
24+
selectUserSupplyAssetsForMigrationWithPermits,
25+
selectUserSupplyIncreasedReservesForMigrationPermits,
26+
} from './v3MigrationSelectors';
1727

1828
export type V3MigrationSlice = {
1929
//STATE
@@ -38,6 +48,9 @@ export type V3MigrationSlice = {
3848
deadline: BigNumberish
3949
) => Promise<EthereumTransactionTypeExtended[]>;
4050
migrateWithoutPermits: () => Promise<EthereumTransactionTypeExtended[]>;
51+
migrateBorrow: (
52+
signedPermits?: V3MigrationHelperSignedPermit[]
53+
) => Promise<EthereumTransactionTypeExtended[]>;
4154
_testMigration: () => void;
4255
// migrateSelectedPositions: () => void;
4356
};
@@ -71,7 +84,14 @@ export const createV3MigrationSlice: StateCreator<
7184

7285
const typeData = {
7386
types: {
87+
EIP712Domain: [
88+
{ name: 'name', type: 'string' },
89+
{ name: 'version', type: 'string' },
90+
{ name: 'chainId', type: 'uint256' },
91+
{ name: 'verifyingContract', type: 'address' },
92+
],
7493
Permit: [
94+
// { name: 'PERMIT_TYPEHASH', type: 'string' },
7595
{ name: 'owner', type: 'address' },
7696
{ name: 'spender', type: 'address' },
7797
{ name: 'value', type: 'uint256' },
@@ -121,12 +141,12 @@ export const createV3MigrationSlice: StateCreator<
121141
getApprovePermitsForSelectedAssets: async () => {
122142
const timestamp = dayjs().unix();
123143
const approvalPermitsForMigrationAssets = await Promise.all(
124-
selectedUserReservesForMigration(get(), timestamp).map(
125-
async ({ reserve, underlyingBalance }): Promise<Approval> => {
144+
selectUserSupplyIncreasedReservesForMigrationPermits(get(), timestamp).map(
145+
async ({ reserve, increasedAmount, underlyingBalance }): Promise<Approval> => {
146+
console.log(underlyingBalance, 'underlyingBalance');
126147
const { getTokenData } = new ERC20Service(get().jsonRpcProvider());
127-
const { name, decimals } = await getTokenData(reserve.aTokenAddress);
128-
const amount = (Number(underlyingBalance) + 100).toString();
129-
const convertedAmount = valueToWei(amount, decimals);
148+
const { decimals } = await getTokenData(reserve.aTokenAddress);
149+
const convertedAmount = valueToWei(increasedAmount, decimals);
130150
return {
131151
// TODO: should we allow spending of exact ammount of the reserver?
132152
amount: convertedAmount,
@@ -142,51 +162,35 @@ export const createV3MigrationSlice: StateCreator<
142162
migrateWithoutPermits: () => {
143163
const timestamp = dayjs().unix();
144164
set({ timestamp });
145-
const assets: {
146-
aToken: string;
147-
deadline: number;
148-
amount: string;
149-
underlyingAsset: string;
150-
}[] = selectedUserReservesForMigration(get(), timestamp).map(
151-
({ underlyingAsset, underlyingBalance, reserve }) => {
152-
const deadline = Math.floor(Date.now() / 1000 + 3600);
153-
return {
154-
amount: constants.MaxUint256.toString(),
155-
aToken: reserve.aTokenAddress,
156-
underlyingAsset: underlyingAsset,
157-
// TODO: fow how long to approve?
158-
deadline,
159-
};
160-
}
161-
);
165+
const borrowedPositions = selectUserBorrowReservesForMigration(get(), timestamp);
166+
if (borrowedPositions.length > 0) {
167+
return get().migrateBorrow();
168+
}
169+
const assets = selectUserSupplyAssetsForMigrationNoPermit(get(), timestamp);
162170
const user = get().account;
163171
return get().getMigrationServiceInstance().migrateNoBorrow({ assets, user });
164172
},
165173
migrateWithPermits: async (signatures: SignatureLike[], deadline: BigNumberish) => {
166-
const permits = await Promise.all(
167-
get().approvalPermitsForMigrationAssets.map(async ({ amount, underlyingAsset }, index) => {
168-
return {
169-
signedPermit: signatures[index],
170-
deadline,
171-
aToken: underlyingAsset,
172-
value: amount,
173-
};
174-
})
174+
const signedPermits = selectUserSupplyAssetsForMigrationWithPermits(
175+
get(),
176+
signatures,
177+
deadline
175178
);
176-
// branch out into flashloan or migrate no borrow
177-
// move that to separate instance and save cache the Migrator instance
179+
const borrowedPositions = selectUserBorrowReservesForMigration(get(), get().timestamp);
180+
if (borrowedPositions.length > 0) {
181+
return get().migrateBorrow(signedPermits);
182+
}
183+
178184
const migratorHelperInstance = get().getMigrationServiceInstance();
179185
const user = get().account;
180-
const assets = selectedUserReservesForMigration(get(), get().timestamp).map(
186+
const assets = selectedUserSupplyReservesForMigration(get(), get().timestamp).map(
181187
(reserve) => reserve.underlyingAsset
182188
);
183-
await get()._testMigration();
184-
console.log(assets);
185189
return migratorHelperInstance.migrateNoBorrowWithPermits({
186190
user,
187191
assets,
188192
deadline,
189-
signedPermits: permits,
193+
signedPermits,
190194
});
191195
},
192196
getMigratorAddress: () => {
@@ -201,20 +205,48 @@ export const createV3MigrationSlice: StateCreator<
201205
}
202206
const provider = get().jsonRpcProvider();
203207
const migratorAddress = get().getMigratorAddress();
204-
const newMigratorInstance = new V3MigrationHelperService(provider, migratorAddress);
208+
const currentMarketData = get().currentMarketData;
209+
// TODO: make it dynamic when network switch will be there
210+
const pool = new Pool(provider, {
211+
POOL: '0x794a61358D6845594F94dc1DB02A252b5b4814aD',
212+
REPAY_WITH_COLLATERAL_ADAPTER: currentMarketData.addresses.REPAY_WITH_COLLATERAL_ADAPTER,
213+
SWAP_COLLATERAL_ADAPTER: currentMarketData.addresses.SWAP_COLLATERAL_ADAPTER,
214+
WETH_GATEWAY: currentMarketData.addresses.WETH_GATEWAY,
215+
L2_ENCODER: currentMarketData.addresses.L2_ENCODER,
216+
});
217+
const newMigratorInstance = new V3MigrationHelperService(provider, migratorAddress, pool);
205218
// TODO: don't forget to add maping here
206219
return newMigratorInstance;
207220
},
208221
_testMigration: async () => {
209222
const currentTimestamp = dayjs().unix();
210-
const selectedReservers = selectedUserReservesForMigration(get(), currentTimestamp);
223+
const selectedReservers = selectedUserSupplyReservesForMigration(get(), currentTimestamp);
211224
const mappedAddresses = await Promise.all(
212225
selectedReservers.map((reserve) =>
213226
get().getMigrationServiceInstance().testDeployment(reserve.underlyingAsset)
214227
)
215228
);
216-
217-
console.log(mappedAddresses);
229+
},
230+
migrateBorrow: async (signedPermits: V3MigrationHelperSignedPermit[] = []) => {
231+
const currentTimestamp = dayjs().unix();
232+
const user = get().account;
233+
const suppliedPositions = selectUserSupplyAssetsForMigrationNoPermit(get(), currentTimestamp);
234+
const borrowedPositions = selectUserBorrowReservesForMigration(get(), currentTimestamp);
235+
const mappedBorrowPositions = borrowedPositions.map(
236+
({ increasedAmount, interestRate, underlyingAsset }) => {
237+
return {
238+
amount: increasedAmount,
239+
interestRate,
240+
address: underlyingAsset,
241+
};
242+
}
243+
);
244+
return get().getMigrationServiceInstance().migrateWithBorrow({
245+
user,
246+
borrowedPositions: mappedBorrowPositions,
247+
suppliedPositions,
248+
signedPermits,
249+
});
218250
},
219251
};
220252
};

0 commit comments

Comments
 (0)