@strkfarm/sdk 1.0.54 → 1.0.56
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/dist/cli.js +0 -0
- package/dist/cli.mjs +0 -0
- package/dist/index.browser.global.js +65626 -44556
- package/dist/index.browser.mjs +18205 -8761
- package/dist/index.d.ts +344 -10
- package/dist/index.js +18985 -9368
- package/dist/index.mjs +18279 -8672
- package/package.json +3 -2
- package/src/data/sensei.abi.json +1759 -0
- package/src/data/universal-vault.abi.json +1565 -0
- package/src/data/vault-manager.abi.json +634 -0
- package/src/data/vesu-singleton.abi.json +2247 -0
- package/src/dataTypes/address.ts +4 -0
- package/src/global.ts +30 -0
- package/src/interfaces/common.tsx +22 -2
- package/src/modules/pricer.ts +1 -1
- package/src/node/deployer.ts +219 -0
- package/src/node/index.ts +2 -1
- package/src/strategies/base-strategy.ts +27 -0
- package/src/strategies/index.ts +3 -0
- package/src/strategies/sensei.ts +333 -0
- package/src/strategies/universal-adapters/adapter-utils.ts +13 -0
- package/src/strategies/universal-adapters/baseAdapter.ts +40 -0
- package/src/strategies/universal-adapters/common-adapter.ts +96 -0
- package/src/strategies/universal-adapters/index.ts +3 -0
- package/src/strategies/universal-adapters/vesu-adapter.ts +274 -0
- package/src/strategies/universal-strategy.ts +543 -0
- package/src/utils/index.ts +5 -0
- package/src/utils/oz-merkle.ts +100 -0
package/src/dataTypes/address.ts
CHANGED
package/src/global.ts
CHANGED
|
@@ -62,6 +62,16 @@ const defaultTokens: TokenInfo[] = [{
|
|
|
62
62
|
decimals: 8,
|
|
63
63
|
coingeckId: undefined,
|
|
64
64
|
displayDecimals: 6,
|
|
65
|
+
priceCheckAmount: 0.0001, // 112000 * 0.0001 = $11.2
|
|
66
|
+
}, {
|
|
67
|
+
name: 'tBTC',
|
|
68
|
+
symbol: 'tBTC',
|
|
69
|
+
logo: 'https://assets.strkfarm.com/integrations/tokens/tbtc.svg',
|
|
70
|
+
address: ContractAddr.from('0x4daa17763b286d1e59b97c283c0b8c949994c361e426a28f743c67bdfe9a32f'),
|
|
71
|
+
decimals: 18,
|
|
72
|
+
coingeckId: undefined,
|
|
73
|
+
displayDecimals: 6,
|
|
74
|
+
priceCheckAmount: 0.0001, // 112000 * 0.0001 = $11.2
|
|
65
75
|
}]
|
|
66
76
|
const tokens: TokenInfo[] = defaultTokens;
|
|
67
77
|
|
|
@@ -69,6 +79,8 @@ const tokens: TokenInfo[] = defaultTokens;
|
|
|
69
79
|
* - fatalError: Things to do when a fatal error occurs
|
|
70
80
|
*/
|
|
71
81
|
export class Global {
|
|
82
|
+
static cache: Record<string, {value: any, ttl: number, timestamp: number}> = {};
|
|
83
|
+
|
|
72
84
|
static fatalError(message: string, err?: Error) {
|
|
73
85
|
logger.error(message);
|
|
74
86
|
console.error(message, err);
|
|
@@ -149,4 +161,22 @@ export class Global {
|
|
|
149
161
|
}
|
|
150
162
|
return token;
|
|
151
163
|
}
|
|
164
|
+
|
|
165
|
+
static setGlobalCache(key: string, data: any, ttl: number = 60000) {
|
|
166
|
+
Global.cache[key] = {
|
|
167
|
+
value: data,
|
|
168
|
+
ttl,
|
|
169
|
+
timestamp: Date.now()
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
static getGlobalCache<T>(key: string): T | null {
|
|
174
|
+
const cached = Global.cache[key];
|
|
175
|
+
if (!cached) return null;
|
|
176
|
+
if (Date.now() - cached.timestamp > cached.ttl) {
|
|
177
|
+
delete Global.cache[key];
|
|
178
|
+
return null;
|
|
179
|
+
}
|
|
180
|
+
return cached.value;
|
|
181
|
+
}
|
|
152
182
|
}
|
|
@@ -14,7 +14,8 @@ export enum RiskType {
|
|
|
14
14
|
SMART_CONTRACT_RISK = "Smart Contract Risk",
|
|
15
15
|
ORACLE_RISK = "Oracle Risk",
|
|
16
16
|
TECHNICAL_RISK = "Technical Risk",
|
|
17
|
-
COUNTERPARTY_RISK = "Counterparty Risk" // e.g. bad debt
|
|
17
|
+
COUNTERPARTY_RISK = "Counterparty Risk", // e.g. bad debt
|
|
18
|
+
DEPEG_RISK = "Depeg Risk" // e.g. USDC depeg
|
|
18
19
|
}
|
|
19
20
|
|
|
20
21
|
export interface RiskFactor {
|
|
@@ -32,6 +33,7 @@ export interface TokenInfo {
|
|
|
32
33
|
logo: string;
|
|
33
34
|
coingeckId?: string;
|
|
34
35
|
displayDecimals: number;
|
|
36
|
+
priceCheckAmount?: number; // for tokens like BTC, doing 1BTC price check may not be ideal, esp on illiquid netwrks like sn
|
|
35
37
|
}
|
|
36
38
|
|
|
37
39
|
export enum Network {
|
|
@@ -104,7 +106,7 @@ export interface IInvestmentFlow {
|
|
|
104
106
|
}
|
|
105
107
|
|
|
106
108
|
export function getMainnetConfig(
|
|
107
|
-
rpcUrl =
|
|
109
|
+
rpcUrl: string = 'https://starknet-mainnet.public.blastapi.io',
|
|
108
110
|
blockIdentifier: BlockIdentifier = "pending"
|
|
109
111
|
): IConfig {
|
|
110
112
|
return {
|
|
@@ -135,6 +137,8 @@ export const getRiskExplaination = (riskType: RiskType) => {
|
|
|
135
137
|
return "The risk of technical issues e.g. backend failure.";
|
|
136
138
|
case RiskType.COUNTERPARTY_RISK:
|
|
137
139
|
return "The risk of the counterparty defaulting e.g. bad debt on lending platforms.";
|
|
140
|
+
case RiskType.DEPEG_RISK:
|
|
141
|
+
return "The risk of a token losing its peg to the underlying asset, leading to potential losses for holders.";
|
|
138
142
|
}
|
|
139
143
|
};
|
|
140
144
|
|
|
@@ -197,3 +201,19 @@ export function highlightTextWithLinks(
|
|
|
197
201
|
</>
|
|
198
202
|
);
|
|
199
203
|
}
|
|
204
|
+
|
|
205
|
+
export interface VaultPosition {
|
|
206
|
+
amount: Web3Number,
|
|
207
|
+
usdValue: number,
|
|
208
|
+
token: TokenInfo,
|
|
209
|
+
remarks: string
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const VesuProtocol: IProtocol = {
|
|
213
|
+
name: "Vesu",
|
|
214
|
+
logo: "https://static-assets-8zct.onrender.com/integrations/vesu/logo.png"
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
export const Protocols = {
|
|
218
|
+
VESU: VesuProtocol,
|
|
219
|
+
}
|
package/src/modules/pricer.ts
CHANGED
|
@@ -149,7 +149,7 @@ export class Pricer extends PricerBase {
|
|
|
149
149
|
}
|
|
150
150
|
case 'Ekubo':
|
|
151
151
|
try {
|
|
152
|
-
const result = await this._getPriceEkubo(token);
|
|
152
|
+
const result = await this._getPriceEkubo(token, new Web3Number(token.priceCheckAmount ? token.priceCheckAmount : 1, token.decimals));
|
|
153
153
|
this.methodToUse[token.symbol] = 'Ekubo';
|
|
154
154
|
return result;
|
|
155
155
|
} catch (error: any) {
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
import assert from 'assert'
|
|
2
|
+
import {Account, Call, RawArgs, RpcProvider, TransactionExecutionStatus, constants, extractContractHashes, hash, json, num, provider, transaction} from 'starknet'
|
|
3
|
+
import { readFileSync, existsSync, writeFileSync } from 'fs'
|
|
4
|
+
import { IConfig } from '../interfaces';
|
|
5
|
+
import { Store, getDefaultStoreConfig } from '../utils/store';
|
|
6
|
+
import { add } from 'winston';
|
|
7
|
+
|
|
8
|
+
function getContracts() {
|
|
9
|
+
const PATH = './contracts.json'
|
|
10
|
+
if (existsSync(PATH)) {
|
|
11
|
+
return JSON.parse(readFileSync(PATH, {encoding: 'utf-8'}))
|
|
12
|
+
}
|
|
13
|
+
return {}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function saveContracts(contracts: any) {
|
|
17
|
+
const PATH = './contracts.json'
|
|
18
|
+
writeFileSync(PATH, JSON.stringify(contracts));
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function getAccount(
|
|
22
|
+
accountKey: string,
|
|
23
|
+
config: IConfig,
|
|
24
|
+
password = process.env.ACCOUNT_SECURE_PASSWORD,
|
|
25
|
+
accountsFileName = process.env.ACCOUNTS_FILE_NAME || getDefaultStoreConfig(config.network).ACCOUNTS_FILE_NAME,
|
|
26
|
+
secretFileFolder = process.env.SECRET_FILE_FOLDER || getDefaultStoreConfig(config.network).SECRET_FILE_FOLDER
|
|
27
|
+
) {
|
|
28
|
+
const storeConfig = getDefaultStoreConfig(config.network);
|
|
29
|
+
storeConfig.ACCOUNTS_FILE_NAME = accountsFileName;
|
|
30
|
+
storeConfig.SECRET_FILE_FOLDER = secretFileFolder;
|
|
31
|
+
if (!password) {
|
|
32
|
+
throw new Error(`getAccount: Password is required (either in env as ACCOUNT_SECURE_PASSWORD or input to function)`);
|
|
33
|
+
}
|
|
34
|
+
const store = new Store(config, {
|
|
35
|
+
...storeConfig,
|
|
36
|
+
PASSWORD: password
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
return store.getAccount(accountKey);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async function myDeclare(contract_name: string, package_name: string = 'strkfarm', config: IConfig, acc: Account) {
|
|
43
|
+
const provider = config.provider;
|
|
44
|
+
const compiledSierra = json.parse(
|
|
45
|
+
readFileSync(`./target/release/${package_name}_${contract_name}.contract_class.json`).toString("ascii")
|
|
46
|
+
)
|
|
47
|
+
const compiledCasm = json.parse(
|
|
48
|
+
readFileSync(`./target/release/${package_name}_${contract_name}.compiled_contract_class.json`).toString("ascii")
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
const contracts = getContracts();
|
|
52
|
+
const payload = {
|
|
53
|
+
contract: compiledSierra,
|
|
54
|
+
casm: compiledCasm
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const result = extractContractHashes(payload);
|
|
58
|
+
console.log("classhash:", result.classHash);
|
|
59
|
+
|
|
60
|
+
try {
|
|
61
|
+
const cls = await provider.getClassByHash(result.classHash);
|
|
62
|
+
console.log(`Class ${result.classHash} already declared`);
|
|
63
|
+
return {
|
|
64
|
+
transaction_hash: '',
|
|
65
|
+
class_hash: result.classHash
|
|
66
|
+
}
|
|
67
|
+
} catch (err) {}
|
|
68
|
+
|
|
69
|
+
const fee = await acc.estimateDeclareFee({
|
|
70
|
+
contract: compiledSierra,
|
|
71
|
+
casm: compiledCasm,
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
const tx = await acc.declareIfNot(payload)
|
|
75
|
+
console.log(`Declaring: ${contract_name}, tx:`, tx.transaction_hash);
|
|
76
|
+
await provider.waitForTransaction(tx.transaction_hash, {
|
|
77
|
+
successStates: [TransactionExecutionStatus.SUCCEEDED]
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
if (!contracts.class_hashes) {
|
|
81
|
+
contracts['class_hashes'] = {};
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Todo attach cairo and scarb version. and commit ID
|
|
85
|
+
contracts.class_hashes[contract_name] = tx.class_hash;
|
|
86
|
+
saveContracts(contracts);
|
|
87
|
+
console.log(`Contract declared: ${contract_name}`)
|
|
88
|
+
console.log(`Class hash: ${tx.class_hash}`)
|
|
89
|
+
return tx;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
async function deployContract(contract_name: string, classHash: string, constructorData: RawArgs, config: IConfig, acc: Account) {
|
|
93
|
+
const provider = config.provider;
|
|
94
|
+
|
|
95
|
+
const fee = await acc.estimateDeployFee({
|
|
96
|
+
classHash,
|
|
97
|
+
constructorCalldata: constructorData,
|
|
98
|
+
})
|
|
99
|
+
console.log("Deploy fee", contract_name, Number(fee.suggestedMaxFee) / 10 ** 18, 'ETH')
|
|
100
|
+
|
|
101
|
+
const tx = await acc.deployContract({
|
|
102
|
+
classHash,
|
|
103
|
+
constructorCalldata: constructorData,
|
|
104
|
+
})
|
|
105
|
+
console.log('Deploy tx: ', tx.transaction_hash);
|
|
106
|
+
await provider.waitForTransaction(tx.transaction_hash, {
|
|
107
|
+
successStates: [TransactionExecutionStatus.SUCCEEDED]
|
|
108
|
+
})
|
|
109
|
+
const contracts = getContracts();
|
|
110
|
+
if (!contracts.contracts) {
|
|
111
|
+
contracts['contracts'] = {};
|
|
112
|
+
}
|
|
113
|
+
contracts.contracts[contract_name] = tx.contract_address;
|
|
114
|
+
saveContracts(contracts);
|
|
115
|
+
console.log(`Contract deployed: ${contract_name}`)
|
|
116
|
+
console.log(`Address: ${tx.contract_address}`)
|
|
117
|
+
return tx;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
interface DeployContractResult {
|
|
121
|
+
contract_name: string;
|
|
122
|
+
package_name: string;
|
|
123
|
+
class_hash: string;
|
|
124
|
+
call: Call,
|
|
125
|
+
address: string
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
async function prepareMultiDeployContracts(
|
|
129
|
+
contracts: Array<{ contract_name: string, package_name: string, constructorData: RawArgs }>,
|
|
130
|
+
config: IConfig,
|
|
131
|
+
acc: Account
|
|
132
|
+
) {
|
|
133
|
+
const result: DeployContractResult[] = [];
|
|
134
|
+
|
|
135
|
+
for (const { contract_name, package_name, constructorData } of contracts) {
|
|
136
|
+
const declaredInfo = await myDeclare(contract_name, package_name, config, acc);
|
|
137
|
+
const classHash = declaredInfo.class_hash;
|
|
138
|
+
|
|
139
|
+
const {calls, addresses} = transaction.buildUDCCall({
|
|
140
|
+
classHash,
|
|
141
|
+
constructorCalldata: constructorData,
|
|
142
|
+
}, acc.address);
|
|
143
|
+
|
|
144
|
+
assert(calls.length == 1, `Expected exactly one call, got ${calls.length}`);
|
|
145
|
+
assert(addresses.length == 1, `Expected exactly one address, got ${addresses.length}`);
|
|
146
|
+
|
|
147
|
+
result.push({
|
|
148
|
+
contract_name,
|
|
149
|
+
package_name,
|
|
150
|
+
class_hash: classHash,
|
|
151
|
+
call: calls[0],
|
|
152
|
+
address: addresses[0]
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
return result;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
async function executeDeployCalls(
|
|
160
|
+
contractsInfo: DeployContractResult[],
|
|
161
|
+
acc: Account,
|
|
162
|
+
provider: RpcProvider
|
|
163
|
+
) {
|
|
164
|
+
// all must be UDC
|
|
165
|
+
for (let contractInfo of contractsInfo) {
|
|
166
|
+
assert(num.toHexString(contractInfo.call.contractAddress) == num.toHexString(constants.UDC.ADDRESS), 'Must be pointed at UDC address');
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const allCalls = contractsInfo.map(info => info.call);
|
|
170
|
+
await executeTransactions(allCalls, acc, provider, `Deploying contracts: ${contractsInfo.map(info => info.contract_name).join(', ')}`);
|
|
171
|
+
|
|
172
|
+
// save contracts in storage
|
|
173
|
+
const contracts = getContracts();
|
|
174
|
+
if (!contracts.contracts) {
|
|
175
|
+
contracts['contracts'] = {};
|
|
176
|
+
}
|
|
177
|
+
if (!contracts.class_hashes) {
|
|
178
|
+
contracts['class_hashes'] = {};
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
for (let contractInfo of contractsInfo) {
|
|
182
|
+
// Todo attach cairo and scarb version. and commit ID
|
|
183
|
+
contracts.class_hashes[contractInfo.contract_name] = contractInfo.class_hash;
|
|
184
|
+
contracts.contracts[contractInfo.contract_name] = contractInfo.address;
|
|
185
|
+
console.log(`Contract deployed: ${contractInfo.contract_name}, addr: ${contractInfo.address}`);
|
|
186
|
+
}
|
|
187
|
+
saveContracts(contracts);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
async function executeTransactions(
|
|
191
|
+
calls: Call[],
|
|
192
|
+
acc: Account,
|
|
193
|
+
provider: RpcProvider,
|
|
194
|
+
remarks?: string, // optional string for logging purposes
|
|
195
|
+
) {
|
|
196
|
+
const tx = await acc.execute(calls);
|
|
197
|
+
console.log(`Transaction executed: ${tx.transaction_hash}`);
|
|
198
|
+
if (remarks)
|
|
199
|
+
console.log(`Remarks: ${remarks}`);
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
await provider.waitForTransaction(tx.transaction_hash, {
|
|
203
|
+
successStates: [TransactionExecutionStatus.SUCCEEDED]
|
|
204
|
+
});
|
|
205
|
+
console.log(`Transaction confirmed: ${tx.transaction_hash}`);
|
|
206
|
+
|
|
207
|
+
return tx;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
const Deployer = {
|
|
211
|
+
getAccount,
|
|
212
|
+
myDeclare,
|
|
213
|
+
deployContract,
|
|
214
|
+
prepareMultiDeployContracts,
|
|
215
|
+
executeDeployCalls,
|
|
216
|
+
executeTransactions
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
export default Deployer;
|
package/src/node/index.ts
CHANGED
|
@@ -21,8 +21,14 @@ export interface DualTokenInfo {
|
|
|
21
21
|
token1: SingleTokenInfo
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
+
interface CacheData {
|
|
25
|
+
timestamp: number;
|
|
26
|
+
ttl: number;
|
|
27
|
+
data: any;
|
|
28
|
+
}
|
|
24
29
|
export class BaseStrategy<TVLInfo, ActionInfo> {
|
|
25
30
|
readonly config: IConfig;
|
|
31
|
+
readonly cache: Map<string, CacheData> = new Map();
|
|
26
32
|
|
|
27
33
|
constructor(config: IConfig) {
|
|
28
34
|
this.config = config;
|
|
@@ -43,5 +49,26 @@ export class BaseStrategy<TVLInfo, ActionInfo> {
|
|
|
43
49
|
async withdrawCall(amountInfo: ActionInfo, receiver: ContractAddr, owner: ContractAddr): Promise<Call[]> {
|
|
44
50
|
throw new Error("Not implemented");
|
|
45
51
|
}
|
|
52
|
+
|
|
53
|
+
setCache(key: string, data: any, ttl: number = 60000): void {
|
|
54
|
+
const timestamp = Date.now();
|
|
55
|
+
this.cache.set(key, { timestamp, ttl, data });
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
getCache(key: string): any | null {
|
|
59
|
+
const cachedData = this.cache.get(key);
|
|
60
|
+
if (!cachedData || !this.isCacheValid(key)) {
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
return cachedData.data;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
isCacheValid(key: string): boolean {
|
|
67
|
+
const cachedData = this.cache.get(key);
|
|
68
|
+
if (!cachedData) return false;
|
|
69
|
+
|
|
70
|
+
const { timestamp, ttl } = cachedData;
|
|
71
|
+
return Date.now() - timestamp <= ttl;
|
|
72
|
+
}
|
|
46
73
|
|
|
47
74
|
}
|
package/src/strategies/index.ts
CHANGED