moneyos 0.2.0 → 0.3.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 +180 -25
- package/dist/cli/index.js +2160 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/index.cjs +720 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +405 -0
- package/dist/index.d.ts +303 -30
- package/dist/index.js +483 -244
- package/dist/index.js.map +1 -1
- package/package.json +30 -10
- package/dist/cli/index.mjs +0 -565
- package/dist/cli/index.mjs.map +0 -1
- package/dist/index.d.mts +0 -132
- package/dist/index.mjs +0 -424
- package/dist/index.mjs.map +0 -1
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,720 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var src_exports = {};
|
|
22
|
+
__export(src_exports, {
|
|
23
|
+
EOAExecutor: () => EOAExecutor,
|
|
24
|
+
FileKeyStore: () => FileKeyStore,
|
|
25
|
+
LocalAccessAdapter: () => LocalAccessAdapter,
|
|
26
|
+
MoneyOS: () => MoneyOS,
|
|
27
|
+
NATIVE_TOKEN_ADDRESS: () => NATIVE_TOKEN_ADDRESS,
|
|
28
|
+
OdosProvider: () => OdosProvider,
|
|
29
|
+
ViemReadClient: () => ViemReadClient,
|
|
30
|
+
chains: () => chains,
|
|
31
|
+
createMoneyOS: () => createMoneyOS,
|
|
32
|
+
defaultChain: () => defaultChain,
|
|
33
|
+
getChain: () => getChain,
|
|
34
|
+
getToken: () => getToken,
|
|
35
|
+
getTokenAddress: () => getTokenAddress,
|
|
36
|
+
tokens: () => tokens
|
|
37
|
+
});
|
|
38
|
+
module.exports = __toCommonJS(src_exports);
|
|
39
|
+
|
|
40
|
+
// src/core/client.ts
|
|
41
|
+
var import_viem4 = require("viem");
|
|
42
|
+
|
|
43
|
+
// packages/core/dist/index.js
|
|
44
|
+
var NATIVE_TOKEN_ADDRESS = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE";
|
|
45
|
+
var tokens = {
|
|
46
|
+
ETH: {
|
|
47
|
+
symbol: "ETH",
|
|
48
|
+
name: "Ether",
|
|
49
|
+
decimals: 18,
|
|
50
|
+
addresses: {
|
|
51
|
+
42161: NATIVE_TOKEN_ADDRESS,
|
|
52
|
+
1: NATIVE_TOKEN_ADDRESS
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
POL: {
|
|
56
|
+
symbol: "POL",
|
|
57
|
+
name: "POL",
|
|
58
|
+
decimals: 18,
|
|
59
|
+
addresses: {
|
|
60
|
+
137: NATIVE_TOKEN_ADDRESS
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
USDC: {
|
|
64
|
+
symbol: "USDC",
|
|
65
|
+
name: "USD Coin",
|
|
66
|
+
decimals: 6,
|
|
67
|
+
addresses: {
|
|
68
|
+
42161: "0xaf88d065e77c8cC2239327C5EDb3A432268e5831",
|
|
69
|
+
1: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
|
|
70
|
+
137: "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359"
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
USDT: {
|
|
74
|
+
symbol: "USDT",
|
|
75
|
+
name: "Tether USD",
|
|
76
|
+
decimals: 6,
|
|
77
|
+
addresses: {
|
|
78
|
+
42161: "0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9",
|
|
79
|
+
1: "0xdAC17F958D2ee523a2206206994597C13D831ec7",
|
|
80
|
+
137: "0xc2132D05D31c914a87C6611C10748AEb04B58e8F"
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
RYZE: {
|
|
84
|
+
symbol: "RYZE",
|
|
85
|
+
name: "RYZE",
|
|
86
|
+
decimals: 18,
|
|
87
|
+
addresses: {
|
|
88
|
+
42161: "0x7712da72127d5dD213B621497D6E4899d5989e5C"
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
function getToken(symbol) {
|
|
93
|
+
return tokens[symbol.toUpperCase()];
|
|
94
|
+
}
|
|
95
|
+
function getTokenAddress(symbol, chainId) {
|
|
96
|
+
return getToken(symbol)?.addresses[chainId];
|
|
97
|
+
}
|
|
98
|
+
var chains = {
|
|
99
|
+
arbitrum: {
|
|
100
|
+
id: 42161,
|
|
101
|
+
name: "Arbitrum One",
|
|
102
|
+
rpcUrl: "https://arb1.arbitrum.io/rpc",
|
|
103
|
+
nativeCurrency: { name: "Ether", symbol: "ETH", decimals: 18 },
|
|
104
|
+
blockExplorer: "https://arbiscan.io"
|
|
105
|
+
},
|
|
106
|
+
ethereum: {
|
|
107
|
+
id: 1,
|
|
108
|
+
name: "Ethereum",
|
|
109
|
+
rpcUrl: "https://eth.public-rpc.com",
|
|
110
|
+
nativeCurrency: { name: "Ether", symbol: "ETH", decimals: 18 },
|
|
111
|
+
blockExplorer: "https://etherscan.io"
|
|
112
|
+
},
|
|
113
|
+
polygon: {
|
|
114
|
+
id: 137,
|
|
115
|
+
name: "Polygon",
|
|
116
|
+
rpcUrl: "https://polygon-rpc.com",
|
|
117
|
+
nativeCurrency: { name: "POL", symbol: "POL", decimals: 18 },
|
|
118
|
+
blockExplorer: "https://polygonscan.com"
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
var defaultChain = chains.arbitrum;
|
|
122
|
+
function getChain(idOrName) {
|
|
123
|
+
if (typeof idOrName === "number") {
|
|
124
|
+
return Object.values(chains).find((c) => c.id === idOrName);
|
|
125
|
+
}
|
|
126
|
+
return chains[idOrName.toLowerCase()];
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// src/core/eoa.ts
|
|
130
|
+
var import_viem2 = require("viem");
|
|
131
|
+
var import_chains = require("viem/chains");
|
|
132
|
+
|
|
133
|
+
// src/core/signer.ts
|
|
134
|
+
var import_viem = require("viem");
|
|
135
|
+
var import_accounts = require("viem/accounts");
|
|
136
|
+
function privateKeyToManagedAccount(privateKey) {
|
|
137
|
+
return (0, import_accounts.privateKeyToAccount)(privateKey, { nonceManager: import_viem.nonceManager });
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// src/core/eoa.ts
|
|
141
|
+
var viemChainMap = {
|
|
142
|
+
42161: import_chains.arbitrum,
|
|
143
|
+
1: import_chains.mainnet,
|
|
144
|
+
137: import_chains.polygon
|
|
145
|
+
};
|
|
146
|
+
function getViemChain(chainId) {
|
|
147
|
+
return viemChainMap[chainId];
|
|
148
|
+
}
|
|
149
|
+
var ViemReadClient = class {
|
|
150
|
+
clients = /* @__PURE__ */ new Map();
|
|
151
|
+
config;
|
|
152
|
+
constructor(config) {
|
|
153
|
+
this.config = config;
|
|
154
|
+
}
|
|
155
|
+
getClient(chainId) {
|
|
156
|
+
let client = this.clients.get(chainId);
|
|
157
|
+
if (!client) {
|
|
158
|
+
const chain = getViemChain(chainId);
|
|
159
|
+
const chainInfo = getChain(chainId);
|
|
160
|
+
const rpcUrl = chainId === this.config.defaultChainId ? this.config.rpcUrl : void 0;
|
|
161
|
+
client = (0, import_viem2.createPublicClient)({
|
|
162
|
+
chain,
|
|
163
|
+
transport: (0, import_viem2.http)(rpcUrl ?? chainInfo?.rpcUrl)
|
|
164
|
+
});
|
|
165
|
+
this.clients.set(chainId, client);
|
|
166
|
+
}
|
|
167
|
+
return client;
|
|
168
|
+
}
|
|
169
|
+
async getBalance(params) {
|
|
170
|
+
const client = this.getClient(params.chainId);
|
|
171
|
+
return client.getBalance({ address: params.address });
|
|
172
|
+
}
|
|
173
|
+
async readContract(params) {
|
|
174
|
+
const client = this.getClient(params.chainId);
|
|
175
|
+
return client.readContract({
|
|
176
|
+
address: params.address,
|
|
177
|
+
abi: params.abi,
|
|
178
|
+
functionName: params.functionName,
|
|
179
|
+
args: params.args
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
var EOAExecutor = class _EOAExecutor {
|
|
184
|
+
mode = "eoa";
|
|
185
|
+
signer;
|
|
186
|
+
walletClients = /* @__PURE__ */ new Map();
|
|
187
|
+
publicClients = /* @__PURE__ */ new Map();
|
|
188
|
+
config;
|
|
189
|
+
constructor(signer, config) {
|
|
190
|
+
this.signer = signer;
|
|
191
|
+
this.config = config;
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Convenience factory: build an EOAExecutor from a raw private key.
|
|
195
|
+
* Equivalent to `new EOAExecutor(privateKeyToAccount(privateKey), config)`.
|
|
196
|
+
* Kept as a helper so the common "I have a hex key" path stays one line
|
|
197
|
+
* while the constructor itself takes a viem `Account` to accommodate
|
|
198
|
+
* future keystore-backed signers (hardware, KMS, MPC).
|
|
199
|
+
*
|
|
200
|
+
* Attach viem's nonce manager so back-to-back live transactions use a
|
|
201
|
+
* pending-aware nonce source instead of relying on RPC fill behavior.
|
|
202
|
+
*/
|
|
203
|
+
static fromPrivateKey(privateKey, config) {
|
|
204
|
+
return new _EOAExecutor(privateKeyToManagedAccount(privateKey), config);
|
|
205
|
+
}
|
|
206
|
+
getWalletClient(chainId) {
|
|
207
|
+
let client = this.walletClients.get(chainId);
|
|
208
|
+
if (!client) {
|
|
209
|
+
const chain = getViemChain(chainId);
|
|
210
|
+
const chainInfo = getChain(chainId);
|
|
211
|
+
const rpcUrl = chainId === this.config.defaultChainId ? this.config.rpcUrl : void 0;
|
|
212
|
+
client = (0, import_viem2.createWalletClient)({
|
|
213
|
+
account: this.signer,
|
|
214
|
+
chain,
|
|
215
|
+
transport: (0, import_viem2.http)(rpcUrl ?? chainInfo?.rpcUrl)
|
|
216
|
+
});
|
|
217
|
+
this.walletClients.set(chainId, client);
|
|
218
|
+
}
|
|
219
|
+
return client;
|
|
220
|
+
}
|
|
221
|
+
getPublicClient(chainId) {
|
|
222
|
+
let client = this.publicClients.get(chainId);
|
|
223
|
+
if (!client) {
|
|
224
|
+
const chain = getViemChain(chainId);
|
|
225
|
+
const chainInfo = getChain(chainId);
|
|
226
|
+
const rpcUrl = chainId === this.config.defaultChainId ? this.config.rpcUrl : void 0;
|
|
227
|
+
client = (0, import_viem2.createPublicClient)({
|
|
228
|
+
chain,
|
|
229
|
+
transport: (0, import_viem2.http)(rpcUrl ?? chainInfo?.rpcUrl)
|
|
230
|
+
});
|
|
231
|
+
this.publicClients.set(chainId, client);
|
|
232
|
+
}
|
|
233
|
+
return client;
|
|
234
|
+
}
|
|
235
|
+
getAddress() {
|
|
236
|
+
return this.signer.address;
|
|
237
|
+
}
|
|
238
|
+
async send(call) {
|
|
239
|
+
const walletClient = this.getWalletClient(call.chainId);
|
|
240
|
+
const hash = await walletClient.sendTransaction({
|
|
241
|
+
account: walletClient.account,
|
|
242
|
+
to: call.to,
|
|
243
|
+
data: call.data,
|
|
244
|
+
value: call.value ?? 0n,
|
|
245
|
+
chain: walletClient.chain
|
|
246
|
+
});
|
|
247
|
+
const publicClient = this.getPublicClient(call.chainId);
|
|
248
|
+
const receipt = await publicClient.waitForTransactionReceipt({ hash });
|
|
249
|
+
if (receipt.status !== "success") {
|
|
250
|
+
throw new Error(
|
|
251
|
+
`Transaction ${hash} reverted on chain ${call.chainId} (block ${receipt.blockNumber}).`
|
|
252
|
+
);
|
|
253
|
+
}
|
|
254
|
+
return { hash, chainId: call.chainId };
|
|
255
|
+
}
|
|
256
|
+
capabilities() {
|
|
257
|
+
return {
|
|
258
|
+
sponsoredGas: false,
|
|
259
|
+
batching: false,
|
|
260
|
+
simulation: false
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
};
|
|
264
|
+
|
|
265
|
+
// src/tools/swap.ts
|
|
266
|
+
var import_viem3 = require("viem");
|
|
267
|
+
var ERC20_ABI = [
|
|
268
|
+
{
|
|
269
|
+
name: "approve",
|
|
270
|
+
type: "function",
|
|
271
|
+
stateMutability: "nonpayable",
|
|
272
|
+
inputs: [
|
|
273
|
+
{ name: "spender", type: "address" },
|
|
274
|
+
{ name: "amount", type: "uint256" }
|
|
275
|
+
],
|
|
276
|
+
outputs: [{ name: "", type: "bool" }]
|
|
277
|
+
},
|
|
278
|
+
{
|
|
279
|
+
name: "allowance",
|
|
280
|
+
type: "function",
|
|
281
|
+
stateMutability: "view",
|
|
282
|
+
inputs: [
|
|
283
|
+
{ name: "owner", type: "address" },
|
|
284
|
+
{ name: "spender", type: "address" }
|
|
285
|
+
],
|
|
286
|
+
outputs: [{ name: "", type: "uint256" }]
|
|
287
|
+
}
|
|
288
|
+
];
|
|
289
|
+
async function executeSwap(input, ctx) {
|
|
290
|
+
const { tokenIn, tokenOut, amount, provider, chainId, slippage } = input;
|
|
291
|
+
const { read, execute, assets } = ctx;
|
|
292
|
+
const sender = execute.getAddress();
|
|
293
|
+
const tokenInAddress = assets.getTokenAddress(tokenIn, chainId);
|
|
294
|
+
const tokenOutAddress = assets.getTokenAddress(tokenOut, chainId);
|
|
295
|
+
if (!tokenInAddress) {
|
|
296
|
+
throw new Error(`Token ${tokenIn} not found on chain ${chainId}`);
|
|
297
|
+
}
|
|
298
|
+
if (!tokenOutAddress) {
|
|
299
|
+
throw new Error(`Token ${tokenOut} not found on chain ${chainId}`);
|
|
300
|
+
}
|
|
301
|
+
const tokenInInfo = assets.getToken(tokenIn);
|
|
302
|
+
const amountWei = (0, import_viem3.parseUnits)(amount, tokenInInfo.decimals);
|
|
303
|
+
const quote = await provider.getQuote({
|
|
304
|
+
chainId,
|
|
305
|
+
tokenIn: tokenInAddress,
|
|
306
|
+
tokenOut: tokenOutAddress,
|
|
307
|
+
amount: amountWei,
|
|
308
|
+
sender,
|
|
309
|
+
slippage
|
|
310
|
+
});
|
|
311
|
+
const calldata = await provider.getCalldata(quote);
|
|
312
|
+
const isNativeIn = tokenInAddress === assets.nativeTokenAddress;
|
|
313
|
+
if (!isNativeIn) {
|
|
314
|
+
const currentAllowance = await read.readContract({
|
|
315
|
+
address: tokenInAddress,
|
|
316
|
+
abi: ERC20_ABI,
|
|
317
|
+
functionName: "allowance",
|
|
318
|
+
args: [sender, calldata.to],
|
|
319
|
+
chainId
|
|
320
|
+
});
|
|
321
|
+
if (currentAllowance < amountWei) {
|
|
322
|
+
const approveData = (0, import_viem3.encodeFunctionData)({
|
|
323
|
+
abi: ERC20_ABI,
|
|
324
|
+
functionName: "approve",
|
|
325
|
+
args: [calldata.to, amountWei]
|
|
326
|
+
});
|
|
327
|
+
await execute.send({ to: tokenInAddress, data: approveData, chainId });
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
const result = await execute.send({
|
|
331
|
+
to: calldata.to,
|
|
332
|
+
data: calldata.data,
|
|
333
|
+
value: isNativeIn ? amountWei : calldata.value,
|
|
334
|
+
chainId
|
|
335
|
+
});
|
|
336
|
+
const tokenOutInfo = assets.getToken(tokenOut);
|
|
337
|
+
return {
|
|
338
|
+
hash: result.hash,
|
|
339
|
+
tokenIn: tokenInInfo.symbol,
|
|
340
|
+
tokenOut: tokenOutInfo.symbol,
|
|
341
|
+
amountIn: amount,
|
|
342
|
+
amountOut: (0, import_viem3.formatUnits)(BigInt(quote.expectedOut), tokenOutInfo.decimals),
|
|
343
|
+
chainId
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
// src/core/client.ts
|
|
348
|
+
var ERC20_ABI2 = [
|
|
349
|
+
{
|
|
350
|
+
name: "balanceOf",
|
|
351
|
+
type: "function",
|
|
352
|
+
stateMutability: "view",
|
|
353
|
+
inputs: [{ name: "account", type: "address" }],
|
|
354
|
+
outputs: [{ name: "", type: "uint256" }]
|
|
355
|
+
},
|
|
356
|
+
{
|
|
357
|
+
name: "transfer",
|
|
358
|
+
type: "function",
|
|
359
|
+
stateMutability: "nonpayable",
|
|
360
|
+
inputs: [
|
|
361
|
+
{ name: "to", type: "address" },
|
|
362
|
+
{ name: "amount", type: "uint256" }
|
|
363
|
+
],
|
|
364
|
+
outputs: [{ name: "", type: "bool" }]
|
|
365
|
+
},
|
|
366
|
+
{
|
|
367
|
+
name: "decimals",
|
|
368
|
+
type: "function",
|
|
369
|
+
stateMutability: "view",
|
|
370
|
+
inputs: [],
|
|
371
|
+
outputs: [{ name: "", type: "uint8" }]
|
|
372
|
+
},
|
|
373
|
+
{
|
|
374
|
+
name: "symbol",
|
|
375
|
+
type: "function",
|
|
376
|
+
stateMutability: "view",
|
|
377
|
+
inputs: [],
|
|
378
|
+
outputs: [{ name: "", type: "string" }]
|
|
379
|
+
}
|
|
380
|
+
];
|
|
381
|
+
var DefaultAssetRegistry = class {
|
|
382
|
+
nativeTokenAddress = NATIVE_TOKEN_ADDRESS;
|
|
383
|
+
getToken = getToken;
|
|
384
|
+
getTokenAddress = getTokenAddress;
|
|
385
|
+
getChain = getChain;
|
|
386
|
+
};
|
|
387
|
+
var MoneyOS = class {
|
|
388
|
+
read;
|
|
389
|
+
executor;
|
|
390
|
+
assets;
|
|
391
|
+
runtimeConfig;
|
|
392
|
+
constructor(config) {
|
|
393
|
+
const provided = [];
|
|
394
|
+
if (config.execute) provided.push("execute");
|
|
395
|
+
if (config.privateKey) provided.push("privateKey");
|
|
396
|
+
if (config.signer) provided.push("signer");
|
|
397
|
+
if (provided.length > 1) {
|
|
398
|
+
throw new Error(
|
|
399
|
+
`MoneyOSConfig: pass at most one of \`execute\`, \`privateKey\`, or \`signer\`. Received: ${provided.join(", ")}.`
|
|
400
|
+
);
|
|
401
|
+
}
|
|
402
|
+
this.runtimeConfig = {
|
|
403
|
+
defaultChainId: config.chainId ?? defaultChain.id,
|
|
404
|
+
rpcUrl: config.rpcUrl
|
|
405
|
+
};
|
|
406
|
+
this.read = config.read ?? new ViemReadClient(this.runtimeConfig);
|
|
407
|
+
this.assets = config.assets ?? new DefaultAssetRegistry();
|
|
408
|
+
if (config.execute) {
|
|
409
|
+
this.executor = config.execute;
|
|
410
|
+
} else if (config.signer) {
|
|
411
|
+
this.executor = new EOAExecutor(config.signer, this.runtimeConfig);
|
|
412
|
+
} else if (config.privateKey) {
|
|
413
|
+
this.executor = EOAExecutor.fromPrivateKey(
|
|
414
|
+
config.privateKey,
|
|
415
|
+
this.runtimeConfig
|
|
416
|
+
);
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
get runtime() {
|
|
420
|
+
return {
|
|
421
|
+
read: this.read,
|
|
422
|
+
execute: this.requireExecutor(),
|
|
423
|
+
assets: this.assets,
|
|
424
|
+
config: this.runtimeConfig
|
|
425
|
+
};
|
|
426
|
+
}
|
|
427
|
+
get address() {
|
|
428
|
+
return this.requireExecutor().getAddress();
|
|
429
|
+
}
|
|
430
|
+
requireExecutor() {
|
|
431
|
+
if (!this.executor) {
|
|
432
|
+
throw new Error(
|
|
433
|
+
"No signing account configured. Set `signer`, `privateKey`, or `execute` in MoneyOS config."
|
|
434
|
+
);
|
|
435
|
+
}
|
|
436
|
+
return this.executor;
|
|
437
|
+
}
|
|
438
|
+
async balance(token, options) {
|
|
439
|
+
const chainId = options?.chainId ?? this.runtimeConfig.defaultChainId;
|
|
440
|
+
const account = options?.address ?? this.address;
|
|
441
|
+
const tokenAddress = this.assets.getTokenAddress(token, chainId);
|
|
442
|
+
if (!tokenAddress) {
|
|
443
|
+
throw new Error(`Token ${token} not found on chain ${chainId}`);
|
|
444
|
+
}
|
|
445
|
+
const tokenInfo = this.assets.getToken(token);
|
|
446
|
+
if (tokenAddress === NATIVE_TOKEN_ADDRESS) {
|
|
447
|
+
const raw2 = await this.read.getBalance({ address: account, chainId });
|
|
448
|
+
return {
|
|
449
|
+
token: tokenInfo.name,
|
|
450
|
+
symbol: tokenInfo.symbol,
|
|
451
|
+
amount: (0, import_viem4.formatUnits)(raw2, tokenInfo.decimals),
|
|
452
|
+
rawAmount: raw2,
|
|
453
|
+
decimals: tokenInfo.decimals,
|
|
454
|
+
chainId
|
|
455
|
+
};
|
|
456
|
+
}
|
|
457
|
+
const raw = await this.read.readContract({
|
|
458
|
+
address: tokenAddress,
|
|
459
|
+
abi: ERC20_ABI2,
|
|
460
|
+
functionName: "balanceOf",
|
|
461
|
+
args: [account],
|
|
462
|
+
chainId
|
|
463
|
+
});
|
|
464
|
+
return {
|
|
465
|
+
token: tokenInfo.name,
|
|
466
|
+
symbol: tokenInfo.symbol,
|
|
467
|
+
amount: (0, import_viem4.formatUnits)(raw, tokenInfo.decimals),
|
|
468
|
+
rawAmount: raw,
|
|
469
|
+
decimals: tokenInfo.decimals,
|
|
470
|
+
chainId
|
|
471
|
+
};
|
|
472
|
+
}
|
|
473
|
+
async send(token, to, amount, options) {
|
|
474
|
+
const execute = this.requireExecutor();
|
|
475
|
+
const chainId = options?.chainId ?? this.runtimeConfig.defaultChainId;
|
|
476
|
+
const from = execute.getAddress();
|
|
477
|
+
const tokenAddress = this.assets.getTokenAddress(token, chainId);
|
|
478
|
+
if (!tokenAddress) {
|
|
479
|
+
throw new Error(`Token ${token} not found on chain ${chainId}`);
|
|
480
|
+
}
|
|
481
|
+
const tokenInfo = this.assets.getToken(token);
|
|
482
|
+
const value = (0, import_viem4.parseUnits)(amount, tokenInfo.decimals);
|
|
483
|
+
if (tokenAddress === NATIVE_TOKEN_ADDRESS) {
|
|
484
|
+
const result2 = await execute.send({ to, value, chainId });
|
|
485
|
+
return {
|
|
486
|
+
hash: result2.hash,
|
|
487
|
+
from,
|
|
488
|
+
to,
|
|
489
|
+
amount,
|
|
490
|
+
token: tokenInfo.symbol,
|
|
491
|
+
chainId
|
|
492
|
+
};
|
|
493
|
+
}
|
|
494
|
+
const data = (0, import_viem4.encodeFunctionData)({
|
|
495
|
+
abi: ERC20_ABI2,
|
|
496
|
+
functionName: "transfer",
|
|
497
|
+
args: [to, value]
|
|
498
|
+
});
|
|
499
|
+
const result = await execute.send({ to: tokenAddress, data, chainId });
|
|
500
|
+
return {
|
|
501
|
+
hash: result.hash,
|
|
502
|
+
from,
|
|
503
|
+
to,
|
|
504
|
+
amount,
|
|
505
|
+
token: tokenInfo.symbol,
|
|
506
|
+
chainId
|
|
507
|
+
};
|
|
508
|
+
}
|
|
509
|
+
async swap(tokenIn, tokenOut, amount, provider, options) {
|
|
510
|
+
const execute = this.requireExecutor();
|
|
511
|
+
const chainId = options?.chainId ?? this.runtimeConfig.defaultChainId;
|
|
512
|
+
return executeSwap(
|
|
513
|
+
{ tokenIn, tokenOut, amount, provider, chainId, slippage: options?.slippage },
|
|
514
|
+
{ read: this.read, execute, assets: this.assets }
|
|
515
|
+
);
|
|
516
|
+
}
|
|
517
|
+
};
|
|
518
|
+
|
|
519
|
+
// src/providers/odos.ts
|
|
520
|
+
var ODOS_API = "https://api.odos.xyz";
|
|
521
|
+
var ODOS_NATIVE_ADDRESS = "0x0000000000000000000000000000000000000000";
|
|
522
|
+
var OdosProvider = class {
|
|
523
|
+
name = "odos";
|
|
524
|
+
apiKey;
|
|
525
|
+
constructor(options) {
|
|
526
|
+
this.apiKey = options?.apiKey;
|
|
527
|
+
}
|
|
528
|
+
toOdosAddress(address) {
|
|
529
|
+
return address === NATIVE_TOKEN_ADDRESS ? ODOS_NATIVE_ADDRESS : address;
|
|
530
|
+
}
|
|
531
|
+
async getQuote(params) {
|
|
532
|
+
const headers = {
|
|
533
|
+
"Content-Type": "application/json"
|
|
534
|
+
};
|
|
535
|
+
if (this.apiKey) {
|
|
536
|
+
headers["Authorization"] = `Bearer ${this.apiKey}`;
|
|
537
|
+
}
|
|
538
|
+
const response = await fetch(`${ODOS_API}/sor/quote/v2`, {
|
|
539
|
+
method: "POST",
|
|
540
|
+
headers,
|
|
541
|
+
body: JSON.stringify({
|
|
542
|
+
chainId: params.chainId,
|
|
543
|
+
inputTokens: [
|
|
544
|
+
{
|
|
545
|
+
tokenAddress: this.toOdosAddress(params.tokenIn),
|
|
546
|
+
amount: params.amount.toString()
|
|
547
|
+
}
|
|
548
|
+
],
|
|
549
|
+
outputTokens: [
|
|
550
|
+
{
|
|
551
|
+
tokenAddress: this.toOdosAddress(params.tokenOut),
|
|
552
|
+
proportion: 1
|
|
553
|
+
}
|
|
554
|
+
],
|
|
555
|
+
userAddr: params.sender,
|
|
556
|
+
slippageLimitPercent: params.slippage ?? 1,
|
|
557
|
+
referralCode: 0,
|
|
558
|
+
compact: true
|
|
559
|
+
})
|
|
560
|
+
});
|
|
561
|
+
if (!response.ok) {
|
|
562
|
+
const text = await response.text();
|
|
563
|
+
throw new Error(`Odos quote failed: ${response.status} ${text}`);
|
|
564
|
+
}
|
|
565
|
+
const data = await response.json();
|
|
566
|
+
return {
|
|
567
|
+
tokenIn: params.tokenIn,
|
|
568
|
+
tokenOut: params.tokenOut,
|
|
569
|
+
amountIn: params.amount.toString(),
|
|
570
|
+
expectedOut: data.outAmounts[0],
|
|
571
|
+
router: "",
|
|
572
|
+
chainId: params.chainId,
|
|
573
|
+
pathId: data.pathId,
|
|
574
|
+
sender: params.sender
|
|
575
|
+
};
|
|
576
|
+
}
|
|
577
|
+
async getCalldata(quote) {
|
|
578
|
+
const headers = {
|
|
579
|
+
"Content-Type": "application/json"
|
|
580
|
+
};
|
|
581
|
+
if (this.apiKey) {
|
|
582
|
+
headers["Authorization"] = `Bearer ${this.apiKey}`;
|
|
583
|
+
}
|
|
584
|
+
const response = await fetch(`${ODOS_API}/sor/assemble`, {
|
|
585
|
+
method: "POST",
|
|
586
|
+
headers,
|
|
587
|
+
body: JSON.stringify({
|
|
588
|
+
userAddr: quote.sender,
|
|
589
|
+
pathId: quote.pathId,
|
|
590
|
+
simulate: false
|
|
591
|
+
})
|
|
592
|
+
});
|
|
593
|
+
if (!response.ok) {
|
|
594
|
+
const text = await response.text();
|
|
595
|
+
throw new Error(`Odos assemble failed: ${response.status} ${text}`);
|
|
596
|
+
}
|
|
597
|
+
const data = await response.json();
|
|
598
|
+
return {
|
|
599
|
+
to: data.transaction.to,
|
|
600
|
+
data: data.transaction.data,
|
|
601
|
+
value: BigInt(data.transaction.value)
|
|
602
|
+
};
|
|
603
|
+
}
|
|
604
|
+
};
|
|
605
|
+
|
|
606
|
+
// src/core/access-local.ts
|
|
607
|
+
var import_accounts2 = require("viem/accounts");
|
|
608
|
+
var LocalAccessSession = class {
|
|
609
|
+
kind = "local";
|
|
610
|
+
address;
|
|
611
|
+
constructor(privateKey) {
|
|
612
|
+
this.address = (0, import_accounts2.privateKeyToAccount)(privateKey).address;
|
|
613
|
+
}
|
|
614
|
+
getAddress() {
|
|
615
|
+
return this.address;
|
|
616
|
+
}
|
|
617
|
+
};
|
|
618
|
+
var LocalAccessAdapter = class {
|
|
619
|
+
name = "local";
|
|
620
|
+
privateKey;
|
|
621
|
+
constructor(privateKey) {
|
|
622
|
+
this.privateKey = privateKey;
|
|
623
|
+
}
|
|
624
|
+
async openSession(_ctx) {
|
|
625
|
+
return new LocalAccessSession(this.privateKey);
|
|
626
|
+
}
|
|
627
|
+
};
|
|
628
|
+
|
|
629
|
+
// src/core/keystore-file.ts
|
|
630
|
+
var import_node_fs = require("fs");
|
|
631
|
+
var import_node_os = require("os");
|
|
632
|
+
var import_node_path = require("path");
|
|
633
|
+
var import_accounts3 = require("viem/accounts");
|
|
634
|
+
var DEFAULT_CONFIG_PATH = (0, import_node_path.join)((0, import_node_os.homedir)(), ".moneyos", "config.json");
|
|
635
|
+
var FileKeyStore = class {
|
|
636
|
+
kind = "file";
|
|
637
|
+
configPath;
|
|
638
|
+
constructor(options = {}) {
|
|
639
|
+
this.configPath = options.configPath ?? DEFAULT_CONFIG_PATH;
|
|
640
|
+
}
|
|
641
|
+
async hasKey() {
|
|
642
|
+
const config = this.readConfig();
|
|
643
|
+
return Boolean(config?.privateKey);
|
|
644
|
+
}
|
|
645
|
+
async metadata() {
|
|
646
|
+
const config = this.readConfig();
|
|
647
|
+
const address = config?.privateKey ? (0, import_accounts3.privateKeyToAccount)(config.privateKey).address : void 0;
|
|
648
|
+
return {
|
|
649
|
+
kind: "file",
|
|
650
|
+
address
|
|
651
|
+
};
|
|
652
|
+
}
|
|
653
|
+
async loadSigner() {
|
|
654
|
+
const config = this.readConfig();
|
|
655
|
+
if (!config?.privateKey) {
|
|
656
|
+
throw new Error(
|
|
657
|
+
`FileKeyStore: no private key found at ${this.configPath}. Run \`moneyos init\` to create one.`
|
|
658
|
+
);
|
|
659
|
+
}
|
|
660
|
+
return privateKeyToManagedAccount(config.privateKey);
|
|
661
|
+
}
|
|
662
|
+
/**
|
|
663
|
+
* Read and validate the config file. Returns `undefined` if the file does
|
|
664
|
+
* not exist. Throws with context for any other failure mode (malformed
|
|
665
|
+
* JSON, wrong top-level type, wrong `privateKey` type). The hex format of
|
|
666
|
+
* the key itself is validated later by viem's `privateKeyToAccount`.
|
|
667
|
+
*/
|
|
668
|
+
readConfig() {
|
|
669
|
+
if (!(0, import_node_fs.existsSync)(this.configPath)) {
|
|
670
|
+
return void 0;
|
|
671
|
+
}
|
|
672
|
+
let parsed;
|
|
673
|
+
try {
|
|
674
|
+
parsed = JSON.parse((0, import_node_fs.readFileSync)(this.configPath, "utf-8"));
|
|
675
|
+
} catch (error) {
|
|
676
|
+
throw new Error(
|
|
677
|
+
`FileKeyStore: failed to read config at ${this.configPath}`,
|
|
678
|
+
{ cause: error }
|
|
679
|
+
);
|
|
680
|
+
}
|
|
681
|
+
if (typeof parsed !== "object" || parsed === null) {
|
|
682
|
+
throw new Error(
|
|
683
|
+
`FileKeyStore: config at ${this.configPath} is not a JSON object`
|
|
684
|
+
);
|
|
685
|
+
}
|
|
686
|
+
const pk = parsed.privateKey;
|
|
687
|
+
if (pk === void 0 || pk === null) {
|
|
688
|
+
return {};
|
|
689
|
+
}
|
|
690
|
+
if (typeof pk !== "string") {
|
|
691
|
+
throw new Error(
|
|
692
|
+
`FileKeyStore: privateKey at ${this.configPath} must be a string`
|
|
693
|
+
);
|
|
694
|
+
}
|
|
695
|
+
return { privateKey: pk };
|
|
696
|
+
}
|
|
697
|
+
};
|
|
698
|
+
|
|
699
|
+
// src/core/factory.ts
|
|
700
|
+
function createMoneyOS(config) {
|
|
701
|
+
return new MoneyOS(config);
|
|
702
|
+
}
|
|
703
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
704
|
+
0 && (module.exports = {
|
|
705
|
+
EOAExecutor,
|
|
706
|
+
FileKeyStore,
|
|
707
|
+
LocalAccessAdapter,
|
|
708
|
+
MoneyOS,
|
|
709
|
+
NATIVE_TOKEN_ADDRESS,
|
|
710
|
+
OdosProvider,
|
|
711
|
+
ViemReadClient,
|
|
712
|
+
chains,
|
|
713
|
+
createMoneyOS,
|
|
714
|
+
defaultChain,
|
|
715
|
+
getChain,
|
|
716
|
+
getToken,
|
|
717
|
+
getTokenAddress,
|
|
718
|
+
tokens
|
|
719
|
+
});
|
|
720
|
+
//# sourceMappingURL=index.cjs.map
|