aiia-vault-sdk 1.0.1
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.
- package/SeedRoundFundraiser.ts +742 -0
- package/TradingVault.ts +863 -0
- package/abis/SeedRoundFundraiser.json +1519 -0
- package/abis/TradingVault.json +1647 -0
- package/common.ts +131 -0
- package/contracts/SeedRoundFundraiser.ts +1670 -0
- package/contracts/TradingVault.ts +1752 -0
- package/contracts/common.ts +131 -0
- package/contracts/factories/SeedRoundFundraiser__factory.ts +1495 -0
- package/contracts/factories/index.ts +4 -0
- package/contracts/index.ts +6 -0
- package/contracts.json +28 -0
- package/dist/SeedRoundFundraiser.d.ts +130 -0
- package/dist/SeedRoundFundraiser.js +445 -0
- package/dist/TradingVault.d.ts +175 -0
- package/dist/TradingVault.js +521 -0
- package/dist/abis/SeedRoundFundraiser.json +1519 -0
- package/dist/abis/TradingVault.json +1647 -0
- package/dist/common.d.ts +50 -0
- package/dist/common.js +2 -0
- package/dist/contracts/SeedRoundFundraiser.d.ts +936 -0
- package/dist/contracts/SeedRoundFundraiser.js +2 -0
- package/dist/contracts/TradingVault.d.ts +930 -0
- package/dist/contracts/TradingVault.js +2 -0
- package/dist/contracts.json +28 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +19 -0
- package/dist/types.d.ts +291 -0
- package/dist/types.js +2 -0
- package/dist/utils.d.ts +95 -0
- package/dist/utils.js +370 -0
- package/dist/whitelist-tokens.json +14 -0
- package/index.ts +3 -0
- package/package.json +21 -0
- package/temp/aiia-vault-sdk-1.0.0.tgz +0 -0
- package/tsconfig.json +15 -0
- package/types.ts +301 -0
- package/utils.ts +576 -0
- package/whitelist-tokens.json +14 -0
@@ -0,0 +1,175 @@
|
|
1
|
+
import { ethers } from "ethers";
|
2
|
+
import { TradingVault } from "./contracts/TradingVault";
|
3
|
+
import { AnyEvent, AnyEventRaw } from "./types";
|
4
|
+
import { type SendTransactionMutateAsync } from "@wagmi/core/query";
|
5
|
+
import { Config } from "@wagmi/core/dist/types/createConfig";
|
6
|
+
export declare class TradingVaultSDK {
|
7
|
+
name: string;
|
8
|
+
private contract;
|
9
|
+
private providers;
|
10
|
+
private _currency;
|
11
|
+
private _rewardToken;
|
12
|
+
private _currencyDecimals;
|
13
|
+
private _rewardTokenDecimals;
|
14
|
+
private priceDecimals;
|
15
|
+
private contractAddress;
|
16
|
+
private isBootstrapped;
|
17
|
+
private configs;
|
18
|
+
private BASE_WEIGHT;
|
19
|
+
private BASE_PRICE;
|
20
|
+
constructor(rpcUrls: string | string[], contractAddress?: string);
|
21
|
+
private getRandomProvider;
|
22
|
+
private getContractWithRandomProvider;
|
23
|
+
bootstrap(): Promise<void>;
|
24
|
+
signAndSendTransaction(tx: ethers.ContractTransaction, wallet: ethers.Wallet | SendTransactionMutateAsync<Config, any>, callbacks?: {
|
25
|
+
onSubmit?: (tx: string) => void | Promise<void>;
|
26
|
+
onFinally?: (status: {
|
27
|
+
status: boolean | null;
|
28
|
+
confirmations: number;
|
29
|
+
txHash: string;
|
30
|
+
isCompleted: boolean;
|
31
|
+
attempts: number;
|
32
|
+
}) => void | Promise<void>;
|
33
|
+
onError?: (error: Error) => void | Promise<void>;
|
34
|
+
}): Promise<{
|
35
|
+
transaction: {
|
36
|
+
hash: string;
|
37
|
+
};
|
38
|
+
status: {
|
39
|
+
status: boolean | null;
|
40
|
+
confirmations: number;
|
41
|
+
isCompleted: boolean;
|
42
|
+
attempts: number;
|
43
|
+
};
|
44
|
+
}>;
|
45
|
+
buildCreatePositionTx(amount: number): Promise<ethers.ContractTransaction>;
|
46
|
+
buildCreatePositionForUserTx(user: string, amount: number): Promise<ethers.ContractTransaction>;
|
47
|
+
buildReducePositionTx(tokenId: bigint, amount: number): Promise<ethers.ContractTransaction>;
|
48
|
+
buildReducePositionsTx(tokenIds: bigint[], amounts: number[]): Promise<ethers.ContractTransaction>;
|
49
|
+
buildBorrowCurrencyTx(amount: number): Promise<ethers.ContractTransaction>;
|
50
|
+
buildRepayCurrencyTx(amount: number): Promise<ethers.ContractTransaction>;
|
51
|
+
buildSetPriceTx(newPrice: number, rewardAmount: number): Promise<ethers.ContractTransaction>;
|
52
|
+
buildClaimERC20Tx(token: string, amount: number): Promise<ethers.ContractTransaction>;
|
53
|
+
buildCreatePositionTxRaw(amount: bigint): Promise<ethers.ContractTransaction>;
|
54
|
+
buildCreatePositionForUserTxRaw(user: string, amount: bigint): Promise<ethers.ContractTransaction>;
|
55
|
+
buildReducePositionTxRaw(tokenId: bigint, amount: bigint): Promise<ethers.ContractTransaction>;
|
56
|
+
buildReducePositionsTxRaw(tokenIds: bigint[], amounts: bigint[]): Promise<ethers.ContractTransaction>;
|
57
|
+
buildBorrowCurrencyTxRaw(amount: bigint): Promise<ethers.ContractTransaction>;
|
58
|
+
buildRepayCurrencyTxRaw(amount: bigint): Promise<ethers.ContractTransaction>;
|
59
|
+
buildSetPriceTxRaw(newPrice: bigint, rewardAmount: bigint): Promise<ethers.ContractTransaction>;
|
60
|
+
buildSetCurrencyTxRaw(currency: string): Promise<ethers.ContractTransaction>;
|
61
|
+
buildSetRewardTokenTxRaw(rewardToken: string): Promise<ethers.ContractTransaction>;
|
62
|
+
buildSetTreasuryTxRaw(treasury: string): Promise<ethers.ContractTransaction>;
|
63
|
+
buildUpdateRewardConfigsTxRaw(configs: TradingVault.RewardConfigStruct[]): Promise<ethers.ContractTransaction>;
|
64
|
+
buildSetReduceEnabledTxRaw(enabled: boolean): Promise<ethers.ContractTransaction>;
|
65
|
+
buildClaimERC20TxRaw(token: string, amount: bigint): Promise<ethers.ContractTransaction>;
|
66
|
+
buildApproveERC20Tx(tokenAddress: string, spender: string, amount: number): Promise<ethers.ContractTransaction>;
|
67
|
+
buildApproveERC20TxRaw(tokenAddress: string, spender: string, amount: bigint): Promise<ethers.ContractTransaction>;
|
68
|
+
getAllowanceRaw(tokenAddress: string, owner: string, spender: string): Promise<bigint>;
|
69
|
+
getAllowance(tokenAddress: string, owner: string, spender: string): Promise<number>;
|
70
|
+
buildGrantOperatorRoleTxRaw(operator: string): Promise<ethers.ContractTransaction>;
|
71
|
+
getPrice(): Promise<number>;
|
72
|
+
getPriceRaw(): Promise<bigint>;
|
73
|
+
getCurrency(): Promise<string>;
|
74
|
+
getRewardToken(): Promise<string>;
|
75
|
+
getTreasury(): Promise<string>;
|
76
|
+
getTotalAmount(): Promise<number>;
|
77
|
+
getTotalAmountRaw(): Promise<bigint>;
|
78
|
+
getTotalBorrowed(): Promise<number>;
|
79
|
+
getTotalBorrowedRaw(): Promise<bigint>;
|
80
|
+
isReduceEnabled(): Promise<boolean>;
|
81
|
+
getPosition(tokenId: bigint): Promise<{
|
82
|
+
remainingAmount: number;
|
83
|
+
entryPrice: number;
|
84
|
+
outPrice: number;
|
85
|
+
openedAt: number;
|
86
|
+
closedAt: number;
|
87
|
+
rewardedAmount: number;
|
88
|
+
lossAmount: number;
|
89
|
+
initAmount: number;
|
90
|
+
}>;
|
91
|
+
getPositionRaw(tokenId: bigint): Promise<[bigint, bigint, bigint, bigint, bigint, bigint, bigint, bigint] & {
|
92
|
+
entryPrice: bigint;
|
93
|
+
outPrice: bigint;
|
94
|
+
remainingAmount: bigint;
|
95
|
+
initAmount: bigint;
|
96
|
+
openedAt: bigint;
|
97
|
+
closedAt: bigint;
|
98
|
+
rewardedAmount: bigint;
|
99
|
+
lossAmount: bigint;
|
100
|
+
}>;
|
101
|
+
getRewardConfig(index: number): Promise<[bigint, bigint] & {
|
102
|
+
weight: bigint;
|
103
|
+
duration: bigint;
|
104
|
+
}>;
|
105
|
+
getRewardConfigsLength(): Promise<bigint>;
|
106
|
+
getCurrencyDecimals(): Promise<number>;
|
107
|
+
getRewardTokenDecimals(): Promise<number>;
|
108
|
+
getContractAddress(): string;
|
109
|
+
getConfigs(): Array<{
|
110
|
+
weight: number;
|
111
|
+
duration: number;
|
112
|
+
}>;
|
113
|
+
getAllEvents(fromBlock: number, toBlock: number): Promise<AnyEventRaw[]>;
|
114
|
+
streamEvents(fromBlock: number, onEvent: (event: AnyEvent) => Promise<void>, saveLatestBlock: (blockNumber: number) => Promise<void>, batchSize?: number, sleepTime?: number): Promise<void>;
|
115
|
+
formatEventArgs: (event: AnyEventRaw) => AnyEvent;
|
116
|
+
estimateUnrealizedPnl({ price, entryPrice, initAmount, remainingAmount, }: {
|
117
|
+
price: number;
|
118
|
+
entryPrice: number;
|
119
|
+
initAmount: number;
|
120
|
+
remainingAmount: number;
|
121
|
+
}): {
|
122
|
+
pnl: number;
|
123
|
+
pnlPercentage: number;
|
124
|
+
};
|
125
|
+
estReducePosition({ amount, price, entryPrice, openedAt, configs, }: {
|
126
|
+
amount: number;
|
127
|
+
price: number;
|
128
|
+
entryPrice: number;
|
129
|
+
openedAt: number;
|
130
|
+
configs: Array<{
|
131
|
+
weight: number;
|
132
|
+
duration: number;
|
133
|
+
}>;
|
134
|
+
}): {
|
135
|
+
amount: number;
|
136
|
+
totalReward: number;
|
137
|
+
userReward: number;
|
138
|
+
treasuryReward: number;
|
139
|
+
weight: number;
|
140
|
+
};
|
141
|
+
estReducePositions({ positions, price, configs, }: {
|
142
|
+
positions: Array<{
|
143
|
+
amount: number;
|
144
|
+
entryPrice: number;
|
145
|
+
openedAt: number;
|
146
|
+
}>;
|
147
|
+
price: number;
|
148
|
+
configs: Array<{
|
149
|
+
weight: number;
|
150
|
+
duration: number;
|
151
|
+
}>;
|
152
|
+
}): {
|
153
|
+
amount: number;
|
154
|
+
totalReward: number;
|
155
|
+
userReward: number;
|
156
|
+
treasuryReward: number;
|
157
|
+
};
|
158
|
+
private getRewardWeight;
|
159
|
+
estimateUnrealizedPnls({ price, positions, }: {
|
160
|
+
price: number;
|
161
|
+
positions: Array<{
|
162
|
+
entryPrice: number;
|
163
|
+
initAmount: number;
|
164
|
+
remainingAmount: number;
|
165
|
+
rewardedAmount: number;
|
166
|
+
lossAmount: number;
|
167
|
+
}>;
|
168
|
+
}): {
|
169
|
+
totalInitAmount: number;
|
170
|
+
totalRemainingAmount: number;
|
171
|
+
totalRewardedAmount: number;
|
172
|
+
totalLossAmount: number;
|
173
|
+
totalPnl: number;
|
174
|
+
};
|
175
|
+
}
|
@@ -0,0 +1,521 @@
|
|
1
|
+
"use strict";
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
4
|
+
};
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
6
|
+
exports.TradingVaultSDK = void 0;
|
7
|
+
const ethers_1 = require("ethers");
|
8
|
+
const TradingVault_json_1 = __importDefault(require("./abis/TradingVault.json"));
|
9
|
+
const contracts_json_1 = __importDefault(require("./contracts.json"));
|
10
|
+
const utils_1 = require("./utils");
|
11
|
+
class TradingVaultSDK {
|
12
|
+
constructor(rpcUrls, contractAddress) {
|
13
|
+
this.name = "TradingVault";
|
14
|
+
this._currency = null;
|
15
|
+
this._rewardToken = null;
|
16
|
+
this._currencyDecimals = null;
|
17
|
+
this._rewardTokenDecimals = null;
|
18
|
+
this.priceDecimals = 6;
|
19
|
+
this.isBootstrapped = false;
|
20
|
+
this.configs = [];
|
21
|
+
this.BASE_WEIGHT = 10000;
|
22
|
+
this.BASE_PRICE = 100;
|
23
|
+
this.formatEventArgs = (event) => {
|
24
|
+
const currencyDecimals = this._currencyDecimals;
|
25
|
+
const rewardTokenDecimals = this._rewardTokenDecimals;
|
26
|
+
const { eventName, args } = event;
|
27
|
+
switch (eventName) {
|
28
|
+
case "PositionCreated":
|
29
|
+
return {
|
30
|
+
...event,
|
31
|
+
args: {
|
32
|
+
...args,
|
33
|
+
user: args.user.toLowerCase(),
|
34
|
+
amount: Number(args.amount) / Math.pow(10, currencyDecimals),
|
35
|
+
entryPrice: Number(args.entryPrice) / Math.pow(10, this.priceDecimals),
|
36
|
+
tokenId: Number(args.tokenId),
|
37
|
+
openedAt: Number(args.openedAt),
|
38
|
+
},
|
39
|
+
};
|
40
|
+
case "PositionReduced":
|
41
|
+
return {
|
42
|
+
...event,
|
43
|
+
args: {
|
44
|
+
...args,
|
45
|
+
user: args.user.toLowerCase(),
|
46
|
+
reducedAmount: Number(args.reducedAmount) / Math.pow(10, currencyDecimals),
|
47
|
+
remainingAmount: Number(args.remainingAmount) / Math.pow(10, currencyDecimals),
|
48
|
+
totalReward: Number(args.totalReward) / Math.pow(10, rewardTokenDecimals),
|
49
|
+
userReward: Number(args.userReward) / Math.pow(10, rewardTokenDecimals),
|
50
|
+
treasuryReward: Number(args.treasuryReward) / Math.pow(10, rewardTokenDecimals),
|
51
|
+
rewardedAmount: Number(args.rewardedAmount) / Math.pow(10, rewardTokenDecimals),
|
52
|
+
weight: Number(args.weight),
|
53
|
+
tokenId: Number(args.tokenId),
|
54
|
+
lossAmount: Number(args.lossAmount) / Math.pow(10, currencyDecimals),
|
55
|
+
price: Number(args.price) / Math.pow(10, this.priceDecimals),
|
56
|
+
loss: Number(args.loss) / Math.pow(10, currencyDecimals),
|
57
|
+
},
|
58
|
+
};
|
59
|
+
case "CurrencyBorrowed":
|
60
|
+
case "CurrencyRepaid":
|
61
|
+
return {
|
62
|
+
...event,
|
63
|
+
args: {
|
64
|
+
...args,
|
65
|
+
amount: Number(args.amount) / Math.pow(10, currencyDecimals),
|
66
|
+
borrower: args.borrower.toLowerCase(),
|
67
|
+
},
|
68
|
+
};
|
69
|
+
case "PriceUpdated":
|
70
|
+
return {
|
71
|
+
...event,
|
72
|
+
args: {
|
73
|
+
...args,
|
74
|
+
oldPrice: Number(args.oldPrice) / Math.pow(10, this.priceDecimals),
|
75
|
+
newPrice: Number(args.newPrice) / Math.pow(10, this.priceDecimals),
|
76
|
+
requiredReward: Number(args.requiredReward) / Math.pow(10, rewardTokenDecimals),
|
77
|
+
},
|
78
|
+
};
|
79
|
+
case "TotalAmountUpdated":
|
80
|
+
return {
|
81
|
+
...event,
|
82
|
+
args: {
|
83
|
+
...args,
|
84
|
+
newTotalAmount: Number(args.newTotalAmount) / Math.pow(10, currencyDecimals),
|
85
|
+
},
|
86
|
+
};
|
87
|
+
case "CurrencyUpdated":
|
88
|
+
return {
|
89
|
+
...event,
|
90
|
+
args: {
|
91
|
+
...args,
|
92
|
+
oldCurrency: args.oldCurrency.toLowerCase(),
|
93
|
+
newCurrency: args.newCurrency.toLowerCase(),
|
94
|
+
},
|
95
|
+
};
|
96
|
+
case "RewardTokenUpdated":
|
97
|
+
return {
|
98
|
+
...event,
|
99
|
+
args: {
|
100
|
+
...args,
|
101
|
+
oldRewardToken: args.oldRewardToken.toLowerCase(),
|
102
|
+
newRewardToken: args.newRewardToken.toLowerCase(),
|
103
|
+
},
|
104
|
+
};
|
105
|
+
case "ReduceEnabledUpdated":
|
106
|
+
return {
|
107
|
+
...event,
|
108
|
+
args: {
|
109
|
+
...args,
|
110
|
+
enabled: args.enabled,
|
111
|
+
},
|
112
|
+
};
|
113
|
+
case "TreasuryUpdated":
|
114
|
+
return {
|
115
|
+
...event,
|
116
|
+
args: {
|
117
|
+
...args,
|
118
|
+
oldTreasury: args.oldTreasury.toLowerCase(),
|
119
|
+
newTreasury: args.newTreasury.toLowerCase(),
|
120
|
+
},
|
121
|
+
};
|
122
|
+
case "RewardConfigsUpdated":
|
123
|
+
return {
|
124
|
+
...event,
|
125
|
+
args: {
|
126
|
+
...args,
|
127
|
+
},
|
128
|
+
};
|
129
|
+
case "TotalRewardsUpdated": {
|
130
|
+
return {
|
131
|
+
...event,
|
132
|
+
args: {
|
133
|
+
...args,
|
134
|
+
oldAmount: Number(args.oldAmount) / Math.pow(10, rewardTokenDecimals),
|
135
|
+
newAmount: Number(args.newAmount) / Math.pow(10, rewardTokenDecimals),
|
136
|
+
},
|
137
|
+
};
|
138
|
+
}
|
139
|
+
case "TotalRewardsHarvestedUpdated": {
|
140
|
+
return {
|
141
|
+
...event,
|
142
|
+
args: {
|
143
|
+
...args,
|
144
|
+
oldAmount: Number(args.oldAmount) / Math.pow(10, rewardTokenDecimals),
|
145
|
+
newAmount: Number(args.newAmount) / Math.pow(10, rewardTokenDecimals),
|
146
|
+
},
|
147
|
+
};
|
148
|
+
}
|
149
|
+
default:
|
150
|
+
return event; // Return unformatted args for unknown events
|
151
|
+
}
|
152
|
+
};
|
153
|
+
// Convert single RPC to array if needed
|
154
|
+
const rpcArray = Array.isArray(rpcUrls) ? rpcUrls : [rpcUrls];
|
155
|
+
// Create providers for each RPC
|
156
|
+
this.providers = rpcArray.map((rpc) => new ethers_1.ethers.JsonRpcProvider(rpc));
|
157
|
+
// Get a random provider for initial setup
|
158
|
+
const initialProvider = (0, utils_1.getRandomProvider)(this.providers);
|
159
|
+
// Determine contract address based on RPC URL if not provided
|
160
|
+
this.contractAddress = (0, utils_1.resolveContractAddress)(rpcArray[0], this.name, contracts_json_1.default, contractAddress);
|
161
|
+
// Initialize contract with initial provider
|
162
|
+
this.contract = new ethers_1.ethers.Contract(this.contractAddress, TradingVault_json_1.default.abi, initialProvider);
|
163
|
+
}
|
164
|
+
getRandomProvider() {
|
165
|
+
return (0, utils_1.getRandomProvider)(this.providers);
|
166
|
+
}
|
167
|
+
getContractWithRandomProvider() {
|
168
|
+
return new ethers_1.ethers.Contract(this.contractAddress, TradingVault_json_1.default.abi, this.getRandomProvider());
|
169
|
+
}
|
170
|
+
async bootstrap() {
|
171
|
+
if (this.isBootstrapped) {
|
172
|
+
return;
|
173
|
+
}
|
174
|
+
// Check health of all RPCs and remove inactive ones
|
175
|
+
const healthChecks = await Promise.all(this.providers.map((provider, index) => (0, utils_1.checkRpcHealth)(provider, index)));
|
176
|
+
// Filter out inactive providers
|
177
|
+
this.providers = this.providers.filter((_, index) => healthChecks[index]);
|
178
|
+
if (this.providers.length === 0) {
|
179
|
+
throw new Error("No active RPC providers available");
|
180
|
+
}
|
181
|
+
await Promise.all([
|
182
|
+
this.getCurrencyDecimals(),
|
183
|
+
this.getRewardTokenDecimals(),
|
184
|
+
(async () => {
|
185
|
+
const configLength = await this.getRewardConfigsLength();
|
186
|
+
const configPromises = [];
|
187
|
+
for (let i = 0; i < configLength; i++) {
|
188
|
+
configPromises.push(this.getRewardConfig(i));
|
189
|
+
}
|
190
|
+
const configs = await Promise.all(configPromises);
|
191
|
+
this.configs = configs.map((config) => ({
|
192
|
+
weight: Number(config.weight) / this.BASE_WEIGHT,
|
193
|
+
duration: Number(config.duration),
|
194
|
+
}));
|
195
|
+
})(),
|
196
|
+
]);
|
197
|
+
this.isBootstrapped = true;
|
198
|
+
}
|
199
|
+
async signAndSendTransaction(tx, wallet, callbacks = {}) {
|
200
|
+
return (0, utils_1.signAndSendTransaction)(tx, wallet, () => this.getRandomProvider(), callbacks);
|
201
|
+
}
|
202
|
+
// Transaction builders
|
203
|
+
async buildCreatePositionTx(amount) {
|
204
|
+
const decimals = await this.getCurrencyDecimals();
|
205
|
+
const amountBigInt = BigInt(Math.floor(amount * Math.pow(10, decimals)));
|
206
|
+
return this.buildCreatePositionTxRaw(amountBigInt);
|
207
|
+
}
|
208
|
+
async buildCreatePositionForUserTx(user, amount) {
|
209
|
+
const decimals = await this.getCurrencyDecimals();
|
210
|
+
const amountBigInt = BigInt(Math.floor(amount * Math.pow(10, decimals)));
|
211
|
+
return this.buildCreatePositionForUserTxRaw(user, amountBigInt);
|
212
|
+
}
|
213
|
+
async buildReducePositionTx(tokenId, amount) {
|
214
|
+
const decimals = await this.getCurrencyDecimals();
|
215
|
+
const amountBigInt = BigInt(Math.floor(amount * Math.pow(10, decimals)));
|
216
|
+
return this.buildReducePositionTxRaw(tokenId, amountBigInt);
|
217
|
+
}
|
218
|
+
async buildReducePositionsTx(tokenIds, amounts) {
|
219
|
+
const decimals = await this.getCurrencyDecimals();
|
220
|
+
const amountsBigInt = amounts.map((amount) => BigInt(Math.floor(amount * Math.pow(10, decimals))));
|
221
|
+
return this.buildReducePositionsTxRaw(tokenIds, amountsBigInt);
|
222
|
+
}
|
223
|
+
async buildBorrowCurrencyTx(amount) {
|
224
|
+
const decimals = await this.getCurrencyDecimals();
|
225
|
+
const amountBigInt = BigInt(Math.floor(amount * Math.pow(10, decimals)));
|
226
|
+
return this.buildBorrowCurrencyTxRaw(amountBigInt);
|
227
|
+
}
|
228
|
+
async buildRepayCurrencyTx(amount) {
|
229
|
+
const decimals = await this.getCurrencyDecimals();
|
230
|
+
const amountBigInt = BigInt(Math.floor(amount * Math.pow(10, decimals)));
|
231
|
+
return this.buildRepayCurrencyTxRaw(amountBigInt);
|
232
|
+
}
|
233
|
+
async buildSetPriceTx(newPrice, rewardAmount) {
|
234
|
+
const decimals = this.priceDecimals;
|
235
|
+
const rewardDecimals = await this.getRewardTokenDecimals();
|
236
|
+
const priceBigInt = BigInt(Math.floor(newPrice * Math.pow(10, decimals)));
|
237
|
+
const rewardAmountBigInt = BigInt(Math.floor(rewardAmount * Math.pow(10, rewardDecimals)));
|
238
|
+
return this.buildSetPriceTxRaw(priceBigInt, rewardAmountBigInt);
|
239
|
+
}
|
240
|
+
async buildClaimERC20Tx(token, amount) {
|
241
|
+
const tokenContract = new ethers_1.ethers.Contract(token, ["function decimals() view returns (uint8)"], this.getRandomProvider());
|
242
|
+
const decimals = await tokenContract.decimals();
|
243
|
+
const amountBigInt = BigInt(Math.floor(amount * Math.pow(10, decimals)));
|
244
|
+
return this.buildClaimERC20TxRaw(token, amountBigInt);
|
245
|
+
}
|
246
|
+
async buildCreatePositionTxRaw(amount) {
|
247
|
+
const tx = await this.contract.createPosition.populateTransaction(amount);
|
248
|
+
return tx;
|
249
|
+
}
|
250
|
+
async buildCreatePositionForUserTxRaw(user, amount) {
|
251
|
+
const tx = await this.contract.createPositionForUser.populateTransaction(user, amount);
|
252
|
+
return tx;
|
253
|
+
}
|
254
|
+
async buildReducePositionTxRaw(tokenId, amount) {
|
255
|
+
const tx = await this.contract.reducePosition.populateTransaction(tokenId, amount);
|
256
|
+
return tx;
|
257
|
+
}
|
258
|
+
async buildReducePositionsTxRaw(tokenIds, amounts) {
|
259
|
+
const tx = await this.contract.reducePositions.populateTransaction(tokenIds, amounts);
|
260
|
+
return tx;
|
261
|
+
}
|
262
|
+
async buildBorrowCurrencyTxRaw(amount) {
|
263
|
+
const tx = await this.contract.borrowCurrency.populateTransaction(amount);
|
264
|
+
return tx;
|
265
|
+
}
|
266
|
+
async buildRepayCurrencyTxRaw(amount) {
|
267
|
+
const tx = await this.contract.repayCurrency.populateTransaction(amount);
|
268
|
+
return tx;
|
269
|
+
}
|
270
|
+
async buildSetPriceTxRaw(newPrice, rewardAmount) {
|
271
|
+
const tx = await this.contract.setPrice.populateTransaction(newPrice, rewardAmount);
|
272
|
+
return tx;
|
273
|
+
}
|
274
|
+
async buildSetCurrencyTxRaw(currency) {
|
275
|
+
this._currency = null; // Reset cache when currency is about to change
|
276
|
+
const tx = await this.contract.setCurrency.populateTransaction(currency);
|
277
|
+
return tx;
|
278
|
+
}
|
279
|
+
async buildSetRewardTokenTxRaw(rewardToken) {
|
280
|
+
this._rewardToken = null; // Reset cache when reward token is about to change
|
281
|
+
const tx = await this.contract.setRewardToken.populateTransaction(rewardToken);
|
282
|
+
return tx;
|
283
|
+
}
|
284
|
+
async buildSetTreasuryTxRaw(treasury) {
|
285
|
+
const tx = await this.contract.setTreasury.populateTransaction(treasury);
|
286
|
+
return tx;
|
287
|
+
}
|
288
|
+
async buildUpdateRewardConfigsTxRaw(configs) {
|
289
|
+
const tx = await this.contract.updateRewardConfigs.populateTransaction(configs);
|
290
|
+
return tx;
|
291
|
+
}
|
292
|
+
async buildSetReduceEnabledTxRaw(enabled) {
|
293
|
+
const tx = await this.contract.setReduceEnabled.populateTransaction(enabled);
|
294
|
+
return tx;
|
295
|
+
}
|
296
|
+
async buildClaimERC20TxRaw(token, amount) {
|
297
|
+
const tx = await this.contract.claimERC20.populateTransaction(token, amount);
|
298
|
+
return tx;
|
299
|
+
}
|
300
|
+
async buildApproveERC20Tx(tokenAddress, spender, amount) {
|
301
|
+
const tokenContract = new ethers_1.ethers.Contract(tokenAddress, ["function decimals() view returns (uint8)"], this.getRandomProvider());
|
302
|
+
const decimals = await tokenContract.decimals();
|
303
|
+
const amountBigInt = BigInt(Math.floor(amount * Math.pow(10, Number(decimals))));
|
304
|
+
return this.buildApproveERC20TxRaw(tokenAddress, spender, amountBigInt);
|
305
|
+
}
|
306
|
+
async buildApproveERC20TxRaw(tokenAddress, spender, amount) {
|
307
|
+
return await (0, utils_1.buildApproveERC20Tx)(tokenAddress, spender, amount, this.getRandomProvider());
|
308
|
+
}
|
309
|
+
async getAllowanceRaw(tokenAddress, owner, spender) {
|
310
|
+
return await (0, utils_1.getTokenAllowance)(tokenAddress, owner, spender, this.getRandomProvider());
|
311
|
+
}
|
312
|
+
async getAllowance(tokenAddress, owner, spender) {
|
313
|
+
const [allowanceRaw, decimals] = await Promise.all([
|
314
|
+
this.getAllowanceRaw(tokenAddress, owner, spender),
|
315
|
+
(0, utils_1.getTokenDecimals)(tokenAddress, this.getRandomProvider()),
|
316
|
+
]);
|
317
|
+
return Number(allowanceRaw) / Math.pow(10, decimals);
|
318
|
+
}
|
319
|
+
async buildGrantOperatorRoleTxRaw(operator) {
|
320
|
+
const tx = await this.contract.grantOperatorRole.populateTransaction(operator);
|
321
|
+
return tx;
|
322
|
+
}
|
323
|
+
// Read methods
|
324
|
+
async getPrice() {
|
325
|
+
const priceRaw = await this.getPriceRaw();
|
326
|
+
const decimals = this.priceDecimals;
|
327
|
+
return Number(priceRaw) / Math.pow(10, decimals);
|
328
|
+
}
|
329
|
+
async getPriceRaw() {
|
330
|
+
return await this.contract.price();
|
331
|
+
}
|
332
|
+
async getCurrency() {
|
333
|
+
if (!this._currency) {
|
334
|
+
this._currency = await this.contract.currency();
|
335
|
+
}
|
336
|
+
return this._currency;
|
337
|
+
}
|
338
|
+
async getRewardToken() {
|
339
|
+
if (!this._rewardToken) {
|
340
|
+
this._rewardToken = await this.contract.rewardToken();
|
341
|
+
}
|
342
|
+
return this._rewardToken;
|
343
|
+
}
|
344
|
+
async getTreasury() {
|
345
|
+
return await this.contract.treasury();
|
346
|
+
}
|
347
|
+
async getTotalAmount() {
|
348
|
+
const totalAmountRaw = await this.getTotalAmountRaw();
|
349
|
+
const decimals = await this.getCurrencyDecimals();
|
350
|
+
return Number(totalAmountRaw) / Math.pow(10, decimals);
|
351
|
+
}
|
352
|
+
async getTotalAmountRaw() {
|
353
|
+
return await this.contract.totalAmount();
|
354
|
+
}
|
355
|
+
async getTotalBorrowed() {
|
356
|
+
const totalBorrowedRaw = await this.getTotalBorrowedRaw();
|
357
|
+
const decimals = await this.getCurrencyDecimals();
|
358
|
+
return Number(totalBorrowedRaw) / Math.pow(10, decimals);
|
359
|
+
}
|
360
|
+
async getTotalBorrowedRaw() {
|
361
|
+
return await this.contract.totalBorrowed();
|
362
|
+
}
|
363
|
+
async isReduceEnabled() {
|
364
|
+
return await this.contract.isReduceEnabled();
|
365
|
+
}
|
366
|
+
async getPosition(tokenId) {
|
367
|
+
const positionRaw = await this.getPositionRaw(tokenId);
|
368
|
+
const currencyDecimals = await this.getCurrencyDecimals();
|
369
|
+
const rewardTokenDecimals = await this.getRewardTokenDecimals();
|
370
|
+
const priceDecimals = this.priceDecimals;
|
371
|
+
return {
|
372
|
+
remainingAmount: Number(positionRaw.remainingAmount) / Math.pow(10, currencyDecimals),
|
373
|
+
entryPrice: Number(positionRaw.entryPrice) / Math.pow(10, priceDecimals),
|
374
|
+
outPrice: Number(positionRaw.outPrice) / Math.pow(10, priceDecimals),
|
375
|
+
openedAt: Number(positionRaw.openedAt),
|
376
|
+
closedAt: Number(positionRaw.closedAt),
|
377
|
+
rewardedAmount: Number(positionRaw.rewardedAmount) / Math.pow(10, rewardTokenDecimals),
|
378
|
+
lossAmount: Number(positionRaw.lossAmount) / Math.pow(10, currencyDecimals),
|
379
|
+
initAmount: Number(positionRaw.initAmount) / Math.pow(10, currencyDecimals),
|
380
|
+
};
|
381
|
+
}
|
382
|
+
async getPositionRaw(tokenId) {
|
383
|
+
return await this.contract.positions(tokenId);
|
384
|
+
}
|
385
|
+
async getRewardConfig(index) {
|
386
|
+
return await this.contract.rewardConfigs(index);
|
387
|
+
}
|
388
|
+
async getRewardConfigsLength() {
|
389
|
+
return await this.contract.getRewardConfigsLength();
|
390
|
+
}
|
391
|
+
async getCurrencyDecimals() {
|
392
|
+
if (this._currencyDecimals === null) {
|
393
|
+
const currency = await this.getCurrency();
|
394
|
+
const currencyContract = new ethers_1.ethers.Contract(currency, ["function decimals() view returns (uint8)"], this.getRandomProvider());
|
395
|
+
this._currencyDecimals = Number(await currencyContract.decimals());
|
396
|
+
}
|
397
|
+
return this._currencyDecimals;
|
398
|
+
}
|
399
|
+
async getRewardTokenDecimals() {
|
400
|
+
if (this._rewardTokenDecimals === null) {
|
401
|
+
const rewardToken = await this.getRewardToken();
|
402
|
+
const rewardTokenContract = new ethers_1.ethers.Contract(rewardToken, ["function decimals() view returns (uint8)"], this.getRandomProvider());
|
403
|
+
this._rewardTokenDecimals = Number(await rewardTokenContract.decimals());
|
404
|
+
}
|
405
|
+
return this._rewardTokenDecimals;
|
406
|
+
}
|
407
|
+
getContractAddress() {
|
408
|
+
return this.contractAddress;
|
409
|
+
}
|
410
|
+
getConfigs() {
|
411
|
+
return [...this.configs];
|
412
|
+
}
|
413
|
+
async getAllEvents(fromBlock, toBlock) {
|
414
|
+
await this.bootstrap();
|
415
|
+
return (0, utils_1.getAllEvents)(this.contract, () => this.getRandomProvider(), () => this.getContractWithRandomProvider(), fromBlock, toBlock);
|
416
|
+
}
|
417
|
+
async streamEvents(fromBlock, onEvent, saveLatestBlock, batchSize = 1000, sleepTime = 5000) {
|
418
|
+
await this.bootstrap();
|
419
|
+
return (0, utils_1.streamEvents)({
|
420
|
+
getProvider: () => this.getRandomProvider(),
|
421
|
+
getAllEvents: (fromBlock, toBlock) => this.getAllEvents(fromBlock, toBlock),
|
422
|
+
formatEvent: (event) => this.formatEventArgs(event),
|
423
|
+
onEvent,
|
424
|
+
saveLatestBlock,
|
425
|
+
fromBlock,
|
426
|
+
batchSize,
|
427
|
+
sleepTime,
|
428
|
+
});
|
429
|
+
}
|
430
|
+
estimateUnrealizedPnl({ price, entryPrice, initAmount, remainingAmount, }) {
|
431
|
+
// Calculate PNL using the formula: amount * (price - entryPrice) / BASE_PRICE + rewardedAmount - lossAmount
|
432
|
+
const pnl = (remainingAmount * (price - entryPrice)) / this.BASE_PRICE;
|
433
|
+
// Calculate PNL percentage relative to the initial amount
|
434
|
+
const pnlPercentage = (pnl / initAmount) * 100;
|
435
|
+
return {
|
436
|
+
pnl,
|
437
|
+
pnlPercentage,
|
438
|
+
};
|
439
|
+
}
|
440
|
+
estReducePosition({ amount, price, entryPrice, openedAt, configs = [], }) {
|
441
|
+
const BASE_PRICE = this.BASE_PRICE;
|
442
|
+
const BASE_WEIGHT = this.BASE_WEIGHT;
|
443
|
+
let returnAmount = amount;
|
444
|
+
let totalReward = 0;
|
445
|
+
let userReward = 0;
|
446
|
+
let treasuryReward = 0;
|
447
|
+
let weight = 0;
|
448
|
+
// If price is less than entry price, user is at a loss
|
449
|
+
if (price < entryPrice) {
|
450
|
+
// Calculate loss amount
|
451
|
+
const priceDiff = entryPrice - price;
|
452
|
+
const loss = (amount * priceDiff) / 100;
|
453
|
+
returnAmount = amount - loss;
|
454
|
+
// No rewards when at a loss
|
455
|
+
return {
|
456
|
+
amount: returnAmount,
|
457
|
+
totalReward: 0,
|
458
|
+
userReward: 0,
|
459
|
+
treasuryReward: 0,
|
460
|
+
weight: 0,
|
461
|
+
};
|
462
|
+
}
|
463
|
+
// Calculate rewards if price is higher than entry price
|
464
|
+
if (price >= entryPrice) {
|
465
|
+
totalReward = (amount * (price - entryPrice)) / BASE_PRICE;
|
466
|
+
// Get weight based on duration
|
467
|
+
const duration = Math.floor(Date.now() / 1000) - openedAt;
|
468
|
+
weight = this.getRewardWeight(duration, configs);
|
469
|
+
// Calculate user and treasury rewards based on weight
|
470
|
+
userReward = totalReward * weight;
|
471
|
+
treasuryReward = totalReward - userReward;
|
472
|
+
}
|
473
|
+
return {
|
474
|
+
amount: returnAmount,
|
475
|
+
totalReward,
|
476
|
+
userReward,
|
477
|
+
treasuryReward,
|
478
|
+
weight,
|
479
|
+
};
|
480
|
+
}
|
481
|
+
estReducePositions({ positions, price, configs = [], }) {
|
482
|
+
const results = positions.map((position) => this.estReducePosition({
|
483
|
+
amount: position.amount,
|
484
|
+
price,
|
485
|
+
entryPrice: position.entryPrice,
|
486
|
+
openedAt: position.openedAt,
|
487
|
+
configs,
|
488
|
+
}));
|
489
|
+
return results.reduce((acc, curr) => ({
|
490
|
+
amount: acc.amount + curr.amount,
|
491
|
+
totalReward: acc.totalReward + curr.totalReward,
|
492
|
+
userReward: acc.userReward + curr.userReward,
|
493
|
+
treasuryReward: acc.treasuryReward + curr.treasuryReward,
|
494
|
+
}), { amount: 0, totalReward: 0, userReward: 0, treasuryReward: 0 });
|
495
|
+
}
|
496
|
+
getRewardWeight(duration, configs) {
|
497
|
+
return (0, utils_1.getRewardWeight)(duration, configs);
|
498
|
+
}
|
499
|
+
estimateUnrealizedPnls({ price, positions, }) {
|
500
|
+
return positions.reduce((acc, position) => {
|
501
|
+
const { pnl } = this.estimateUnrealizedPnl({
|
502
|
+
price,
|
503
|
+
...position,
|
504
|
+
});
|
505
|
+
return {
|
506
|
+
totalInitAmount: acc.totalInitAmount + position.initAmount,
|
507
|
+
totalRemainingAmount: acc.totalRemainingAmount + position.remainingAmount,
|
508
|
+
totalRewardedAmount: acc.totalRewardedAmount + position.rewardedAmount,
|
509
|
+
totalLossAmount: acc.totalLossAmount + position.lossAmount,
|
510
|
+
totalPnl: acc.totalPnl + pnl,
|
511
|
+
};
|
512
|
+
}, {
|
513
|
+
totalInitAmount: 0,
|
514
|
+
totalRemainingAmount: 0,
|
515
|
+
totalRewardedAmount: 0,
|
516
|
+
totalLossAmount: 0,
|
517
|
+
totalPnl: 0,
|
518
|
+
});
|
519
|
+
}
|
520
|
+
}
|
521
|
+
exports.TradingVaultSDK = TradingVaultSDK;
|