impermax-sdk 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. package/.idea/impermax-sdk.iml +12 -0
  2. package/.idea/misc.xml +6 -0
  3. package/.idea/modules.xml +8 -0
  4. package/.idea/workspace.xml +642 -0
  5. package/abis/ImpermaxABI.ts +3 -0
  6. package/abis/contracts/BAllowance.json +4735 -0
  7. package/abis/contracts/BDeployer.json +1195 -0
  8. package/abis/contracts/BInterestRateModel.json +10796 -0
  9. package/abis/contracts/BSetter.json +6219 -0
  10. package/abis/contracts/BStorage.json +2613 -0
  11. package/abis/contracts/Borrowable.json +19937 -0
  12. package/abis/contracts/CDeployer.json +1104 -0
  13. package/abis/contracts/CSetter.json +5094 -0
  14. package/abis/contracts/CStorage.json +516 -0
  15. package/abis/contracts/ClaimAggregator.json +2015 -0
  16. package/abis/contracts/Collateral.json +21615 -0
  17. package/abis/contracts/ERC20.json +819 -0
  18. package/abis/contracts/Factory.json +21986 -0
  19. package/abis/contracts/FarmingPool.json +8601 -0
  20. package/abis/contracts/IBDeployer.json +351 -0
  21. package/abis/contracts/IBorrowTracker.json +346 -0
  22. package/abis/contracts/IBorrowable.json +13207 -0
  23. package/abis/contracts/ICDeployer.json +294 -0
  24. package/abis/contracts/IClaimable.json +406 -0
  25. package/abis/contracts/ICollateral.json +8952 -0
  26. package/abis/contracts/IERC20.json +2376 -0
  27. package/abis/contracts/IFactory.json +3660 -0
  28. package/abis/contracts/IFarmingPool.json +3584 -0
  29. package/abis/contracts/IImpermaxCallee.json +679 -0
  30. package/abis/contracts/IMerkleDistributor.json +1134 -0
  31. package/abis/contracts/IPoolToken.json +5343 -0
  32. package/abis/contracts/IRouter01.json +6891 -0
  33. package/abis/contracts/IRouter02.json +7283 -0
  34. package/abis/contracts/ISimpleUniswapOracle.json +1469 -0
  35. package/abis/contracts/IStakedLPToken.json +7309 -0
  36. package/abis/contracts/IStakingRewards.json +1036 -0
  37. package/abis/contracts/IUniswapV2Callee.json +403 -0
  38. package/abis/contracts/IUniswapV2ERC20.json +3155 -0
  39. package/abis/contracts/IUniswapV2Factory.json +1690 -0
  40. package/abis/contracts/IUniswapV2Pair.json +6761 -0
  41. package/abis/contracts/IWETH.json +561 -0
  42. package/abis/contracts/ImpermaxChef.json +20945 -0
  43. package/abis/contracts/ImpermaxERC20.json +12095 -0
  44. package/abis/contracts/Math.json +1966 -0
  45. package/abis/contracts/MockERC20.json +8884 -0
  46. package/abis/contracts/PoolToken.json +10784 -0
  47. package/abis/contracts/Router01.json +43963 -0
  48. package/abis/contracts/SafeMath.json +6828 -0
  49. package/abis/contracts/SimpleUniswapOracle.json +9640 -0
  50. package/abis/contracts/TransferHelper.json +4875 -0
  51. package/abis/contracts/UQ112x112.json +1201 -0
  52. package/abis/contracts/UniswapV2ERC20.json +10969 -0
  53. package/abis/contracts/UniswapV2Factory.json +5521 -0
  54. package/abis/contracts/UniswapV2Library.json +13789 -0
  55. package/abis/contracts/UniswapV2Pair.json +30782 -0
  56. package/abis/contracts/WETH9.json +6613 -0
  57. package/config/amms.ts +199 -0
  58. package/config/contracts/claim-aggregators.ts +16 -0
  59. package/config/contracts/impermax-chef.ts +16 -0
  60. package/config/contracts/imxes.ts +16 -0
  61. package/config/contracts/merkle-distributors.ts +13 -0
  62. package/config/contracts/routers.ts +36 -0
  63. package/config/contracts/simple-uniswap-oracles.ts +33 -0
  64. package/config/contracts/weths.ts +18 -0
  65. package/config/debank-ids.ts +15 -0
  66. package/config/endpoints/merkle-distributors.ts +13 -0
  67. package/config/eth.ts +32 -0
  68. package/config/factories.ts +26 -0
  69. package/config/farms.ts +119 -0
  70. package/config/general.ts +8 -0
  71. package/config/subgraphs.ts +69 -0
  72. package/config/types.ts +81 -0
  73. package/impermax-router/Account.ts +123 -0
  74. package/impermax-router/AccountBorrowable.ts +110 -0
  75. package/impermax-router/AccountCollateral.ts +40 -0
  76. package/impermax-router/AccountLendingPool.ts +231 -0
  77. package/impermax-router/AccountPoolToken.ts +76 -0
  78. package/impermax-router/Borrowable.ts +86 -0
  79. package/impermax-router/Collateral.ts +26 -0
  80. package/impermax-router/ContractsHelper.ts +64 -0
  81. package/impermax-router/ImpermaxFactory.ts +47 -0
  82. package/impermax-router/Interactions.ts +94 -0
  83. package/impermax-router/InteractionsLendingPool.ts +129 -0
  84. package/impermax-router/InteractionsPoolToken.ts +187 -0
  85. package/impermax-router/LendingPool.ts +256 -0
  86. package/impermax-router/PoolToken.ts +112 -0
  87. package/impermax-router/index.ts +49 -0
  88. package/impermax-router/interfaces.ts +233 -0
  89. package/index.ts +5 -0
  90. package/package.json +23 -0
  91. package/subgraph/Account.ts +93 -0
  92. package/subgraph/AccountLendingPool.ts +60 -0
  93. package/subgraph/AccountPoolToken.ts +60 -0
  94. package/subgraph/LendingPool.ts +179 -0
  95. package/subgraph/PoolToken.ts +381 -0
  96. package/subgraph/PriceHelper.ts +150 -0
  97. package/subgraph/SolidexHelper.ts +54 -0
  98. package/subgraph/index.ts +166 -0
  99. package/subgraph/initializer.ts +509 -0
  100. package/subgraph/query.ts +224 -0
  101. package/tsconfig.json +16 -0
  102. package/utils/ether-utils.ts +22 -0
  103. package/utils/index.ts +12 -0
@@ -0,0 +1,86 @@
1
+ import { Contract } from "./interfaces";
2
+
3
+ import PoolToken from "./PoolToken";
4
+ import { Address, PoolTokenType } from '../config/types';
5
+
6
+ export default class Borrowable extends PoolToken {
7
+ borrowableCache: {
8
+ borrowTracker?: Promise<Address>,
9
+ rewarder?: Promise<Contract>,
10
+ rewarderTokenSymbol?: Promise<string>,
11
+ rewardSpeed?: Promise<number>,
12
+ } = {};
13
+
14
+ cleanCache() {
15
+ super.cleanCache();
16
+ this.borrowableCache = {};
17
+ }
18
+
19
+ async initializePoolToken() : Promise<Contract> {
20
+ return this.getContractHelper().newBorrowable(await this.getPoolTokenAddressFromLendingPool());
21
+ }
22
+
23
+ async initializeToken() : Promise<Contract> {
24
+ const poolToken = await this.getPoolToken();
25
+ return this.getContractHelper().newERC20(await poolToken.methods.underlying().call());
26
+ }
27
+
28
+ // Price Denom LP
29
+ async getPriceDenomLP() {
30
+ const prices = await this.lendingPool.getPriceDenomLP();
31
+ return prices[this.poolTokenType === PoolTokenType.BorrowableA ? 0 : 1];
32
+ }
33
+ async getMarketPriceDenomLP() {
34
+ const prices = await this.lendingPool.getMarketPriceDenomLP();
35
+ return prices[this.poolTokenType === PoolTokenType.BorrowableA ? 0 : 1];
36
+ }
37
+
38
+ // Farming Pool
39
+ private async initializeBorrowTracker() : Promise<Address> {
40
+ const borrowable = await this.getPoolToken();
41
+ return borrowable.methods.borrowTracker().call();
42
+ }
43
+ async getBorrowTracker() {
44
+ if (!this.borrowableCache.borrowTracker) this.borrowableCache.borrowTracker = this.initializeBorrowTracker();
45
+ return this.borrowableCache.borrowTracker;
46
+ }
47
+ async hasFarming() : Promise<boolean> {
48
+ const borrowTracker = await this.getBorrowTracker();
49
+ return borrowTracker !== '0x0000000000000000000000000000000000000000';
50
+ }
51
+ async hasImpermaxChef() : Promise<boolean> {
52
+ const borrowTracker = await this.getBorrowTracker();
53
+ return borrowTracker.toLowerCase() === (this.getImpermaxChef()._address ?? "").toLowerCase();
54
+ }
55
+ async getFarmingPool() : Promise<Contract> {
56
+ if (!await this.hasFarming() || await this.hasImpermaxChef()) return null;
57
+ return this.getContractHelper().newFarmingPool(await this.getBorrowTracker());
58
+ }
59
+ getImpermaxChef = () => this.getContractHelper().impermaxChef;
60
+ private async initializeRewarder() : Promise<Contract> {
61
+ const poolTokenAddress = await this.getPoolTokenAddress();
62
+ try {
63
+ const { rewarder } = await this.getImpermaxChef().methods.poolInfo(poolTokenAddress).call();
64
+ if (rewarder == "0x0000000000000000000000000000000000000000") return null;
65
+ return this.getContractHelper().newImpermaxChef(rewarder);
66
+ } catch { return null; }
67
+ }
68
+ async getRewarder() {
69
+ if (!this.borrowableCache.rewarder) this.borrowableCache.rewarder = this.initializeRewarder();
70
+ return this.borrowableCache.rewarder;
71
+ }
72
+ async hasRewarder() : Promise<boolean> {
73
+ return await this.getRewarder() !== null;
74
+ }
75
+ private async initializeRewarderTokenSymbol() : Promise<string> {
76
+ if (!await this.hasRewarder()) return "";
77
+ const rewarder = await this.getRewarder();
78
+ const rewardTokenAddress = await rewarder.methods.rewardToken().call();
79
+ return this.getContractHelper().newERC20(rewardTokenAddress).methods.symbol().call();
80
+ }
81
+ async getRewarderTokenSymbol() {
82
+ if (!this.borrowableCache.rewarderTokenSymbol) this.borrowableCache.rewarderTokenSymbol = this.initializeRewarderTokenSymbol();
83
+ return this.borrowableCache.rewarderTokenSymbol;
84
+ }
85
+
86
+ }
@@ -0,0 +1,26 @@
1
+ import { Contract } from "./interfaces";
2
+ import PoolToken from "./PoolToken";
3
+
4
+ export default class Collateral extends PoolToken {
5
+ collateralCache: {
6
+ } = {};
7
+
8
+ cleanCache() {
9
+ super.cleanCache();
10
+ this.collateralCache = {};
11
+ }
12
+
13
+ async initializePoolToken() : Promise<Contract> {
14
+ return this.lendingPool.factory.router.contractsHelper.newCollateral(await this.getPoolTokenAddressFromLendingPool());
15
+ }
16
+
17
+ async initializeToken() : Promise<Contract> {
18
+ return this.lendingPool.getUniswapV2Pair();
19
+ }
20
+
21
+ protected async initializeExchangeRate() : Promise<number> {
22
+ let exchangeRate = await super.initializeExchangeRate();
23
+ return exchangeRate * await this.lendingPool.getStakedLPExchangeRate();
24
+ }
25
+
26
+ }
@@ -0,0 +1,64 @@
1
+ import { Contract } from "../impermax-router/interfaces";
2
+
3
+ import ImpermaxRouter from ".";
4
+
5
+ import ERC20JSON from '../abis/contracts/IERC20.json';
6
+ import UniswapV2PairJSON from '../abis/contracts/IUniswapV2Pair.json';
7
+ import UniswapV2FactoryJSON from '../abis/contracts/IUniswapV2Factory.json';
8
+ import Router02JSON from '../abis/contracts/IRouter02.json';
9
+ import BorrowableJSON from '../abis/contracts/IBorrowable.json';
10
+ import CollateralJSON from '../abis/contracts/ICollateral.json';
11
+ import StakedLPTokenJSON from '../abis/contracts/IStakedLPToken.json';
12
+ import FactoryJSON from '../abis/contracts/IFactory.json';
13
+ import SimpleUniswapOracleJSON from '../abis/contracts/ISimpleUniswapOracle.json';
14
+ import MerkleDistributorJSON from '../abis/contracts/IMerkleDistributor.json';
15
+ import FarmingPoolJSON from '../abis/contracts/IFarmingPool.json';
16
+ import ClaimAggregatorJSON from '../abis/contracts/ClaimAggregator.json';
17
+ import ClaimableJSON from '../abis/contracts/IClaimable.json';
18
+ import StakingRewardsJSON from '../abis/contracts/IStakingRewards.json';
19
+ import ImpermaxChefJSON from '../abis/contracts/ImpermaxChef.json';
20
+ import { Address } from '../config/types';
21
+ import { IMPERMAX_CHEF } from '../config/contracts/impermax-chef';
22
+ import { CLAIM_AGGREGATOR } from '../config/contracts/claim-aggregators';
23
+ import {
24
+ MERKLE_DISTRIBUTOR_ETH,
25
+ MERKLE_DISTRIBUTOR_IBEX,
26
+ MERKLE_DISTRIBUTOR_IBEX_2
27
+ } from '../config/contracts/merkle-distributors';
28
+
29
+ export default class ContractsHelper {
30
+ router: ImpermaxRouter;
31
+ impermaxChef: Contract;
32
+ merkleDistributorIbex: Contract;
33
+ merkleDistributorIbex2: Contract;
34
+ merkleDistributorEth: Contract;
35
+ claimAggregator: Contract;
36
+
37
+ constructor(router: ImpermaxRouter) {
38
+ this.router = router;
39
+ this.impermaxChef = this.newImpermaxChef(IMPERMAX_CHEF[this.router.network]);
40
+ this.merkleDistributorIbex = this.newMerkleDistributor(MERKLE_DISTRIBUTOR_IBEX[this.router.network]);
41
+ this.merkleDistributorIbex2 = this.newMerkleDistributor(MERKLE_DISTRIBUTOR_IBEX_2[this.router.network]);
42
+ this.merkleDistributorEth = this.newMerkleDistributor(MERKLE_DISTRIBUTOR_ETH[this.router.network]);
43
+ this.claimAggregator = this.newClaimAggregator(CLAIM_AGGREGATOR[this.router.network]);
44
+ }
45
+
46
+ newContract = (abi: any, address: Address) => new this.router.web3.eth.Contract(abi, address);
47
+
48
+ newRouter = (address: Address) => this.newContract(Router02JSON.abi, address);
49
+ newFactory = (address: Address) => this.newContract(FactoryJSON.abi, address);
50
+ newSimpleUniswapOracle = (address: Address) => this.newContract(SimpleUniswapOracleJSON.abi, address);
51
+ newUniswapV2Pair = (address: Address) => this.newContract(UniswapV2PairJSON.abi, address);
52
+ newUniswapV2Factory = (address: Address) => this.newContract(UniswapV2FactoryJSON.abi, address);
53
+ newERC20 = (address: Address) => this.newContract(ERC20JSON.abi, address);
54
+ newCollateral = (address: Address) => this.newContract(CollateralJSON.abi, address);
55
+ newBorrowable = (address: Address) => this.newContract(BorrowableJSON.abi, address);
56
+ newStakedLPToken = (address: Address) => this.newContract(StakedLPTokenJSON.abi, address);
57
+ newMerkleDistributor = (address: Address) => this.newContract(MerkleDistributorJSON.abi, address);
58
+ newFarmingPool = (address: Address) => this.newContract(FarmingPoolJSON.abi, address);
59
+ newClaimAggregator = (address: Address) => this.newContract(ClaimAggregatorJSON.abi, address);
60
+ newClaimable = (address: Address) => this.newContract(ClaimableJSON.abi, address);
61
+ newStakingRewards = (address: Address) => this.newContract(StakingRewardsJSON.abi, address);
62
+ newImpermaxChef = (address: Address) => this.newContract(ImpermaxChefJSON.abi, address);
63
+
64
+ }
@@ -0,0 +1,47 @@
1
+ import ImpermaxRouter from ".";
2
+ import LendingPool from "./LendingPool";
3
+ import { Address, Factory } from '../config/types';
4
+ import { SIMPLE_UNISWAP_ORACLE } from '../config/contracts/simple-uniswap-oracles';
5
+ import { ROUTER } from '../config/contracts/routers';
6
+
7
+ export default class ImpermaxFactory {
8
+ router: ImpermaxRouter;
9
+ factory: Factory;
10
+ lendingPools: {[key in Address]: LendingPool};
11
+
12
+ constructor(router: ImpermaxRouter, factory: Factory) {
13
+ this.router = router;
14
+ this.factory = factory;
15
+ this.lendingPools = {};
16
+ }
17
+
18
+ cleanCache() {
19
+ for (const pairAddress of Object.keys(this.lendingPools) as Address[]) {
20
+ this.lendingPools[pairAddress].cleanCache();
21
+ }
22
+ }
23
+
24
+ getSimpleUniswapOracle() {
25
+ const address = SIMPLE_UNISWAP_ORACLE[this.router.network][this.factory];
26
+ if (!address) {
27
+ console.error("SimpleUniswapOracle address not found");
28
+ return null;
29
+ }
30
+ return this.router.contractsHelper.newSimpleUniswapOracle(address);
31
+ }
32
+
33
+ getRouter() {
34
+ const address = ROUTER[this.router.network][this.factory];
35
+ if (!address) {
36
+ console.error("Router address not found");
37
+ return null;
38
+ }
39
+ return this.router.contractsHelper.newRouter(address);
40
+ }
41
+
42
+ getLendingPool(uniswapV2PairAddress: Address) {
43
+ if (!this.lendingPools[uniswapV2PairAddress]) this.lendingPools[uniswapV2PairAddress] = new LendingPool(this, uniswapV2PairAddress);
44
+ return this.lendingPools[uniswapV2PairAddress];
45
+ }
46
+
47
+ }
@@ -0,0 +1,94 @@
1
+ import { BigNumber } from "ethers";
2
+ import Account from "./Account";
3
+ import AccountBorrowable from "./AccountBorrowable";
4
+ import InteractionsLendingPool from "./InteractionsLendingPool";
5
+ import { AirdropData, Contract } from "./interfaces";
6
+ import { Address, Factory, FactoryIndex, LendingPoolIndex, PoolTokenType } from '../config/types';
7
+
8
+ const ZERO = BigNumber.from(0);
9
+
10
+ export default class Interactions {
11
+ account: Account;
12
+ interactionsLLPs: LendingPoolIndex<Promise<InteractionsLendingPool>>;
13
+
14
+ constructor(account: Account) {
15
+ this.account = account;
16
+ this.interactionsLLPs = {};
17
+ }
18
+
19
+ private async initializeInteractionsLendingPool(factory: Factory, pair: Address) : Promise<InteractionsLendingPool> {
20
+ const lendingPool = await this.account.getAccountLendingPool(factory, pair);
21
+ return new InteractionsLendingPool(this, lendingPool);
22
+ }
23
+ async getInteractionsLendingPool(factory: Factory, pair: Address) : Promise<InteractionsLendingPool> {
24
+ if (!this.interactionsLLPs[factory]) this.interactionsLLPs[factory] = {};
25
+ if (!this.interactionsLLPs[factory][pair]) this.interactionsLLPs[factory][pair] = this.initializeInteractionsLendingPool(factory, pair);
26
+ return this.interactionsLLPs[factory][pair];
27
+ }
28
+
29
+ async send(method: any, onTransactionHash: Function, value = ZERO) {
30
+ try {
31
+ await method.call({from: this.account.account, value});
32
+ return method.send({from: this.account.account, value}).on('transactionHash', onTransactionHash);
33
+ } catch (e) {
34
+ console.error(e);
35
+ }
36
+ }
37
+
38
+ async claimAirdrop(airdropData: AirdropData, merkleDistributor: Contract, onTransactionHash: Function) {
39
+ return this.send(merkleDistributor.methods.claim(airdropData.index, this.account.account, airdropData.amount, airdropData.proof), onTransactionHash);
40
+ }
41
+
42
+ async claims(pairAddresses: FactoryIndex<Address[]>, onTransactionHash: Function) {
43
+ const requests: Array<Promise<{
44
+ hasPendingReward: boolean,
45
+ hasImpermaxChef: boolean,
46
+ farmingPool: Contract,
47
+ borrowableAddress: Address,
48
+ }>> = [];
49
+ for (const factory of Object.keys(pairAddresses) as Factory[]) {
50
+ for (const pairAddress of pairAddresses[factory]) {
51
+ for (const poolToken of [PoolTokenType.BorrowableA, PoolTokenType.BorrowableB]) {
52
+ requests.push((async () => {
53
+ const accountBorrowable = (await this.account.getAccountLendingPool(factory, pairAddress)).accountPoolTokens[poolToken] as AccountBorrowable;
54
+ const borrowable = accountBorrowable.poolToken;
55
+ const pendingReward = await accountBorrowable.getAvailableIMXReward() + await accountBorrowable.getAvailableRewarderReward();
56
+ return {
57
+ hasPendingReward: pendingReward > 0,
58
+ hasImpermaxChef: await borrowable.hasImpermaxChef(),
59
+ farmingPool: await borrowable.getFarmingPool(),
60
+ borrowableAddress: await borrowable.getPoolTokenAddress(),
61
+ }
62
+ })());
63
+ }
64
+ }
65
+ }
66
+ const data = await Promise.all(requests);
67
+
68
+ const toClaimThroughChef = [];
69
+ const toClaimThroughAggregator = [];
70
+ for (const borrowable of data) {
71
+ if (!borrowable.hasPendingReward) continue;
72
+ if (borrowable.hasImpermaxChef) {
73
+ toClaimThroughChef.push(borrowable.borrowableAddress);
74
+ } else {
75
+ toClaimThroughAggregator.push(borrowable.farmingPool._address);
76
+ }
77
+ }
78
+
79
+ if (toClaimThroughAggregator.length > 0) {
80
+ const claimAggregator = this.account.router.contractsHelper.claimAggregator;
81
+ return this.send(claimAggregator.methods.claims(this.account.account, toClaimThroughAggregator), onTransactionHash);
82
+ }
83
+ else if (toClaimThroughChef.length > 0) {
84
+ const impermaxChef = this.account.router.contractsHelper.impermaxChef;
85
+ return this.send(impermaxChef.methods.massHarvest(toClaimThroughChef, this.account.account), onTransactionHash);
86
+ }
87
+ }
88
+
89
+ async claimDistributor(claimableAddress: Address, onTransactionHash: Function) {
90
+ const claimable = this.account.router.contractsHelper.newClaimable(claimableAddress);
91
+ return this.send(claimable.methods.claim(), onTransactionHash);
92
+ }
93
+
94
+ }
@@ -0,0 +1,129 @@
1
+ import Interactions from "./Interactions";
2
+ import AccountLendingPool from "./AccountLendingPool";
3
+ import InteractionsPoolToken from "./InteractionsPoolToken";
4
+ import { BigNumber } from "ethers";
5
+ import { impermanentLoss } from "../utils";
6
+ import AccountBorrowable from "./AccountBorrowable";
7
+ import { PoolTokenType } from '../config/types';
8
+ import { DEADLINE } from '../config/general';
9
+ import { PermitData } from './interfaces';
10
+
11
+ export default class InteractionsLendingPool {
12
+ interactions: Interactions;
13
+ accountLendingPool: AccountLendingPool;
14
+ interactionsPoolToken: {
15
+ [PoolTokenType.Collateral]: InteractionsPoolToken,
16
+ [PoolTokenType.BorrowableA]: InteractionsPoolToken,
17
+ [PoolTokenType.BorrowableB]: InteractionsPoolToken,
18
+ }
19
+
20
+ constructor(interactions: Interactions, accountLendingPool: AccountLendingPool) {
21
+ this.interactions = interactions;
22
+ this.accountLendingPool = accountLendingPool;
23
+ this.interactionsPoolToken = {
24
+ [PoolTokenType.Collateral]: new InteractionsPoolToken(this, PoolTokenType.Collateral),
25
+ [PoolTokenType.BorrowableA]: new InteractionsPoolToken(this, PoolTokenType.BorrowableA),
26
+ [PoolTokenType.BorrowableB]: new InteractionsPoolToken(this, PoolTokenType.BorrowableB),
27
+ };
28
+ }
29
+
30
+ getRouterLendingPool = () => this.accountLendingPool.lendingPool;
31
+ getRouterContract = () => this.accountLendingPool.lendingPool.factory.getRouter();
32
+ getAccount = () => this.accountLendingPool.account.account;
33
+ send = (method: any, onTransactionHash: Function) => this.interactions.send(method, onTransactionHash);
34
+
35
+ getOwnerSpender() {
36
+ const router = this.accountLendingPool.lendingPool.factory.getRouter();
37
+ return {
38
+ owner: this.accountLendingPool.account.account,
39
+ spender: router._address,
40
+ }
41
+ }
42
+
43
+ async getLeverageAmounts(leverage: number, slippage: number) {
44
+ const [priceA, priceB] = await this.accountLendingPool.lendingPool.getMarketPriceDenomLP();
45
+ // This function must use the market price, but the account leverage is calculated with the TWAP, so we need an adjustFactor
46
+ const [priceATWAP,priceBTWAP] = await this.accountLendingPool.lendingPool.getPriceDenomLP();
47
+ const diff = priceA > priceATWAP ? priceA / priceATWAP : priceATWAP / priceA;
48
+ const adjustFactor = Math.pow(impermanentLoss(diff**2), leverage);
49
+ const currentLeverage = await this.accountLendingPool.getLeverage();
50
+ const collateralValue = await this.accountLendingPool.ptc().getDeposited();
51
+ const changeCollateralValue = (collateralValue * leverage / currentLeverage - collateralValue) * adjustFactor;
52
+ const valueForEach = changeCollateralValue / 2;
53
+ const bAmountA = priceA > 0 ? valueForEach / priceA: 0;
54
+ const bAmountB = priceB > 0 ? valueForEach / priceB: 0;
55
+ const cAmount = changeCollateralValue ? changeCollateralValue: 0;
56
+ return {
57
+ bAmountA: bAmountA,
58
+ bAmountB: bAmountB,
59
+ cAmount: cAmount,
60
+ bAmountAMin: bAmountA / slippage,
61
+ bAmountBMin: bAmountB / slippage,
62
+ cAmountMin: cAmount / Math.sqrt(slippage),
63
+ };
64
+ }
65
+ async leverage(
66
+ amountA: BigNumber,
67
+ amountB: BigNumber,
68
+ amountAMin: BigNumber,
69
+ amountBMin: BigNumber,
70
+ permitDataA: PermitData,
71
+ permitDataB: PermitData,
72
+ onTransactionHash: Function
73
+ ) {
74
+ const router = this.getRouterContract();
75
+ const dataA = permitDataA ? permitDataA.permitData : '0x';
76
+ const dataB = permitDataB ? permitDataB.permitData : '0x';
77
+ if (permitDataA && permitDataB && !permitDataA.deadline.eq(permitDataB.deadline)) return console.error("Permits deadline are not equal")
78
+ const deadline = permitDataA ? permitDataA.deadline : permitDataB ? permitDataB.deadline : DEADLINE;
79
+ const pairAddress = this.getRouterLendingPool().pairAddress;
80
+ const account = this.accountLendingPool.account.account;
81
+ return this.send(router.methods.leverage(pairAddress, amountA, amountB, amountAMin, amountBMin, account, deadline, dataA, dataB), onTransactionHash);
82
+ }
83
+
84
+ async getDeleverageAmounts(changeCollateralAmount: number, slippage: number) {
85
+ changeCollateralAmount = changeCollateralAmount ?? 0;
86
+ const [priceA, priceB] = await this.accountLendingPool.lendingPool.getMarketPriceDenomLP();
87
+ const valueForEach = changeCollateralAmount / 2;
88
+ const bAmountA = priceA > 0 ? valueForEach / priceA: 0;
89
+ const bAmountB = priceB > 0 ? valueForEach / priceB: 0;
90
+ return {
91
+ bAmountA: bAmountA,
92
+ bAmountB: bAmountB,
93
+ cAmount: changeCollateralAmount,
94
+ bAmountAMin: bAmountA / Math.sqrt(slippage),
95
+ bAmountBMin: bAmountB / Math.sqrt(slippage),
96
+ };
97
+ }
98
+ async deleverage(
99
+ tokens: BigNumber,
100
+ amountAMin: BigNumber,
101
+ amountBMin: BigNumber,
102
+ permitData: PermitData,
103
+ onTransactionHash: Function
104
+ ) {
105
+ const router = this.getRouterContract();
106
+ const data = permitData ? permitData.permitData : '0x';
107
+ const deadline = permitData ? permitData.deadline : DEADLINE;
108
+ const pairAddress = this.getRouterLendingPool().pairAddress;
109
+ return this.send(router.methods.deleverage(pairAddress, tokens, amountAMin, amountBMin, deadline, data), onTransactionHash);
110
+ }
111
+
112
+ async trackBorrows(onTransactionHash: Function) {
113
+ const account = this.accountLendingPool.account.account;
114
+ const claimAggregator = this.interactions.account.router.contractsHelper.claimAggregator;
115
+ const toTrack = [];
116
+ for (const borrowable of [PoolTokenType.BorrowableA, PoolTokenType.BorrowableB]) {
117
+ const b = this.accountLendingPool.accountPoolTokens[borrowable] as AccountBorrowable;
118
+ if (await b.getBorrowed() === 0 || await b.getFarmingShares() > 0) continue;
119
+ toTrack.push(await this.getRouterLendingPool().poolTokens[borrowable].getPoolTokenAddress());
120
+ }
121
+ return this.send(claimAggregator.methods.trackBorrows(account, toTrack), onTransactionHash);
122
+ }
123
+
124
+ async reinvest(onTransactionHash: Function) {
125
+ const account = this.accountLendingPool.account.account;
126
+ const stakedLPToken = await this.getRouterLendingPool().getStakedLPToken();
127
+ return this.send(stakedLPToken.methods.reinvest(), onTransactionHash);
128
+ }
129
+ }
@@ -0,0 +1,187 @@
1
+ import { ethers, BigNumber } from "ethers";
2
+ import AccountPoolToken from "./AccountPoolToken";
3
+ import InteractionsLendingPool from "./InteractionsLendingPool";
4
+ import { ApprovalType, PermitData } from "./interfaces";
5
+ import { PoolTokenType } from '../config/types';
6
+ import { WETH } from '../config/contracts/weths';
7
+ import { DEADLINE } from '../config/general';
8
+
9
+ const MAX_UINT256 = ethers.constants.MaxUint256;
10
+
11
+ const EIP712DOMAIN = [
12
+ { name: "name", type: "string" },
13
+ { name: "version", type: "string" },
14
+ { name: "chainId", type: "uint256" },
15
+ { name: "verifyingContract", type: "address" },
16
+ ];
17
+ const PERMIT = [
18
+ { name: "owner", type: "address" },
19
+ { name: "spender", type: "address" },
20
+ { name: "value", type: "uint256" },
21
+ { name: "nonce", type: "uint256" },
22
+ { name: "deadline", type: "uint256" },
23
+ ];
24
+ const TYPES = {
25
+ EIP712Domain: EIP712DOMAIN,
26
+ Permit: PERMIT,
27
+ BorrowPermit: PERMIT,
28
+ }
29
+
30
+ export default class InteractionsPoolToken {
31
+ interactionsLendingPool: InteractionsLendingPool;
32
+ accountPoolToken: AccountPoolToken;
33
+
34
+ constructor(interactionsLendingPool: InteractionsLendingPool, poolTokenType: PoolTokenType) {
35
+ this.interactionsLendingPool = interactionsLendingPool;
36
+ this.accountPoolToken = interactionsLendingPool.accountLendingPool.accountPoolTokens[poolTokenType];
37
+ }
38
+
39
+ // Shortcuts
40
+ getImpermaxRouter = () => this.interactionsLendingPool.interactions.account.router;
41
+ getPoolToken = () => this.accountPoolToken.poolToken;
42
+ getRouterContract = () => this.interactionsLendingPool.accountLendingPool.lendingPool.factory.getRouter();
43
+ send = (method: any, onTransactionHash: Function, value?: BigNumber) => this.interactionsLendingPool.interactions.send(method, onTransactionHash, value);
44
+
45
+ async isWETH() {
46
+ const token = await this.getPoolToken().getToken();
47
+ return token._address.toLowerCase() == WETH[this.getImpermaxRouter().network].toLowerCase();
48
+ }
49
+
50
+ isCollateral() {
51
+ return this.getPoolToken().poolTokenType == PoolTokenType.Collateral;
52
+ }
53
+
54
+ async getAllowance(approvalType: ApprovalType) {
55
+ const poolToken = await this.getPoolToken().getPoolToken();
56
+ const token = await this.getPoolToken().getToken();
57
+ if (await this.isWETH() && approvalType == ApprovalType.UNDERLYING) return MAX_UINT256;
58
+ const {owner, spender} = this.interactionsLendingPool.getOwnerSpender();
59
+ const allowance =
60
+ (approvalType == ApprovalType.POOL_TOKEN) ? await poolToken.methods.allowance(owner, spender).call() :
61
+ (approvalType == ApprovalType.UNDERLYING) ? await token.methods.allowance(owner, spender).call() :
62
+ (approvalType == ApprovalType.BORROW) ? await poolToken.methods.borrowAllowance(owner, spender).call() : 0;
63
+ return BigNumber.from(allowance);
64
+ }
65
+
66
+ async approve(approvalType: ApprovalType, amount: BigNumber, onTransactionHash: Function) {
67
+ const {spender} = this.interactionsLendingPool.getOwnerSpender();
68
+ const poolToken = await this.getPoolToken().getPoolToken();
69
+ const token = await this.getPoolToken().getToken();
70
+ let method;
71
+ if (approvalType == ApprovalType.POOL_TOKEN) method = poolToken.methods.approve(spender, amount);
72
+ if (approvalType == ApprovalType.UNDERLYING) method = token.methods.approve(spender, amount);
73
+ if (approvalType == ApprovalType.BORROW) method = poolToken.methods.borrowApprove(spender, amount);
74
+ return this.send(method, onTransactionHash);
75
+ }
76
+
77
+ async getPermitData(
78
+ approvalType: ApprovalType,
79
+ amount: BigNumber,
80
+ deadlineArg: BigNumber | null,
81
+ callBack: (permitData: PermitData) => void
82
+ ) {
83
+ if (approvalType === ApprovalType.UNDERLYING && this.getPoolToken().poolTokenType != PoolTokenType.Collateral) return callBack(null);
84
+ const {owner, spender} = this.interactionsLendingPool.getOwnerSpender();
85
+ const poolToken = await this.getPoolToken().getPoolToken();
86
+ const token = await this.getPoolToken().getToken();
87
+ const contract = approvalType == ApprovalType.UNDERLYING ? token : poolToken;
88
+ const nonce = await contract.methods.nonces(owner).call();
89
+ const name = await contract.methods.name().call();
90
+ const deadline = deadlineArg ? deadlineArg : DEADLINE;
91
+
92
+ const data = JSON.stringify({
93
+ types: TYPES,
94
+ domain: {
95
+ name: name,
96
+ version: "1",
97
+ chainId: this.getImpermaxRouter().chainId,
98
+ verifyingContract: contract._address,
99
+ },
100
+ primaryType: approvalType == ApprovalType.BORROW ? "BorrowPermit" : "Permit",
101
+ message: {
102
+ owner: owner,
103
+ spender: spender,
104
+ value: amount.toString(),
105
+ nonce: BigNumber.from(nonce).toHexString(),
106
+ deadline: deadline.toNumber(),
107
+ }
108
+ });
109
+
110
+ this.getImpermaxRouter().web3.currentProvider.send(
111
+ {
112
+ method: "eth_signTypedData_v4",
113
+ params: [owner, data],
114
+ from: owner
115
+ },
116
+ (err: any, data: any) => {
117
+ if (err) {
118
+ console.error(err);
119
+ return callBack(null);
120
+ }
121
+ const signature = data.result.substring(2);
122
+ const r = "0x" + signature.substring(0, 64);
123
+ const s = "0x" + signature.substring(64, 128);
124
+ let v = parseInt(signature.substring(128, 130), 16);
125
+ if (v == 0 || v == 1) v = v + 27;
126
+ //console.log(v, r, s);
127
+ const permitData: string = ethers.utils.defaultAbiCoder.encode(
128
+ ['bool', 'uint8', 'bytes32', 'bytes32'],
129
+ [false, v, r, s]
130
+ );
131
+ callBack({permitData, deadline, amount});
132
+ }
133
+ );
134
+ }
135
+
136
+ async deposit(amount: BigNumber, permitData: PermitData, onTransactionHash: Function) {
137
+ const router = this.getRouterContract();
138
+ const poolToken = await this.getPoolToken().getPoolToken();
139
+ const data = permitData ? permitData.permitData : '0x';
140
+ const deadline = permitData ? permitData.deadline : DEADLINE;
141
+ const account = this.accountPoolToken.getAccount();
142
+ if (await this.isWETH()) {
143
+ return this.send(router.methods.mintETH(poolToken._address, account, deadline), onTransactionHash, amount);
144
+ } else if (this.isCollateral()) {
145
+ return this.send(router.methods.mintCollateral(poolToken._address, amount, account, deadline, data), onTransactionHash);
146
+ } else {
147
+ return this.send(router.methods.mint(poolToken._address, amount, account, deadline), onTransactionHash);
148
+ }
149
+ }
150
+
151
+ async withdraw(tokens: BigNumber, permitData: PermitData, onTransactionHash: Function) {
152
+ const router = this.getRouterContract();
153
+ const poolToken = await this.getPoolToken().getPoolToken();
154
+ const data = permitData ? permitData.permitData : '0x';
155
+ const deadline = permitData ? permitData.deadline : DEADLINE;
156
+ const account = this.accountPoolToken.getAccount();
157
+ if (await this.isWETH()) {
158
+ return this.send(router.methods.redeemETH(poolToken._address, tokens, account, deadline, data), onTransactionHash);
159
+ } else {
160
+ return this.send(router.methods.redeem(poolToken._address, tokens, account, deadline, data), onTransactionHash);
161
+ }
162
+ }
163
+
164
+ async borrow(amount: BigNumber, permitData: PermitData, onTransactionHash: Function) {
165
+ const router = this.getRouterContract();
166
+ const borrowable = await this.getPoolToken().getPoolToken();
167
+ const data = permitData ? permitData.permitData : '0x';
168
+ const deadline = permitData ? permitData.deadline : DEADLINE;
169
+ const account = this.accountPoolToken.getAccount();
170
+ if (await this.isWETH()) {
171
+ return this.send(router.methods.borrowETH(borrowable._address, amount, account, deadline, data), onTransactionHash);
172
+ } else {
173
+ return this.send(router.methods.borrow(borrowable._address, amount, account, deadline, data), onTransactionHash);
174
+ }
175
+ }
176
+
177
+ async repay(amount: BigNumber, onTransactionHash: Function) {
178
+ const router = this.getRouterContract();
179
+ const borrowable = await this.getPoolToken().getPoolToken();
180
+ const account = this.accountPoolToken.getAccount();
181
+ if (await this.isWETH()) {
182
+ return this.send(router.methods.repayETH(borrowable._address, account, DEADLINE), onTransactionHash, amount);
183
+ } else {
184
+ return this.send(router.methods.repay(borrowable._address, amount, account, DEADLINE), onTransactionHash);
185
+ }
186
+ }
187
+ }