@mysten-incubation/sui-agent-pass 0.1.1 → 0.1.3
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 +2 -1
- package/deployments/README.md +5 -1
- package/deployments/testnet.json +2 -24
- package/dist/plugin.js +38 -12
- package/docs/PLAYBOOK.md +4 -2
- package/package.json +1 -1
- package/web-dist/assets/{index-GamQ8vny.js → index--e_95z7d.js} +64 -62
- package/web-dist/assets/index-B_RBIaFM.css +1 -0
- package/web-dist/assets/{mount-B6ddx2sS.js → mount-1CCTGYLA.js} +1 -1
- package/web-dist/deployments/testnet.json +2 -24
- package/web-dist/index.html +2 -2
- package/web-dist/assets/index-IgtbvOwM.css +0 -1
package/README.md
CHANGED
|
@@ -274,7 +274,8 @@ package and a live feed of every call into it, refreshing every four seconds.
|
|
|
274
274
|
The pages use the Sui brand fonts, which are licensed and not in git: put the brand kit under
|
|
275
275
|
`.local/brand/` and run `npm run brand` before building, or the pages fall back to system fonts.
|
|
276
276
|
The build bundles `deployments/<network>.json`; `?network=testnet` picks one, otherwise the
|
|
277
|
-
first of testnet, devnet, localnet
|
|
277
|
+
first of mainnet, testnet, devnet, localnet that exists. `#/` is the home page with the setup
|
|
278
|
+
steps, `#/guide` the longer guide, `#/explorer` the search and the wallet's own passes. To host it, serve `web-dist/` as static
|
|
278
279
|
files at a fixed origin and set `siteUrl` in the deployment file. To run it locally against any
|
|
279
280
|
deployment:
|
|
280
281
|
|
package/deployments/README.md
CHANGED
|
@@ -15,7 +15,11 @@ process with small sums; the real launch will be a fresh publish and a new file
|
|
|
15
15
|
`siteUrl` to it once the hosted site has its address, so the plugin sends owners there.
|
|
16
16
|
`testnet.json` is the current package (Sui Agent Pass), published to testnet on 2026-10-20 with
|
|
17
17
|
the version gate and the per-coin deployment shape (`coins`, `pools`, NAVI `reserves`, the demo
|
|
18
|
-
faucet).
|
|
18
|
+
faucet). The shipped copy lists no pools and no reserves on purpose: the testnet markets are
|
|
19
|
+
stand-ins with 2 SUI of depth, so dogfooders get transfers and staking there and trade on
|
|
20
|
+
mainnet. The stand-in pools stay on chain, and the previous revision of this file in git keeps
|
|
21
|
+
their ids; the tests publish their own stand-ins. Any Move change means a new publish and a new
|
|
22
|
+
file here. `npm run devnet` publishes to devnet and writes its
|
|
19
23
|
`deployment.json` for the plugin; `npm run deploy -- create --network <name>` publishes to
|
|
20
24
|
testnet or devnet. At launch, commit the resulting `deployment.json` here as `<name>.json`.
|
|
21
25
|
|
package/deployments/testnet.json
CHANGED
|
@@ -17,20 +17,7 @@
|
|
|
17
17
|
"decimals": 6
|
|
18
18
|
}
|
|
19
19
|
],
|
|
20
|
-
"pools": [
|
|
21
|
-
{
|
|
22
|
-
"venue": "deepbook",
|
|
23
|
-
"poolId": "0xf95b10ec49e92a4afaa81ff679ebfd8b7e9371984d8c214b26783d9fdfc02a29",
|
|
24
|
-
"coinA": "0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI",
|
|
25
|
-
"coinB": "0x7ffc375a2bebedcec3753cfe4687f3bb104074eb55b014f8185ccc8ee8bf47fa::usdc::USDC"
|
|
26
|
-
},
|
|
27
|
-
{
|
|
28
|
-
"venue": "cetus",
|
|
29
|
-
"poolId": "0x3c779cab1582156a06aca223690bcd23f781ff3fbdda99747659ebddc2059e88",
|
|
30
|
-
"coinA": "0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI",
|
|
31
|
-
"coinB": "0x7ffc375a2bebedcec3753cfe4687f3bb104074eb55b014f8185ccc8ee8bf47fa::usdc::USDC"
|
|
32
|
-
}
|
|
33
|
-
],
|
|
20
|
+
"pools": [],
|
|
34
21
|
"demoFaucet": {
|
|
35
22
|
"packageId": "0x7ffc375a2bebedcec3753cfe4687f3bb104074eb55b014f8185ccc8ee8bf47fa",
|
|
36
23
|
"faucetId": "0x14d07fd3eff80c868c0bab116cbc2f65c8903c77fcb41721ad6db4ba0c6480cf",
|
|
@@ -54,16 +41,7 @@
|
|
|
54
41
|
"oracleId": "0xc962d8795540426c4dce1fea621d89f12f00766a6d4b0d00087fde6fefb2d343",
|
|
55
42
|
"incentiveV2Id": "0x679e3525405bb43ba27b0839dcaae2469d59225856cd6c2e8318a094efe593c5",
|
|
56
43
|
"incentiveV3Id": "0x9488d70edbfd67babcc72b8eb1f3fbf60dd47f080d830e2af27abcecdd6771c6",
|
|
57
|
-
"reserves": {
|
|
58
|
-
"0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI": {
|
|
59
|
-
"poolId": "0x3bdcd67ca6465324f0977d7912dbfb7a25cad759e03744aa760e0fa5baa31812",
|
|
60
|
-
"assetId": 0
|
|
61
|
-
},
|
|
62
|
-
"0x7ffc375a2bebedcec3753cfe4687f3bb104074eb55b014f8185ccc8ee8bf47fa::usdc::USDC": {
|
|
63
|
-
"poolId": "0x7f05ed3b912e6e1b573f8d3095cf3c437fb0fcf78d09669c504c66bceb3bf9a3",
|
|
64
|
-
"assetId": 1
|
|
65
|
-
}
|
|
66
|
-
}
|
|
44
|
+
"reserves": {}
|
|
67
45
|
}
|
|
68
46
|
}
|
|
69
47
|
}
|
package/dist/plugin.js
CHANGED
|
@@ -20,7 +20,7 @@ import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/
|
|
|
20
20
|
import { Transaction } from '@mysten/sui/transactions';
|
|
21
21
|
import { fromBase64, normalizeSuiAddress } from '@mysten/sui/utils';
|
|
22
22
|
import { z } from 'zod';
|
|
23
|
-
import { clientFor, deepbookSizes, readStatus, withMarketFacts } from './chain.js';
|
|
23
|
+
import { clientFor, deepbookSizes, quoteSwap, readStatus, withMarketFacts } from './chain.js';
|
|
24
24
|
import { describePolicy, describeSetup, renderRows } from './describe.js';
|
|
25
25
|
import { address, coinBySymbol, coinInfo, DAY_MS, defaultGasDaily, DeploymentSchema, display, poolsFor, priceUnits, recipientName, sameCoin, SetupSchema, showCoin, units, VenueSchema, } from './domain.js';
|
|
26
26
|
import { passesByAgent } from './explorer.js';
|
|
@@ -236,7 +236,7 @@ const rulesInput = {
|
|
|
236
236
|
.describe('pool object ids for a pair the deployment does not list (a DeepBook or Cetus pool holding exactly these two coins); verified on chain'),
|
|
237
237
|
perTrade: decimal.describe('sold coin per trade'),
|
|
238
238
|
daily: decimal.describe('sold coin per UTC day'),
|
|
239
|
-
minPrice: decimal.describe(
|
|
239
|
+
minPrice: decimal.describe("lowest price accepted, in bought coin per one sold coin; required, above 0. When the owner names no floor, 1% under the pool's current price (list_passes shows it) and say so"),
|
|
240
240
|
})
|
|
241
241
|
.strict())
|
|
242
242
|
.default([])
|
|
@@ -310,7 +310,9 @@ async function toSetup(client, d0, input) {
|
|
|
310
310
|
const pools = poolsFor(d, coinIn, coinOut).filter((p) => (!sw.venues || sw.venues.includes(p.venue)) &&
|
|
311
311
|
(!sw.pools || sw.pools.some((id) => normalizeSuiAddress(id) === p.poolId)));
|
|
312
312
|
if (!pools.length)
|
|
313
|
-
throw new Error(
|
|
313
|
+
throw new Error(d.pools.length
|
|
314
|
+
? `No pool trades ${sw.sell} for ${sw.buy}${sw.venues ? ` on ${sw.venues.join(', ')}` : ''}${sw.pools ? ` among ${sw.pools.join(', ')}` : ''}; name a DeepBook or Cetus pool id for this pair in pools`
|
|
315
|
+
: `Swaps are not offered on ${d.network}: it lists no pools. Propose a pass on a network that does, or leave swaps out`);
|
|
314
316
|
return {
|
|
315
317
|
coinIn,
|
|
316
318
|
coinOut,
|
|
@@ -320,13 +322,20 @@ async function toSetup(client, d0, input) {
|
|
|
320
322
|
minPrice: priceUnits(d, coinIn, coinOut, sw.minPrice),
|
|
321
323
|
};
|
|
322
324
|
}),
|
|
323
|
-
lending: input.lending.map((l) =>
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
325
|
+
lending: input.lending.map((l) => {
|
|
326
|
+
const type = coin(l.coin).type;
|
|
327
|
+
if (!d.protocols.navi.reserves[type])
|
|
328
|
+
throw new Error(Object.keys(d.protocols.navi.reserves).length
|
|
329
|
+
? `NAVI has no reserve for ${l.coin} on ${d.network}`
|
|
330
|
+
: `Lending is not offered on ${d.network}: it lists no NAVI reserves. Propose a pass on a network that does, or leave lending out`);
|
|
331
|
+
return {
|
|
332
|
+
coin: type,
|
|
333
|
+
allowBorrow: l.allowBorrow,
|
|
334
|
+
perAction: inUnits(l.coin, l.perAction),
|
|
335
|
+
daily: inUnits(l.coin, l.daily),
|
|
336
|
+
minHealthFactor: l.minHealthFactor,
|
|
337
|
+
};
|
|
338
|
+
}),
|
|
330
339
|
staking: input.staking && {
|
|
331
340
|
validators: input.staking.validators,
|
|
332
341
|
perStake: sui(input.staking.perStake),
|
|
@@ -407,14 +416,31 @@ export function createPluginMcp(registry) {
|
|
|
407
416
|
annotations: { readOnlyHint: true },
|
|
408
417
|
}, async () => {
|
|
409
418
|
const path = registry.deploymentPath();
|
|
419
|
+
// The pool's own price for ten units of coinA, so a floor can be sized from the market
|
|
420
|
+
// before any pass exists; ten clears DeepBook's minimum order where one may not.
|
|
421
|
+
const price = async (d, p) => {
|
|
422
|
+
const a = coinInfo(d, p.coinA), b = coinInfo(d, p.coinB);
|
|
423
|
+
const amountIn = (10n * 10n ** BigInt(a.decimals)).toString();
|
|
424
|
+
const q = await quoteSwap(clientFor(d), d, p, p.coinA, amountIn).catch(() => null);
|
|
425
|
+
if (!q || q.amountOut === '0')
|
|
426
|
+
return {};
|
|
427
|
+
const perUnit = (BigInt(q.amountOut) * 10n ** BigInt(a.decimals)) / BigInt(q.amountIn);
|
|
428
|
+
return { price: `${display(perUnit.toString(), b.decimals)} ${b.symbol} per ${a.symbol}` };
|
|
429
|
+
};
|
|
410
430
|
const markets = async (d) => ({
|
|
411
431
|
network: d.network,
|
|
412
432
|
coins: d.coins,
|
|
413
|
-
pools: d.pools.map((p) => ({
|
|
433
|
+
pools: await Promise.all(d.pools.map(async (p) => ({
|
|
414
434
|
venue: p.venue,
|
|
415
435
|
pair: `${coinInfo(d, p.coinA).symbol}/${coinInfo(d, p.coinB).symbol}`,
|
|
416
|
-
|
|
436
|
+
...(await price(d, p)),
|
|
437
|
+
}))),
|
|
417
438
|
lending: Object.keys(d.protocols.navi.reserves).map((c) => coinInfo(d, c).symbol),
|
|
439
|
+
...(d.pools.length || Object.keys(d.protocols.navi.reserves).length
|
|
440
|
+
? {}
|
|
441
|
+
: {
|
|
442
|
+
note: 'Transfers and staking only: this network lists no pools and no NAVI reserves, so swap and lending rules are refused here.',
|
|
443
|
+
}),
|
|
418
444
|
});
|
|
419
445
|
const own = (await exists(path)) ? [await markets(await registry.deployment())] : [];
|
|
420
446
|
const bundled = await Promise.all((await registry.bundledNetworks()).map(async (n) => markets(await registry.bundled(n))));
|
package/docs/PLAYBOOK.md
CHANGED
|
@@ -34,8 +34,10 @@ its type so the owner can tell a look-alike from the real one. Lending stays wit
|
|
|
34
34
|
network lists as NAVI reserves. About the sum of daily limits:
|
|
35
35
|
the chain checks the lifetime cap before the daily meter, so a cap equal to one day's limits
|
|
36
36
|
turns the owner's "daily limit" refusal into a "lifetime cap" one. Coins are named by symbol; `list_passes` shows
|
|
37
|
-
each network's coins, pools (which pairs trade where
|
|
38
|
-
pair direction or lending coin; a coin without a rule cannot
|
|
37
|
+
each network's coins, pools (which pairs trade where, with the pool's current price) and
|
|
38
|
+
lendable coins. One rule per coin, pair direction or lending coin; a coin without a rule cannot
|
|
39
|
+
be touched. A swap rule's `minPrice` is the owner's floor: when they name none, set it 1% under
|
|
40
|
+
the pool's current price and say so; a wider margin is theirs to ask for, not yours to assume.
|
|
39
41
|
|
|
40
42
|
| Rule set | Fields (each entry one rule) | What the chain enforces |
|
|
41
43
|
| ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|