@subly_fi/pay 0.7.0 → 0.7.2
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 +10 -10
- package/dist/budget.js +8 -3
- package/dist/deposit.js +8 -3
- package/dist/doctor.js +4 -4
- package/dist/mcp-server.js +17 -4
- package/dist/pay.js +17 -4
- package/dist/setup-link.js +8 -3
- package/dist/withdraw.js +8 -3
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -9,12 +9,12 @@ Version 0.7 is beta software and has not had an external security audit. Vault o
|
|
|
9
9
|
You need **Node.js 24+**, a Solana agent wallet with mainnet USDC, a trusted relayer URL, and a mainnet RPC endpoint that supports transaction simulation with inner instructions. Your wallet can be a local keypair or a supported custody signer. The owner who approves spending controls can use a passkey or a separate Solana wallet.
|
|
10
10
|
|
|
11
11
|
```bash
|
|
12
|
-
npx -y @subly_fi/pay@0.7.
|
|
12
|
+
npx -y @subly_fi/pay@0.7.2 --help
|
|
13
13
|
export SUBLY_RELAYER_URL=https://your-relayer.example.com
|
|
14
14
|
export SOLANA_RPC_URL=https://your-mainnet-rpc.example.com
|
|
15
15
|
export SUBLY_DEMO_AGENT_KEYPAIR_PATH=/absolute/path/to/agent.json
|
|
16
|
-
npx -y @subly_fi/pay@0.7.
|
|
17
|
-
npx -y @subly_fi/pay@0.7.
|
|
16
|
+
npx -y @subly_fi/pay@0.7.2 doctor
|
|
17
|
+
npx -y @subly_fi/pay@0.7.2 vaults
|
|
18
18
|
```
|
|
19
19
|
|
|
20
20
|
Use an existing dedicated agent wallet, or create one with `solana-keygen new -o agent.json`. Keep its recovery material private and restrict the file to its owner (`chmod 600 agent.json`). Fund its public address with **USDC on Solana mainnet**. Subly does not create or fund wallets. Vault fees require a funded relayer sponsor; the final API payment requires the seller's facilitator fee payer.
|
|
@@ -23,28 +23,28 @@ Use an existing dedicated agent wallet, or create one with `solana-keygen new -o
|
|
|
23
23
|
2. Create an owner setup link. This example pre-approves a **1.01 USDC** deposit; the selected vault's minimum can differ:
|
|
24
24
|
|
|
25
25
|
```bash
|
|
26
|
-
npx -y @subly_fi/pay@0.7.
|
|
26
|
+
npx -y @subly_fi/pay@0.7.2 setup-link --initial-deposit 1010000
|
|
27
27
|
```
|
|
28
28
|
|
|
29
29
|
Open the returned `setupUrl`, review the wallet, vault and limits, then approve with your passkey or wallet. Links expire in 10 minutes. Treat setup and approval links as private capabilities. The first person completing an initial setup becomes the owner for that wallet/vault.
|
|
30
30
|
3. Check completion and deposit promptly; initial deposit approval lasts about 15 minutes:
|
|
31
31
|
|
|
32
32
|
```bash
|
|
33
|
-
npx -y @subly_fi/pay@0.7.
|
|
34
|
-
npx -y @subly_fi/pay@0.7.
|
|
35
|
-
npx -y @subly_fi/pay@0.7.
|
|
33
|
+
npx -y @subly_fi/pay@0.7.2 setup-status <sessionId>
|
|
34
|
+
npx -y @subly_fi/pay@0.7.2 deposit 1010000
|
|
35
|
+
npx -y @subly_fi/pay@0.7.2 budget
|
|
36
36
|
```
|
|
37
37
|
|
|
38
38
|
4. Wait until **spendable yield** covers the price and vault fees. A new deposit does not immediately provide a payment budget. Then request a compatible API:
|
|
39
39
|
|
|
40
40
|
```bash
|
|
41
|
-
npx -y @subly_fi/pay@0.7.
|
|
41
|
+
npx -y @subly_fi/pay@0.7.2 fetch https://seller.example.com/paid-resource
|
|
42
42
|
```
|
|
43
43
|
|
|
44
44
|
5. Withdraw funds back to the same agent wallet when needed:
|
|
45
45
|
|
|
46
46
|
```bash
|
|
47
|
-
npx -y @subly_fi/pay@0.7.
|
|
47
|
+
npx -y @subly_fi/pay@0.7.2 withdraw 1000000
|
|
48
48
|
```
|
|
49
49
|
|
|
50
50
|
All amounts are raw USDC integers: `1000000` = 1 USDC. `fetch` defaults to a **0.01 USDC cap**, configurable with `SUBLY_MCP_MAX_AMOUNT_RAW_USDC` or `fetch <URL> <capRawUSDC>`. The owner mandate may set stricter limits. `setup-link --help` lists policy options. A withdrawal can include principal and is subject to liquidity, fees and the owner's policy. A revoked mandate also blocks relayer withdrawals.
|
|
@@ -60,7 +60,7 @@ Add this to the MCP configuration of your editor or agent host. Replace all exam
|
|
|
60
60
|
"mcpServers": {
|
|
61
61
|
"subly": {
|
|
62
62
|
"command": "npx",
|
|
63
|
-
"args": ["-y", "@subly_fi/pay@0.7.
|
|
63
|
+
"args": ["-y", "@subly_fi/pay@0.7.2", "mcp"],
|
|
64
64
|
"env": {
|
|
65
65
|
"SUBLY_RELAYER_URL": "https://your-relayer.example.com",
|
|
66
66
|
"SOLANA_RPC_URL": "https://your-mainnet-rpc.example.com",
|
package/dist/budget.js
CHANGED
|
@@ -1747,8 +1747,11 @@ async function agentWalletSignerFromEnv(env = process.env) {
|
|
|
1747
1747
|
);
|
|
1748
1748
|
}
|
|
1749
1749
|
|
|
1750
|
+
// ../../src/domain/withdrawal-rounding.ts
|
|
1751
|
+
var WITHDRAWAL_ROUNDING_RAW_USDC = 10n;
|
|
1752
|
+
var YIELD_REALIZE_ROUNDING_RAW_USDC = WITHDRAWAL_ROUNDING_RAW_USDC / 2n;
|
|
1753
|
+
|
|
1750
1754
|
// ../../src/client/withdrawal-preview.ts
|
|
1751
|
-
var ROUNDING_RAW_USDC = 10n;
|
|
1752
1755
|
async function assertWithdrawalPreview(input) {
|
|
1753
1756
|
const destination = deriveAssociatedTokenAddress({ owner: input.wallet, mint: input.vault.usdcMint });
|
|
1754
1757
|
const simulation = await input.rpc.simulateTransaction(
|
|
@@ -1781,7 +1784,8 @@ async function assertWithdrawalPreview(input) {
|
|
|
1781
1784
|
if (info.source === destination) received -= amount;
|
|
1782
1785
|
}
|
|
1783
1786
|
}
|
|
1784
|
-
|
|
1787
|
+
const minimum = input.purpose === "yield_realize" ? input.amountRawUsdc : input.amountRawUsdc - WITHDRAWAL_ROUNDING_RAW_USDC;
|
|
1788
|
+
if (received <= 0n || received > input.amountRawUsdc + WITHDRAWAL_ROUNDING_RAW_USDC || received < minimum) {
|
|
1785
1789
|
throw new Error("Withdrawal preview differs from the requested USDC amount; no transaction was signed");
|
|
1786
1790
|
}
|
|
1787
1791
|
}
|
|
@@ -1988,7 +1992,8 @@ var VaultFlowClient = class {
|
|
|
1988
1992
|
serializedTransaction: prepared.serializedTransaction,
|
|
1989
1993
|
wallet: this.signer.walletAddress,
|
|
1990
1994
|
vault: this.vault,
|
|
1991
|
-
amountRawUsdc: input.amountRawUsdc
|
|
1995
|
+
amountRawUsdc: input.amountRawUsdc,
|
|
1996
|
+
...input.purpose === void 0 ? {} : { purpose: input.purpose }
|
|
1992
1997
|
});
|
|
1993
1998
|
const signed = await this.signer.signWithdrawal({
|
|
1994
1999
|
intent: prepared.signingIntent,
|
package/dist/deposit.js
CHANGED
|
@@ -1843,8 +1843,11 @@ async function agentWalletSignerFromEnv(env = process.env) {
|
|
|
1843
1843
|
);
|
|
1844
1844
|
}
|
|
1845
1845
|
|
|
1846
|
+
// ../../src/domain/withdrawal-rounding.ts
|
|
1847
|
+
var WITHDRAWAL_ROUNDING_RAW_USDC = 10n;
|
|
1848
|
+
var YIELD_REALIZE_ROUNDING_RAW_USDC = WITHDRAWAL_ROUNDING_RAW_USDC / 2n;
|
|
1849
|
+
|
|
1846
1850
|
// ../../src/client/withdrawal-preview.ts
|
|
1847
|
-
var ROUNDING_RAW_USDC = 10n;
|
|
1848
1851
|
async function assertWithdrawalPreview(input) {
|
|
1849
1852
|
const destination = deriveAssociatedTokenAddress({ owner: input.wallet, mint: input.vault.usdcMint });
|
|
1850
1853
|
const simulation = await input.rpc.simulateTransaction(
|
|
@@ -1877,7 +1880,8 @@ async function assertWithdrawalPreview(input) {
|
|
|
1877
1880
|
if (info.source === destination) received -= amount;
|
|
1878
1881
|
}
|
|
1879
1882
|
}
|
|
1880
|
-
|
|
1883
|
+
const minimum = input.purpose === "yield_realize" ? input.amountRawUsdc : input.amountRawUsdc - WITHDRAWAL_ROUNDING_RAW_USDC;
|
|
1884
|
+
if (received <= 0n || received > input.amountRawUsdc + WITHDRAWAL_ROUNDING_RAW_USDC || received < minimum) {
|
|
1881
1885
|
throw new Error("Withdrawal preview differs from the requested USDC amount; no transaction was signed");
|
|
1882
1886
|
}
|
|
1883
1887
|
}
|
|
@@ -2047,7 +2051,8 @@ var VaultFlowClient = class {
|
|
|
2047
2051
|
serializedTransaction: prepared.serializedTransaction,
|
|
2048
2052
|
wallet: this.signer.walletAddress,
|
|
2049
2053
|
vault: this.vault,
|
|
2050
|
-
amountRawUsdc: input.amountRawUsdc
|
|
2054
|
+
amountRawUsdc: input.amountRawUsdc,
|
|
2055
|
+
...input.purpose === void 0 ? {} : { purpose: input.purpose }
|
|
2051
2056
|
});
|
|
2052
2057
|
const signed = await this.signer.signWithdrawal({
|
|
2053
2058
|
intent: prepared.signingIntent,
|
package/dist/doctor.js
CHANGED
|
@@ -169,18 +169,18 @@ await check("relayer and vault", async () => {
|
|
|
169
169
|
if (url.protocol !== "https:" && !(url.protocol === "http:" && ["localhost", "127.0.0.1", "[::1]"].includes(url.hostname))) throw new Error("Use HTTPS (HTTP is allowed only for local development)");
|
|
170
170
|
const catalog = vaultCatalogFromEnv();
|
|
171
171
|
const local = defaultCatalogVault(catalog);
|
|
172
|
-
const health = await fetch(`${url.toString().replace(/\/$/, "")}/
|
|
173
|
-
if (!health.ok || (await health.json()).ok !== true) throw new Error("Relayer
|
|
172
|
+
const health = await fetch(`${url.toString().replace(/\/$/, "")}/readyz`, { signal: AbortSignal.timeout(1e4) });
|
|
173
|
+
if (!health.ok || (await health.json()).ok !== true) throw new Error("Relayer readiness check failed");
|
|
174
174
|
const response = await fetch(`${url.toString().replace(/\/$/, "")}/v1/vaults`, { signal: AbortSignal.timeout(1e4) });
|
|
175
175
|
if (!response.ok) throw new Error("Relayer vault catalogue unavailable");
|
|
176
176
|
const remote = (await response.json()).vaults?.find((v) => v.address === local.address);
|
|
177
177
|
if (!remote || ["programId", "usdcMint", "shareMint", "farm"].some((key) => remote[key] !== local[key])) throw new Error("Selected local vault trust anchors differ from the relayer; review the operator catalogue before changing configuration");
|
|
178
|
-
return `
|
|
178
|
+
return `Ready; selected vault ${local.address} matches local trust anchors`;
|
|
179
179
|
});
|
|
180
180
|
await check("Solana RPC", async () => {
|
|
181
181
|
const response = await fetch(env.SOLANA_RPC_URL ?? "https://api.mainnet-beta.solana.com", { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ jsonrpc: "2.0", id: 1, method: "getGenesisHash" }), signal: AbortSignal.timeout(1e4) });
|
|
182
182
|
const body = await response.json();
|
|
183
|
-
if (!response.ok || body.result !== "
|
|
183
|
+
if (!response.ok || body.result !== "5eykt4UsFv8P8NJdTREpY1vzqKqZKvdpKuc147dw2N9d") throw new Error("RPC is unavailable or is not Solana mainnet-beta");
|
|
184
184
|
return "Mainnet-beta RPC reachable";
|
|
185
185
|
});
|
|
186
186
|
var ok = checks.every((c) => c.ok);
|
package/dist/mcp-server.js
CHANGED
|
@@ -274,8 +274,11 @@ function modPow(base, exponent, modulus) {
|
|
|
274
274
|
return result;
|
|
275
275
|
}
|
|
276
276
|
|
|
277
|
+
// ../../src/domain/withdrawal-rounding.ts
|
|
278
|
+
var WITHDRAWAL_ROUNDING_RAW_USDC = 10n;
|
|
279
|
+
var YIELD_REALIZE_ROUNDING_RAW_USDC = WITHDRAWAL_ROUNDING_RAW_USDC / 2n;
|
|
280
|
+
|
|
277
281
|
// ../../src/client/withdrawal-preview.ts
|
|
278
|
-
var ROUNDING_RAW_USDC = 10n;
|
|
279
282
|
async function assertWithdrawalPreview(input) {
|
|
280
283
|
const destination = deriveAssociatedTokenAddress({ owner: input.wallet, mint: input.vault.usdcMint });
|
|
281
284
|
const simulation = await input.rpc.simulateTransaction(
|
|
@@ -308,7 +311,8 @@ async function assertWithdrawalPreview(input) {
|
|
|
308
311
|
if (info.source === destination) received -= amount;
|
|
309
312
|
}
|
|
310
313
|
}
|
|
311
|
-
|
|
314
|
+
const minimum = input.purpose === "yield_realize" ? input.amountRawUsdc : input.amountRawUsdc - WITHDRAWAL_ROUNDING_RAW_USDC;
|
|
315
|
+
if (received <= 0n || received > input.amountRawUsdc + WITHDRAWAL_ROUNDING_RAW_USDC || received < minimum) {
|
|
312
316
|
throw new Error("Withdrawal preview differs from the requested USDC amount; no transaction was signed");
|
|
313
317
|
}
|
|
314
318
|
}
|
|
@@ -515,7 +519,8 @@ var VaultFlowClient = class {
|
|
|
515
519
|
serializedTransaction: prepared.serializedTransaction,
|
|
516
520
|
wallet: this.signer.walletAddress,
|
|
517
521
|
vault: this.vault,
|
|
518
|
-
amountRawUsdc: input.amountRawUsdc
|
|
522
|
+
amountRawUsdc: input.amountRawUsdc,
|
|
523
|
+
...input.purpose === void 0 ? {} : { purpose: input.purpose }
|
|
519
524
|
});
|
|
520
525
|
const signed = await this.signer.signWithdrawal({
|
|
521
526
|
intent: prepared.signingIntent,
|
|
@@ -1013,6 +1018,7 @@ function hashStableJson(value) {
|
|
|
1013
1018
|
|
|
1014
1019
|
// ../../src/x402/headers.ts
|
|
1015
1020
|
var PAYMENT_REQUIRED_HEADER = "payment-required";
|
|
1021
|
+
var PAYMENT_RESPONSE_HEADER = "payment-response";
|
|
1016
1022
|
var MAX_HEADER_JSON_BYTES = 16384;
|
|
1017
1023
|
var X402HeaderError = class extends Error {
|
|
1018
1024
|
reason;
|
|
@@ -1367,6 +1373,13 @@ var StandardX402Payer = class {
|
|
|
1367
1373
|
{ error, pendingPayment: pendingRecord }
|
|
1368
1374
|
);
|
|
1369
1375
|
}
|
|
1376
|
+
if (realized.realizedRawUsdc < selected2.amountRawUsdc) {
|
|
1377
|
+
throw new StandardX402PayError(
|
|
1378
|
+
"realize_underfunded",
|
|
1379
|
+
"The confirmed withdrawal did not cover the exact API price. No external payment was attempted; reconcile the recorded withdrawal before retrying.",
|
|
1380
|
+
{ pendingPayment: pendingRecord }
|
|
1381
|
+
);
|
|
1382
|
+
}
|
|
1370
1383
|
let response;
|
|
1371
1384
|
try {
|
|
1372
1385
|
response = await this.x402Fetch(input.url, init, selected2);
|
|
@@ -1532,7 +1545,7 @@ function pendingPaymentKey(input) {
|
|
|
1532
1545
|
return `${input.method}:${input.url}:${input.requestBodyHash}`;
|
|
1533
1546
|
}
|
|
1534
1547
|
function extractSettledPaymentTxSignature(response) {
|
|
1535
|
-
const header = response.headers.get("x-payment-response");
|
|
1548
|
+
const header = response.headers.get(PAYMENT_RESPONSE_HEADER) ?? response.headers.get("x-payment-response");
|
|
1536
1549
|
if (header === null || header.length === 0) {
|
|
1537
1550
|
return null;
|
|
1538
1551
|
}
|
package/dist/pay.js
CHANGED
|
@@ -328,8 +328,11 @@ function modPow(base, exponent, modulus) {
|
|
|
328
328
|
return result;
|
|
329
329
|
}
|
|
330
330
|
|
|
331
|
+
// ../../src/domain/withdrawal-rounding.ts
|
|
332
|
+
var WITHDRAWAL_ROUNDING_RAW_USDC = 10n;
|
|
333
|
+
var YIELD_REALIZE_ROUNDING_RAW_USDC = WITHDRAWAL_ROUNDING_RAW_USDC / 2n;
|
|
334
|
+
|
|
331
335
|
// ../../src/client/withdrawal-preview.ts
|
|
332
|
-
var ROUNDING_RAW_USDC = 10n;
|
|
333
336
|
async function assertWithdrawalPreview(input) {
|
|
334
337
|
const destination = deriveAssociatedTokenAddress({ owner: input.wallet, mint: input.vault.usdcMint });
|
|
335
338
|
const simulation = await input.rpc.simulateTransaction(
|
|
@@ -362,7 +365,8 @@ async function assertWithdrawalPreview(input) {
|
|
|
362
365
|
if (info.source === destination) received -= amount;
|
|
363
366
|
}
|
|
364
367
|
}
|
|
365
|
-
|
|
368
|
+
const minimum = input.purpose === "yield_realize" ? input.amountRawUsdc : input.amountRawUsdc - WITHDRAWAL_ROUNDING_RAW_USDC;
|
|
369
|
+
if (received <= 0n || received > input.amountRawUsdc + WITHDRAWAL_ROUNDING_RAW_USDC || received < minimum) {
|
|
366
370
|
throw new Error("Withdrawal preview differs from the requested USDC amount; no transaction was signed");
|
|
367
371
|
}
|
|
368
372
|
}
|
|
@@ -532,7 +536,8 @@ var VaultFlowClient = class {
|
|
|
532
536
|
serializedTransaction: prepared.serializedTransaction,
|
|
533
537
|
wallet: this.signer.walletAddress,
|
|
534
538
|
vault: this.vault,
|
|
535
|
-
amountRawUsdc: input.amountRawUsdc
|
|
539
|
+
amountRawUsdc: input.amountRawUsdc,
|
|
540
|
+
...input.purpose === void 0 ? {} : { purpose: input.purpose }
|
|
536
541
|
});
|
|
537
542
|
const signed = await this.signer.signWithdrawal({
|
|
538
543
|
intent: prepared.signingIntent,
|
|
@@ -965,6 +970,7 @@ function sha256HexOf(data) {
|
|
|
965
970
|
// ../../src/x402/headers.ts
|
|
966
971
|
import { z as z2 } from "zod";
|
|
967
972
|
var PAYMENT_REQUIRED_HEADER = "payment-required";
|
|
973
|
+
var PAYMENT_RESPONSE_HEADER = "payment-response";
|
|
968
974
|
var MAX_HEADER_JSON_BYTES = 16384;
|
|
969
975
|
var X402HeaderError = class extends Error {
|
|
970
976
|
reason;
|
|
@@ -1303,6 +1309,13 @@ var StandardX402Payer = class {
|
|
|
1303
1309
|
{ error, pendingPayment: pendingRecord }
|
|
1304
1310
|
);
|
|
1305
1311
|
}
|
|
1312
|
+
if (realized.realizedRawUsdc < selected.amountRawUsdc) {
|
|
1313
|
+
throw new StandardX402PayError(
|
|
1314
|
+
"realize_underfunded",
|
|
1315
|
+
"The confirmed withdrawal did not cover the exact API price. No external payment was attempted; reconcile the recorded withdrawal before retrying.",
|
|
1316
|
+
{ pendingPayment: pendingRecord }
|
|
1317
|
+
);
|
|
1318
|
+
}
|
|
1306
1319
|
let response;
|
|
1307
1320
|
try {
|
|
1308
1321
|
response = await this.x402Fetch(input.url, init, selected);
|
|
@@ -1468,7 +1481,7 @@ function pendingPaymentKey(input) {
|
|
|
1468
1481
|
return `${input.method}:${input.url}:${input.requestBodyHash}`;
|
|
1469
1482
|
}
|
|
1470
1483
|
function extractSettledPaymentTxSignature(response) {
|
|
1471
|
-
const header = response.headers.get("x-payment-response");
|
|
1484
|
+
const header = response.headers.get(PAYMENT_RESPONSE_HEADER) ?? response.headers.get("x-payment-response");
|
|
1472
1485
|
if (header === null || header.length === 0) {
|
|
1473
1486
|
return null;
|
|
1474
1487
|
}
|
package/dist/setup-link.js
CHANGED
|
@@ -1747,8 +1747,11 @@ async function agentWalletSignerFromEnv(env = process.env) {
|
|
|
1747
1747
|
);
|
|
1748
1748
|
}
|
|
1749
1749
|
|
|
1750
|
+
// ../../src/domain/withdrawal-rounding.ts
|
|
1751
|
+
var WITHDRAWAL_ROUNDING_RAW_USDC = 10n;
|
|
1752
|
+
var YIELD_REALIZE_ROUNDING_RAW_USDC = WITHDRAWAL_ROUNDING_RAW_USDC / 2n;
|
|
1753
|
+
|
|
1750
1754
|
// ../../src/client/withdrawal-preview.ts
|
|
1751
|
-
var ROUNDING_RAW_USDC = 10n;
|
|
1752
1755
|
async function assertWithdrawalPreview(input) {
|
|
1753
1756
|
const destination = deriveAssociatedTokenAddress({ owner: input.wallet, mint: input.vault.usdcMint });
|
|
1754
1757
|
const simulation = await input.rpc.simulateTransaction(
|
|
@@ -1781,7 +1784,8 @@ async function assertWithdrawalPreview(input) {
|
|
|
1781
1784
|
if (info.source === destination) received -= amount;
|
|
1782
1785
|
}
|
|
1783
1786
|
}
|
|
1784
|
-
|
|
1787
|
+
const minimum = input.purpose === "yield_realize" ? input.amountRawUsdc : input.amountRawUsdc - WITHDRAWAL_ROUNDING_RAW_USDC;
|
|
1788
|
+
if (received <= 0n || received > input.amountRawUsdc + WITHDRAWAL_ROUNDING_RAW_USDC || received < minimum) {
|
|
1785
1789
|
throw new Error("Withdrawal preview differs from the requested USDC amount; no transaction was signed");
|
|
1786
1790
|
}
|
|
1787
1791
|
}
|
|
@@ -1988,7 +1992,8 @@ var VaultFlowClient = class {
|
|
|
1988
1992
|
serializedTransaction: prepared.serializedTransaction,
|
|
1989
1993
|
wallet: this.signer.walletAddress,
|
|
1990
1994
|
vault: this.vault,
|
|
1991
|
-
amountRawUsdc: input.amountRawUsdc
|
|
1995
|
+
amountRawUsdc: input.amountRawUsdc,
|
|
1996
|
+
...input.purpose === void 0 ? {} : { purpose: input.purpose }
|
|
1992
1997
|
});
|
|
1993
1998
|
const signed = await this.signer.signWithdrawal({
|
|
1994
1999
|
intent: prepared.signingIntent,
|
package/dist/withdraw.js
CHANGED
|
@@ -1747,8 +1747,11 @@ async function agentWalletSignerFromEnv(env = process.env) {
|
|
|
1747
1747
|
);
|
|
1748
1748
|
}
|
|
1749
1749
|
|
|
1750
|
+
// ../../src/domain/withdrawal-rounding.ts
|
|
1751
|
+
var WITHDRAWAL_ROUNDING_RAW_USDC = 10n;
|
|
1752
|
+
var YIELD_REALIZE_ROUNDING_RAW_USDC = WITHDRAWAL_ROUNDING_RAW_USDC / 2n;
|
|
1753
|
+
|
|
1750
1754
|
// ../../src/client/withdrawal-preview.ts
|
|
1751
|
-
var ROUNDING_RAW_USDC = 10n;
|
|
1752
1755
|
async function assertWithdrawalPreview(input) {
|
|
1753
1756
|
const destination = deriveAssociatedTokenAddress({ owner: input.wallet, mint: input.vault.usdcMint });
|
|
1754
1757
|
const simulation = await input.rpc.simulateTransaction(
|
|
@@ -1781,7 +1784,8 @@ async function assertWithdrawalPreview(input) {
|
|
|
1781
1784
|
if (info.source === destination) received -= amount;
|
|
1782
1785
|
}
|
|
1783
1786
|
}
|
|
1784
|
-
|
|
1787
|
+
const minimum = input.purpose === "yield_realize" ? input.amountRawUsdc : input.amountRawUsdc - WITHDRAWAL_ROUNDING_RAW_USDC;
|
|
1788
|
+
if (received <= 0n || received > input.amountRawUsdc + WITHDRAWAL_ROUNDING_RAW_USDC || received < minimum) {
|
|
1785
1789
|
throw new Error("Withdrawal preview differs from the requested USDC amount; no transaction was signed");
|
|
1786
1790
|
}
|
|
1787
1791
|
}
|
|
@@ -1988,7 +1992,8 @@ var VaultFlowClient = class {
|
|
|
1988
1992
|
serializedTransaction: prepared.serializedTransaction,
|
|
1989
1993
|
wallet: this.signer.walletAddress,
|
|
1990
1994
|
vault: this.vault,
|
|
1991
|
-
amountRawUsdc: input.amountRawUsdc
|
|
1995
|
+
amountRawUsdc: input.amountRawUsdc,
|
|
1996
|
+
...input.purpose === void 0 ? {} : { purpose: input.purpose }
|
|
1992
1997
|
});
|
|
1993
1998
|
const signed = await this.signer.signWithdrawal({
|
|
1994
1999
|
intent: prepared.signingIntent,
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@subly_fi/pay",
|
|
3
|
-
"version": "0.7.
|
|
4
|
-
"description": "Subly client: pay compatible standard x402 Solana USDC exact APIs from Kamino vault yield
|
|
3
|
+
"version": "0.7.2",
|
|
4
|
+
"description": "Subly client: pay compatible standard x402 Solana USDC exact APIs from Kamino vault yield — the seller needs no Subly integration. Ships an MCP server and a one-shot pay/deposit CLI; non-custodial (signs locally with your own key).",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"x402",
|
|
7
7
|
"solana",
|