@evaafi/sdk 0.2.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.
- package/README.md +7 -0
- package/dist/api/helpers.d.ts +8 -0
- package/dist/api/helpers.js +33 -0
- package/dist/api/math.d.ts +20 -0
- package/dist/api/math.js +214 -0
- package/dist/api/parser.d.ts +8 -0
- package/dist/api/parser.js +227 -0
- package/dist/api/prices.d.ts +9 -0
- package/dist/api/prices.js +104 -0
- package/dist/constants.d.ts +38 -0
- package/dist/constants.js +42 -0
- package/dist/contracts/JettonWallet.d.ts +7 -0
- package/dist/contracts/JettonWallet.js +20 -0
- package/dist/contracts/MasterContract.d.ts +166 -0
- package/dist/contracts/MasterContract.js +217 -0
- package/dist/contracts/UserContract.d.ts +49 -0
- package/dist/contracts/UserContract.js +99 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +53 -0
- package/dist/types/Common.d.ts +5 -0
- package/dist/types/Common.js +2 -0
- package/dist/types/Master.d.ts +63 -0
- package/dist/types/Master.js +2 -0
- package/dist/types/Redstone.d.ts +15 -0
- package/dist/types/Redstone.js +2 -0
- package/dist/types/User.d.ts +55 -0
- package/dist/types/User.js +8 -0
- package/dist/utils/sha256BigInt.d.ts +1 -0
- package/dist/utils/sha256BigInt.js +13 -0
- package/dist/utils/tonConnectSender.d.ts +4 -0
- package/dist/utils/tonConnectSender.js +37 -0
- package/dist/utils/userJettonWallet.d.ts +2 -0
- package/dist/utils/userJettonWallet.js +37 -0
- package/package.json +38 -0
- package/src/api/helpers.ts +32 -0
- package/src/api/math.ts +252 -0
- package/src/api/parser.ts +277 -0
- package/src/api/prices.ts +127 -0
- package/src/constants.ts +53 -0
- package/src/contracts/JettonWallet.ts +20 -0
- package/src/contracts/MasterContract.ts +387 -0
- package/src/contracts/UserContract.ts +125 -0
- package/src/index.ts +78 -0
- package/src/types/Common.ts +6 -0
- package/src/types/Master.ts +70 -0
- package/src/types/Redstone.ts +15 -0
- package/src/types/User.ts +66 -0
- package/src/utils/sha256BigInt.ts +7 -0
- package/src/utils/tonConnectSender.ts +37 -0
- package/src/utils/userJettonWallet.ts +34 -0
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
import { beginCell, Cell, Dictionary, DictionaryValue, Slice } from '@ton/core';
|
|
2
|
+
import { AssetConfig, AssetData, ExtendedAssetData, MasterData } from '../types/Master';
|
|
3
|
+
import { ASSET_ID, MASTER_CONSTANTS } from '../constants';
|
|
4
|
+
import {
|
|
5
|
+
bigIntMax,
|
|
6
|
+
bigIntMin,
|
|
7
|
+
calculateAssetData,
|
|
8
|
+
calculateLiquidationData,
|
|
9
|
+
calculatePresentValue,
|
|
10
|
+
getAvailableToBorrow,
|
|
11
|
+
presentValue,
|
|
12
|
+
} from './math';
|
|
13
|
+
import { loadMaybeMyRef, loadMyRef } from './helpers';
|
|
14
|
+
import { BalanceType, UserBalance, UserData, UserLiteData } from '../types/User';
|
|
15
|
+
|
|
16
|
+
export function createAssetData(): DictionaryValue<AssetData> {
|
|
17
|
+
return {
|
|
18
|
+
serialize: (src: any, buidler: any) => {
|
|
19
|
+
buidler.storeUint(src.s_rate, 64);
|
|
20
|
+
buidler.storeUint(src.b_rate, 64);
|
|
21
|
+
buidler.storeUint(src.totalSupply, 64);
|
|
22
|
+
buidler.storeUint(src.totalBorrow, 64);
|
|
23
|
+
buidler.storeUint(src.lastAccural, 32);
|
|
24
|
+
buidler.storeUint(src.balance, 64);
|
|
25
|
+
},
|
|
26
|
+
parse: (src: Slice) => {
|
|
27
|
+
const sRate = BigInt(src.loadInt(64));
|
|
28
|
+
const bRate = BigInt(src.loadInt(64));
|
|
29
|
+
const totalSupply = BigInt(src.loadInt(64));
|
|
30
|
+
const totalBorrow = BigInt(src.loadInt(64));
|
|
31
|
+
const lastAccural = BigInt(src.loadInt(32));
|
|
32
|
+
const balance = BigInt(src.loadInt(64));
|
|
33
|
+
return { sRate, bRate, totalSupply, totalBorrow, lastAccural, balance };
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function createAssetConfig(): DictionaryValue<AssetConfig> {
|
|
39
|
+
return {
|
|
40
|
+
serialize: (src: any, builder: any) => {
|
|
41
|
+
builder.storeUint(src.oracle, 256);
|
|
42
|
+
builder.storeUint(src.decimals, 8);
|
|
43
|
+
const refBuild = beginCell();
|
|
44
|
+
refBuild.storeUint(src.collateralFactor, 16);
|
|
45
|
+
refBuild.storeUint(src.liquidationThreshold, 16);
|
|
46
|
+
refBuild.storeUint(src.liquidationPenalty, 16);
|
|
47
|
+
refBuild.storeUint(src.baseBorrowRate, 64);
|
|
48
|
+
refBuild.storeUint(src.borrowRateSlopeLow, 64);
|
|
49
|
+
refBuild.storeUint(src.borrowRateSlopeHigh, 64);
|
|
50
|
+
refBuild.storeUint(src.supplyRateSlopeLow, 64);
|
|
51
|
+
refBuild.storeUint(src.supplyRateSlopeHigh, 64);
|
|
52
|
+
refBuild.storeUint(src.targetUtilization, 64);
|
|
53
|
+
refBuild.storeUint(src.originationFee, 64);
|
|
54
|
+
builder.storeRef(refBuild.endCell());
|
|
55
|
+
},
|
|
56
|
+
parse: (src: Slice) => {
|
|
57
|
+
const oracle = src.loadUintBig(256);
|
|
58
|
+
const decimals = BigInt(src.loadUint(8));
|
|
59
|
+
const ref = src.loadRef().beginParse();
|
|
60
|
+
const collateralFactor = BigInt(ref.loadUint(16));
|
|
61
|
+
const liquidationThreshold = BigInt(ref.loadUint(16));
|
|
62
|
+
const liquidationBonus = BigInt(ref.loadUint(16));
|
|
63
|
+
const baseBorrowRate = BigInt(ref.loadUint(64));
|
|
64
|
+
const borrowRateSlopeLow = BigInt(ref.loadUint(64));
|
|
65
|
+
const borrowRateSlopeHigh = BigInt(ref.loadUint(64));
|
|
66
|
+
const supplyRateSlopeLow = BigInt(ref.loadUint(64));
|
|
67
|
+
const supplyRateSlopeHigh = BigInt(ref.loadUint(64));
|
|
68
|
+
const targetUtilization = BigInt(ref.loadUint(64));
|
|
69
|
+
const originationFee = BigInt(ref.loadUint(64));
|
|
70
|
+
|
|
71
|
+
return {
|
|
72
|
+
oracle,
|
|
73
|
+
decimals,
|
|
74
|
+
collateralFactor,
|
|
75
|
+
liquidationThreshold,
|
|
76
|
+
liquidationBonus,
|
|
77
|
+
baseBorrowRate,
|
|
78
|
+
borrowRateSlopeLow,
|
|
79
|
+
borrowRateSlopeHigh,
|
|
80
|
+
supplyRateSlopeLow,
|
|
81
|
+
supplyRateSlopeHigh,
|
|
82
|
+
targetUtilization,
|
|
83
|
+
originationFee,
|
|
84
|
+
};
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export function parseMasterData(masterDataBOC: string): MasterData {
|
|
90
|
+
const masterSlice = Cell.fromBase64(masterDataBOC).beginParse();
|
|
91
|
+
const meta = masterSlice.loadRef().beginParse().loadStringTail();
|
|
92
|
+
const upgradeConfigParser = masterSlice.loadRef().beginParse();
|
|
93
|
+
|
|
94
|
+
const upgradeConfig = {
|
|
95
|
+
masterCodeVersion: Number(upgradeConfigParser.loadCoins()),
|
|
96
|
+
userCodeVersion: Number(upgradeConfigParser.loadCoins()),
|
|
97
|
+
timeout: upgradeConfigParser.loadUint(32),
|
|
98
|
+
updateTime: upgradeConfigParser.loadUint(64),
|
|
99
|
+
freezeTime: upgradeConfigParser.loadUint(64),
|
|
100
|
+
userCode: loadMyRef(upgradeConfigParser),
|
|
101
|
+
blankCode: loadMyRef(upgradeConfigParser),
|
|
102
|
+
newMasterCode: loadMaybeMyRef(upgradeConfigParser),
|
|
103
|
+
newUserCode: loadMaybeMyRef(upgradeConfigParser),
|
|
104
|
+
};
|
|
105
|
+
upgradeConfigParser.endParse();
|
|
106
|
+
|
|
107
|
+
const masterConfigSlice = masterSlice.loadRef().beginParse();
|
|
108
|
+
|
|
109
|
+
const assetsConfigDict = masterConfigSlice.loadDict(Dictionary.Keys.BigUint(256), createAssetConfig());
|
|
110
|
+
const assetsDataDict = masterSlice.loadDict(Dictionary.Keys.BigUint(256), createAssetData());
|
|
111
|
+
const assetsExtendedData = Dictionary.empty<bigint, ExtendedAssetData>();
|
|
112
|
+
const assetsReserves = Dictionary.empty<bigint, bigint>();
|
|
113
|
+
const apy = {
|
|
114
|
+
supply: Dictionary.empty<bigint, number>(),
|
|
115
|
+
borrow: Dictionary.empty<bigint, number>(),
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
for (const [tokenSymbol, assetID] of Object.entries(ASSET_ID)) {
|
|
119
|
+
const assetData = calculateAssetData(assetsConfigDict, assetsDataDict, assetID);
|
|
120
|
+
assetsExtendedData.set(assetID, assetData);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const masterConfig = {
|
|
124
|
+
ifActive: masterConfigSlice.loadInt(8),
|
|
125
|
+
admin: masterConfigSlice.loadAddress(),
|
|
126
|
+
adminPK: masterConfigSlice.loadBuffer(64),
|
|
127
|
+
tokenKeys: loadMaybeMyRef(masterConfigSlice),
|
|
128
|
+
walletToMaster: loadMaybeMyRef(masterConfigSlice),
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
masterConfigSlice.endParse();
|
|
132
|
+
|
|
133
|
+
for (const [_, assetID] of Object.entries(ASSET_ID)) {
|
|
134
|
+
const assetData = assetsExtendedData.get(assetID) as ExtendedAssetData;
|
|
135
|
+
const totalSupply = calculatePresentValue(assetData.sRate, assetData.totalSupply);
|
|
136
|
+
const totalBorrow = calculatePresentValue(assetData.bRate, assetData.totalBorrow);
|
|
137
|
+
assetsReserves.set(assetID, assetData.balance - totalSupply + totalBorrow);
|
|
138
|
+
|
|
139
|
+
apy.supply.set(assetID, (1 + (Number(assetData.supplyInterest) / 1e12) * 24 * 3600) ** 365 - 1);
|
|
140
|
+
apy.borrow.set(assetID, (1 + (Number(assetData.borrowInterest) / 1e12) * 24 * 3600) ** 365 - 1);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return {
|
|
144
|
+
meta: meta,
|
|
145
|
+
upgradeConfig: upgradeConfig,
|
|
146
|
+
masterConfig: masterConfig,
|
|
147
|
+
assetsConfig: assetsConfigDict,
|
|
148
|
+
assetsData: assetsExtendedData,
|
|
149
|
+
assetsReserves: assetsReserves,
|
|
150
|
+
apy: apy,
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export function parseUserLiteData(
|
|
155
|
+
userDataBOC: string,
|
|
156
|
+
assetsData: Dictionary<bigint, ExtendedAssetData>,
|
|
157
|
+
assetsConfig: Dictionary<bigint, AssetConfig>,
|
|
158
|
+
): UserLiteData {
|
|
159
|
+
const userSlice = Cell.fromBase64(userDataBOC).beginParse();
|
|
160
|
+
|
|
161
|
+
const codeVersion = userSlice.loadCoins();
|
|
162
|
+
const masterAddress = userSlice.loadAddress();
|
|
163
|
+
const userAddress = userSlice.loadAddress();
|
|
164
|
+
const principalsDict = userSlice.loadDict(Dictionary.Keys.BigUint(256), Dictionary.Values.BigInt(64));
|
|
165
|
+
const userState = userSlice.loadInt(64);
|
|
166
|
+
const trackingSupplyIndex = userSlice.loadUintBig(64);
|
|
167
|
+
const trackingBorrowIndex = userSlice.loadUintBig(64);
|
|
168
|
+
const dutchAuctionStart = userSlice.loadUint(32);
|
|
169
|
+
const backupCell = loadMyRef(userSlice);
|
|
170
|
+
userSlice.endParse();
|
|
171
|
+
|
|
172
|
+
const userBalances = Dictionary.empty<bigint, UserBalance>();
|
|
173
|
+
|
|
174
|
+
for (const [_, assetID] of Object.entries(ASSET_ID)) {
|
|
175
|
+
const assetData = assetsData.get(assetID) as ExtendedAssetData;
|
|
176
|
+
const assetConfig = assetsConfig.get(assetID) as AssetConfig;
|
|
177
|
+
const balance = presentValue(assetData.sRate, assetData.bRate, principalsDict.get(assetID) || 0n);
|
|
178
|
+
userBalances.set(assetID, balance);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
return {
|
|
182
|
+
type: 'active',
|
|
183
|
+
codeVersion: Number(codeVersion),
|
|
184
|
+
masterAddress: masterAddress,
|
|
185
|
+
ownerAddress: userAddress,
|
|
186
|
+
principals: principalsDict,
|
|
187
|
+
state: userState,
|
|
188
|
+
balances: userBalances,
|
|
189
|
+
trackingSupplyIndex: trackingSupplyIndex,
|
|
190
|
+
trackingBorrowIndex: trackingBorrowIndex,
|
|
191
|
+
dutchAuctionStart: dutchAuctionStart,
|
|
192
|
+
backupCell: backupCell,
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
export function parseUserData(
|
|
197
|
+
userLiteData: UserLiteData,
|
|
198
|
+
assetsData: Dictionary<bigint, ExtendedAssetData>,
|
|
199
|
+
assetsConfig: Dictionary<bigint, AssetConfig>,
|
|
200
|
+
prices: Dictionary<bigint, bigint>,
|
|
201
|
+
): UserData {
|
|
202
|
+
const withdrawalLimits = Dictionary.empty<bigint, bigint>();
|
|
203
|
+
const borrowLimits = Dictionary.empty<bigint, bigint>();
|
|
204
|
+
|
|
205
|
+
let supplyBalance = 0n;
|
|
206
|
+
let borrowBalance = 0n;
|
|
207
|
+
for (const [_, assetID] of Object.entries(ASSET_ID)) {
|
|
208
|
+
const assetData = assetsData.get(assetID) as ExtendedAssetData;
|
|
209
|
+
const assetConfig = assetsConfig.get(assetID) as AssetConfig;
|
|
210
|
+
const balance = presentValue(assetData.sRate, assetData.bRate, userLiteData.principals.get(assetID) || 0n);
|
|
211
|
+
userLiteData.balances.set(assetID, balance);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
for (const [_, assetID] of Object.entries(ASSET_ID)) {
|
|
215
|
+
const assetConfig = assetsConfig.get(assetID) as AssetConfig;
|
|
216
|
+
const balance = userLiteData.balances.get(assetID) as UserBalance;
|
|
217
|
+
|
|
218
|
+
if (balance.type === BalanceType.supply) {
|
|
219
|
+
supplyBalance += (balance.amount * prices.get(assetID)!) / 10n ** assetConfig.decimals;
|
|
220
|
+
}
|
|
221
|
+
if (balance.type === BalanceType.borrow) {
|
|
222
|
+
borrowBalance += (balance.amount * prices.get(assetID)!) / 10n ** assetConfig.decimals;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
const availableToBorrow = getAvailableToBorrow(assetsConfig, assetsData, userLiteData.principals, prices);
|
|
227
|
+
for (const [_, assetID] of Object.entries(ASSET_ID)) {
|
|
228
|
+
const assetConfig = assetsConfig.get(assetID) as AssetConfig;
|
|
229
|
+
const assetData = assetsData.get(assetID) as ExtendedAssetData;
|
|
230
|
+
const balance = userLiteData.balances.get(assetID) as UserBalance;
|
|
231
|
+
|
|
232
|
+
if (balance.type === BalanceType.supply) {
|
|
233
|
+
withdrawalLimits.set(
|
|
234
|
+
assetID,
|
|
235
|
+
bigIntMax(
|
|
236
|
+
bigIntMin(
|
|
237
|
+
assetData.balance,
|
|
238
|
+
((supplyBalance -
|
|
239
|
+
(borrowBalance * MASTER_CONSTANTS.ASSET_COEFFICIENT_SCALE) / assetConfig.collateralFactor) *
|
|
240
|
+
10n ** assetConfig.decimals) /
|
|
241
|
+
prices.get(assetID)! -
|
|
242
|
+
5n,
|
|
243
|
+
balance.amount,
|
|
244
|
+
),
|
|
245
|
+
0n,
|
|
246
|
+
),
|
|
247
|
+
);
|
|
248
|
+
} else {
|
|
249
|
+
borrowLimits.set(
|
|
250
|
+
assetID,
|
|
251
|
+
bigIntMin((availableToBorrow * 10n ** assetConfig.decimals) / prices.get(assetID)!, assetData.balance),
|
|
252
|
+
);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
const limitUsed = borrowBalance + availableToBorrow;
|
|
257
|
+
const limitUsedPercent =
|
|
258
|
+
limitUsed === 0n
|
|
259
|
+
? 0
|
|
260
|
+
: Number(BigInt(1e9) - (availableToBorrow * BigInt(1e9)) / (borrowBalance + availableToBorrow)) / 1e7;
|
|
261
|
+
|
|
262
|
+
const liquidationData = calculateLiquidationData(assetsConfig, assetsData, userLiteData.principals, prices);
|
|
263
|
+
const healthFactor = 1 - Number(liquidationData.totalDebt) / Number(liquidationData.totalLimit);
|
|
264
|
+
|
|
265
|
+
return {
|
|
266
|
+
...userLiteData,
|
|
267
|
+
withdrawalLimits: withdrawalLimits,
|
|
268
|
+
borrowLimits: borrowLimits,
|
|
269
|
+
supplyBalance: supplyBalance,
|
|
270
|
+
borrowBalance: borrowBalance,
|
|
271
|
+
availableToBorrow: availableToBorrow,
|
|
272
|
+
limitUsedPercent: limitUsedPercent,
|
|
273
|
+
limitUsed: limitUsed,
|
|
274
|
+
liquidationData: liquidationData,
|
|
275
|
+
healthFactor: healthFactor,
|
|
276
|
+
};
|
|
277
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { beginCell, Cell, Dictionary } from '@ton/core';
|
|
2
|
+
import { ethers } from 'ethers';
|
|
3
|
+
import { CoinData } from '../types/Redstone';
|
|
4
|
+
import { ASSET_ID } from '../constants';
|
|
5
|
+
import { PriceData } from '../types/Common';
|
|
6
|
+
|
|
7
|
+
type SerializedPrice = {
|
|
8
|
+
symbol: string;
|
|
9
|
+
value: number;
|
|
10
|
+
timestamp: number;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
type PriceRawData = {
|
|
14
|
+
data: Buffer;
|
|
15
|
+
signature: Buffer;
|
|
16
|
+
dictKey: bigint;
|
|
17
|
+
dictValue: bigint;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
function hexToArrayBuffer(input: any) {
|
|
21
|
+
if (typeof input !== 'string') {
|
|
22
|
+
throw new TypeError('Expected input to be a string');
|
|
23
|
+
}
|
|
24
|
+
if (input.length % 2 !== 0) {
|
|
25
|
+
throw new RangeError('Expected string to be an even number of characters');
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (input.startsWith('0x')) {
|
|
29
|
+
input = input.slice(2);
|
|
30
|
+
}
|
|
31
|
+
const view = new Uint8Array(input.length / 2);
|
|
32
|
+
for (let i = 0; i < input.length; i += 2) {
|
|
33
|
+
view[i / 2] = parseInt(input.substring(i, i + 2), 16);
|
|
34
|
+
}
|
|
35
|
+
return Buffer.from(view.buffer);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function convertStringToBytes32String(str: string) {
|
|
39
|
+
if (str.length > 31) {
|
|
40
|
+
const bytes32StringLength = 32 * 2 + 2; // 32 bytes (each byte uses 2 symbols) + 0x
|
|
41
|
+
if (str.length === bytes32StringLength && str.startsWith('0x')) {
|
|
42
|
+
return str;
|
|
43
|
+
} else {
|
|
44
|
+
return ethers.utils.id(str);
|
|
45
|
+
}
|
|
46
|
+
} else {
|
|
47
|
+
return ethers.utils.formatBytes32String(str);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function getLiteDataBytesString(priceData: SerializedPrice): string {
|
|
52
|
+
let data = priceData.symbol.substr(2) + priceData.value.toString(16).padStart(64, '0');
|
|
53
|
+
|
|
54
|
+
data += Math.ceil(priceData.timestamp / 1000)
|
|
55
|
+
.toString(16)
|
|
56
|
+
.padStart(64, '0');
|
|
57
|
+
return data;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
async function getPrice(symbol: string): Promise<PriceRawData> {
|
|
61
|
+
const res = await fetch(`https://api.redstone.finance/prices?symbol=${symbol}&provider=redstone&limit=1`);
|
|
62
|
+
const data = (await res.json()) as CoinData[];
|
|
63
|
+
const price = data[0];
|
|
64
|
+
|
|
65
|
+
const message = {
|
|
66
|
+
symbol: convertStringToBytes32String(price.symbol),
|
|
67
|
+
value: Math.round(price.value * 10 ** 8),
|
|
68
|
+
timestamp: price.timestamp,
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
let dictKey: bigint;
|
|
72
|
+
const dictValue = BigInt(message.value) * 10n;
|
|
73
|
+
switch (message.symbol) {
|
|
74
|
+
case '0x544f4e0000000000000000000000000000000000000000000000000000000000':
|
|
75
|
+
dictKey = ASSET_ID.TON;
|
|
76
|
+
break;
|
|
77
|
+
case '0x5553445400000000000000000000000000000000000000000000000000000000':
|
|
78
|
+
dictKey = ASSET_ID.jUSDT;
|
|
79
|
+
break;
|
|
80
|
+
case '0x5553444300000000000000000000000000000000000000000000000000000000':
|
|
81
|
+
dictKey = ASSET_ID.jUSDC;
|
|
82
|
+
break;
|
|
83
|
+
default:
|
|
84
|
+
throw new Error('Unknown symbol');
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const signature = hexToArrayBuffer(price.liteEvmSignature);
|
|
88
|
+
|
|
89
|
+
return {
|
|
90
|
+
data: Buffer.from(getLiteDataBytesString(message), 'hex'),
|
|
91
|
+
signature: signature,
|
|
92
|
+
dictKey: dictKey,
|
|
93
|
+
dictValue: dictValue,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export async function getPrices(): Promise<PriceData | undefined> {
|
|
98
|
+
try {
|
|
99
|
+
const symbols = ['TON', 'USDT', 'USDC'];
|
|
100
|
+
const rawPriceData: {
|
|
101
|
+
data: Buffer;
|
|
102
|
+
signature: Buffer;
|
|
103
|
+
}[] = [];
|
|
104
|
+
const priceDict = Dictionary.empty(Dictionary.Keys.BigUint(256), Dictionary.Values.BigUint(64));
|
|
105
|
+
const pricePromises = symbols.map(async (symbol) => {
|
|
106
|
+
const price = await getPrice(symbol);
|
|
107
|
+
priceDict.set(price.dictKey, price.dictValue);
|
|
108
|
+
rawPriceData.push(price);
|
|
109
|
+
});
|
|
110
|
+
await Promise.all(pricePromises);
|
|
111
|
+
|
|
112
|
+
const rawPricesDict = Dictionary.empty<Buffer, Cell>();
|
|
113
|
+
for (const data of rawPriceData) {
|
|
114
|
+
rawPricesDict.set(data.signature, beginCell().storeBuffer(data.data).endCell());
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return {
|
|
118
|
+
dict: priceDict,
|
|
119
|
+
dataCell: beginCell()
|
|
120
|
+
.storeDictDirect(rawPricesDict, Dictionary.Keys.Buffer(65), Dictionary.Values.Cell())
|
|
121
|
+
.endCell(),
|
|
122
|
+
};
|
|
123
|
+
} catch (error) {
|
|
124
|
+
console.error(error);
|
|
125
|
+
return undefined;
|
|
126
|
+
}
|
|
127
|
+
}
|
package/src/constants.ts
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { Address, Cell, toNano } from '@ton/core';
|
|
2
|
+
import { sha256Hash } from './utils/sha256BigInt';
|
|
3
|
+
|
|
4
|
+
export const EVAA_MASTER_MAINNET = Address.parse('EQC8rUZqR_pWV1BylWUlPNBzyiTYVoBEmQkMIQDZXICfnuRr');
|
|
5
|
+
export const MAINNET_VERSION = 2;
|
|
6
|
+
export const EVAA_MASTER_TESTNET = Address.parse('kQBi2jDaq_-Oi62V7u_j_Vr1We8EqC3h0jkhB4Gf4JW741vX');
|
|
7
|
+
export const TESTNET_VERSION = 1;
|
|
8
|
+
|
|
9
|
+
export const ASSET_ID = {
|
|
10
|
+
TON: sha256Hash('TON'),
|
|
11
|
+
jUSDT: sha256Hash('jUSDT'),
|
|
12
|
+
jUSDC: sha256Hash('jUSDC'),
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export const JETTON_MASTER_ADDRESSES = {
|
|
16
|
+
jUSDT_MAINNET: Address.parse('EQBwbF0otxLyA3VrRjjC1q7i3G7LtoEpdyBjZEuNtrhC4drm'),
|
|
17
|
+
jUSDT_TESTNET: Address.parse('kQAGvWIETv29VRXLBL3lugxdLeCZ3r7jcuUvqKeZpbcwiQo0'),
|
|
18
|
+
jUSDC_MAINNET: Address.parse('EQCEHZi-CLX2ghdsNbY35umR1OFODG5ySHrtK6GItMdWv7dS'),
|
|
19
|
+
jUSDC_TESTNET: Address.parse('kQCwj7zrRnBIYUhM7BShqupouNgubrdJUmmA3AAuPH9CK0Kj'),
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export const MASTER_CONSTANTS = {
|
|
23
|
+
FACTOR_SCALE: BigInt(1e12),
|
|
24
|
+
ASSET_COEFFICIENT_SCALE: 10000n,
|
|
25
|
+
ASSET_PRICE_SCALE: BigInt(1e8),
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export const LENDING_CODE = Cell.fromBoc(
|
|
29
|
+
Buffer.from(
|
|
30
|
+
'b5ee9c72c1010e0100fd000d12182a555a6065717691969efd0114ff00f4a413f4bcf2c80b010202c8050202039f740403001ff2f8276a2687d2018fd201800f883b840051d38642c678b64e4400780e58fc10802faf07f80e59fa801e78b096664c02078067c07c100627a7978402014807060007a0ddb0c60201c709080013a0fd007a026900aa90400201200b0a0031b8e1002191960aa00b9e2ca007f4042796d225e8019203f6010201200d0c000bf7c147d2218400b9d10e86981fd201840b07f8138d809797976a2687d2029116382f970fd9178089910374daf81b619fd20182c7883b8701981684100627910eba56001797a6a6ba610fd8200e8768f76a9f6aa00cc2a32a8292878809bef2f1889f883bbcdeb86f01',
|
|
31
|
+
'hex',
|
|
32
|
+
),
|
|
33
|
+
)[0];
|
|
34
|
+
export const JETTON_WALLET_CODE = Cell.fromBase64(
|
|
35
|
+
'te6cckECEQEAAyMAART/APSkE/S88sgLAQIBYgIDAgLMBAUAG6D2BdqJofQB9IH0gahhAgHUBgcCASAICQDDCDHAJJfBOAB0NMDAXGwlRNfA/AM4PpA+kAx+gAxcdch+gAx+gAwc6m0AALTH4IQD4p+pVIgupUxNFnwCeCCEBeNRRlSILqWMUREA/AK4DWCEFlfB7y6k1nwC+BfBIQP8vCAAET6RDBwuvLhTYAIBIAoLAIPUAQa5D2omh9AH0gfSBqGAJpj8EIC8aijKkQXUEIPe7L7wndCVj5cWLpn5j9ABgJ0CgR5CgCfQEsZ4sA54tmZPaqQB8VA9M/+gD6QCHwAe1E0PoA+kD6QNQwUTahUirHBfLiwSjC//LiwlQ0QnBUIBNUFAPIUAT6AljPFgHPFszJIsjLARL0APQAywDJIPkAcHTIywLKB8v/ydAE+kD0BDH6ACDXScIA8uLEd4AYyMsFUAjPFnD6AhfLaxPMgMAgEgDQ4AnoIQF41FGcjLHxnLP1AH+gIizxZQBs8WJfoCUAPPFslQBcwjkXKRceJQCKgToIIJycOAoBS88uLFBMmAQPsAECPIUAT6AljPFgHPFszJ7VQC9ztRND6APpA+kDUMAjTP/oAUVGgBfpA+kBTW8cFVHNtcFQgE1QUA8hQBPoCWM8WAc8WzMkiyMsBEvQA9ADLAMn5AHB0yMsCygfL/8nQUA3HBRyx8uLDCvoAUaihggiYloBmtgihggiYloCgGKEnlxBJEDg3XwTjDSXXCwGAPEADXO1E0PoA+kD6QNQwB9M/+gD6QDBRUaFSSccF8uLBJ8L/8uLCBYIJMS0AoBa88uLDghB73ZfeyMsfFcs/UAP6AiLPFgHPFslxgBjIywUkzxZw+gLLaszJgED7AEATyFAE+gJYzxYBzxbMye1UgAHBSeaAYoYIQc2LQnMjLH1Iwyz9Y+gJQB88WUAfPFslxgBDIywUkzxZQBvoCFctqFMzJcfsAECQQIwB8wwAjwgCwjiGCENUydttwgBDIywVQCM8WUAT6AhbLahLLHxLLP8ly+wCTNWwh4gPIUAT6AljPFgHPFszJ7VSV6u3X',
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
export const OPCODES = {
|
|
39
|
+
SUPPLY: 0x1,
|
|
40
|
+
WITHDRAW: 0x2,
|
|
41
|
+
LIQUIDATE: 0x3,
|
|
42
|
+
JETTON_TRANSFER: 0xf8a7ea5,
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export const FEES = {
|
|
46
|
+
SUPPLY: toNano('0.3'),
|
|
47
|
+
WITHDRAW: toNano('0.5'),
|
|
48
|
+
SUPPLY_JETTON: toNano('0.8'),
|
|
49
|
+
SUPPLY_JETTON_FWD: toNano('0.5'),
|
|
50
|
+
LIQUIDATION: toNano('0.8'),
|
|
51
|
+
LIQUIDATION_JETTON: toNano('1'),
|
|
52
|
+
LIQUIDATION_JETTON_FWD: toNano('0.8'),
|
|
53
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Address, Cell, Contract, ContractProvider, Sender, SendMode } from '@ton/core';
|
|
2
|
+
|
|
3
|
+
export class JettonWallet implements Contract {
|
|
4
|
+
readonly address: Address;
|
|
5
|
+
static createFromAddress(address: Address) {
|
|
6
|
+
return new JettonWallet(address);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
private constructor(address: Address) {
|
|
10
|
+
this.address = address;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
async sendTransfer(provider: ContractProvider, via: Sender, value: bigint, payload: Cell) {
|
|
14
|
+
await provider.internal(via, {
|
|
15
|
+
value,
|
|
16
|
+
sendMode: SendMode.PAY_GAS_SEPARATELY + SendMode.IGNORE_ERRORS,
|
|
17
|
+
body: payload,
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
}
|