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