@prismnetwork/agent-sdk 0.7.12 → 0.8.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 CHANGED
@@ -191,10 +191,27 @@ with `host_key_unpublished`.
191
191
 
192
192
  `lease()` (and the lower-level `fund()`) reproduce the escrow's quote binding: `clientReference = keccak256(quote_id)`, `approve(escrow, maximum_escrow)`, then `createLease(...)`, waiting 12 confirmations.
193
193
 
194
+ Pass `decision` and `policy` to `lease()` to authorise the spend first. The decision is checked against the policy before a quote is taken, and its hash is bound into the deposit: `clientReference = keccak256(keccak256(quote_id) ‖ decision_hash)`. Anyone holding the decision can recompute the reference and see it existed before the money moved. It does not show the decision was right. The helpers live in `@prismnetwork/agent-sdk/decision`.
195
+
194
196
  ## Funding
195
197
 
196
198
  The wallet needs two balances on Robinhood Chain (id 4663): USDG (`0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168`, 6 decimals) for the lease deposit, and native ETH for gas. Bridge from L1 to fund a fresh wallet. `authenticate()`, `offers()`, and `quote()` need neither, so the read paths work before you fund anything.
197
199
 
200
+ ## Prism Chain
201
+
202
+ Prism Chain (id 77476) is the Layer 3 for GPU compute, settled on Robinhood Chain. `@prismnetwork/agent-sdk/chain` exports the chain for viem and the bridge helpers:
203
+
204
+ ```js
205
+ import { depositToken, prismChain, withdraw } from "@prismnetwork/agent-sdk/chain";
206
+
207
+ // Robinhood Chain → Prism Chain, arrives in about a minute.
208
+ await depositToken(robinhoodWallet, USDG, 5_000_000n);
209
+ // Prism Chain → Robinhood Chain, claimable there after about a day.
210
+ await withdraw(prismWallet, 1_000_000n, { token: USDG });
211
+ ```
212
+
213
+ `depositEth` moves ETH the same way. Claim a finished withdrawal at [bridge.prismnetwork.tech](https://bridge.prismnetwork.tech). Leases still fund and settle on Robinhood Chain.
214
+
198
215
  ## Requirements
199
216
 
200
217
  Node >= 20, `viem` ^2 (peer), and `ssh`, `ssh-keygen` and `ssh-keyscan` on PATH
package/chain.d.mts ADDED
@@ -0,0 +1,32 @@
1
+ import type { Address, Chain, Hash, WalletClient } from "viem";
2
+
3
+ export declare const prismChain: Chain;
4
+ export declare const PRISM_CHAIN_BRIDGE_URL: string;
5
+ export declare const prismChainContracts: {
6
+ rollup: Address;
7
+ inbox: Address;
8
+ outbox: Address;
9
+ parentRouter: Address;
10
+ parentStandardGateway: Address;
11
+ childRouter: Address;
12
+ arbSys: Address;
13
+ };
14
+
15
+ export interface TokenDepositFees {
16
+ maxGas: bigint;
17
+ gasPriceBid: bigint;
18
+ maxSubmissionCost: bigint;
19
+ /** Wei of ETH sent with the deposit; the unused part is refunded on Prism Chain. */
20
+ value: bigint;
21
+ }
22
+
23
+ interface RpcOptions {
24
+ parentRpcUrl?: string;
25
+ childRpcUrl?: string;
26
+ }
27
+
28
+ export declare function prismChainToken(token: Address, options?: { rpcUrl?: string }): Promise<Address>;
29
+ export declare function tokenDepositFees(token: Address, options?: RpcOptions): Promise<TokenDepositFees>;
30
+ export declare function depositEth(wallet: WalletClient, amount: bigint): Promise<Hash>;
31
+ export declare function depositToken(wallet: WalletClient, token: Address, amount: bigint, options?: RpcOptions): Promise<Hash>;
32
+ export declare function withdraw(wallet: WalletClient, amount: bigint, options?: { token?: Address | null }): Promise<Hash>;
package/chain.mjs ADDED
@@ -0,0 +1,163 @@
1
+ /// Prism Chain: the Layer 3 for GPU compute, settled on Robinhood Chain.
2
+ ///
3
+ /// Assets reach it through the canonical Arbitrum token bridge. A deposit lands
4
+ /// on Prism Chain in about a minute. A withdrawal starts on Prism Chain,
5
+ /// finalizes on Robinhood Chain after the rollup's confirmation window (about a
6
+ /// day), and is then claimed there; https://bridge.prismnetwork.tech does the
7
+ /// claim. Leases still settle on Robinhood Chain today.
8
+ import { createPublicClient, defineChain, encodeAbiParameters, erc20Abi, http, parseAbi } from "viem";
9
+
10
+ // Kept here rather than imported from prism.mjs, which pulls in Node modules;
11
+ // this file stays usable in a browser.
12
+ const robinhoodChain = defineChain({
13
+ id: 4663,
14
+ name: "Robinhood Chain",
15
+ nativeCurrency: { name: "Ether", symbol: "ETH", decimals: 18 },
16
+ rpcUrls: { default: { http: ["https://rpc.mainnet.chain.robinhood.com"] } },
17
+ });
18
+
19
+ export const prismChain = defineChain({
20
+ id: 77476,
21
+ name: "Prism Chain",
22
+ nativeCurrency: { name: "Ether", symbol: "ETH", decimals: 18 },
23
+ rpcUrls: {
24
+ default: { http: ["https://rpc.prismnetwork.tech"], webSocket: ["wss://ws.prismnetwork.tech"] },
25
+ },
26
+ blockExplorers: { default: { name: "Prism Chain explorer", url: "https://explorer.prismnetwork.tech" } },
27
+ sourceId: robinhoodChain.id,
28
+ });
29
+
30
+ export const PRISM_CHAIN_BRIDGE_URL = "https://bridge.prismnetwork.tech";
31
+
32
+ /// The rollup on Robinhood Chain and both halves of the token bridge.
33
+ export const prismChainContracts = {
34
+ rollup: "0x8232Ce617E7F1031F5B7bdcD72678dbdF2fDafeB",
35
+ inbox: "0x2FbD2fF90f56C58A8789Fc56e8b31F26e660438f",
36
+ outbox: "0x8cC14bF09cE7a1bf2415C70E5E4B9f50cD4a889d",
37
+ parentRouter: "0x52f5aF48C1DF13E0e1ABbe04F99622aabF6B2CD2",
38
+ parentStandardGateway: "0x1274b56aE5566014bB73dfE0A2247ab5BbC96470",
39
+ childRouter: "0x12d1c6c0b4b97278A7E2961eF16105Ba2dd2e859",
40
+ arbSys: "0x0000000000000000000000000000000000000064",
41
+ };
42
+
43
+ const inboxAbi = parseAbi([
44
+ "function depositEth() payable returns (uint256)",
45
+ "function calculateRetryableSubmissionFee(uint256 dataLength, uint256 baseFee) view returns (uint256)",
46
+ ]);
47
+ const parentRouterAbi = parseAbi([
48
+ "function getGateway(address token) view returns (address)",
49
+ "function outboundTransferCustomRefund(address token, address refundTo, address to, uint256 amount, uint256 maxGas, uint256 gasPriceBid, bytes data) payable returns (bytes)",
50
+ ]);
51
+ const childRouterAbi = parseAbi([
52
+ "function calculateL2TokenAddress(address l1Token) view returns (address)",
53
+ "function outboundTransfer(address l1Token, address to, uint256 amount, bytes data) payable returns (bytes)",
54
+ ]);
55
+ const arbSysAbi = parseAbi(["function withdrawEth(address destination) payable returns (uint256)"]);
56
+
57
+ const parent = (rpcUrl) => createPublicClient({ chain: robinhoodChain, transport: http(rpcUrl) });
58
+ const child = (rpcUrl) => createPublicClient({ chain: prismChain, transport: http(rpcUrl) });
59
+
60
+ /// Where a Robinhood Chain token lives on Prism Chain. Its contract exists once
61
+ /// the first deposit of that token has landed.
62
+ export function prismChainToken(token, { rpcUrl } = {}) {
63
+ return child(rpcUrl).readContract({
64
+ address: prismChainContracts.childRouter,
65
+ abi: childRouterAbi,
66
+ functionName: "calculateL2TokenAddress",
67
+ args: [token],
68
+ });
69
+ }
70
+
71
+ /// What a token deposit prepays for its call on Prism Chain, in wei of ETH on
72
+ /// Robinhood Chain. The first deposit of a token also deploys its contract
73
+ /// there, which needs more gas. Whatever goes unused is refunded to the sender
74
+ /// on Prism Chain, so this is a ceiling, not a price.
75
+ export async function tokenDepositFees(token, { parentRpcUrl, childRpcUrl } = {}) {
76
+ const [block, childGasPrice, deployed] = await Promise.all([
77
+ parent(parentRpcUrl).getBlock(),
78
+ child(childRpcUrl).getGasPrice(),
79
+ prismChainToken(token, { rpcUrl: childRpcUrl }).then((address) => child(childRpcUrl).getCode({ address })),
80
+ ]);
81
+ const maxGas = deployed && deployed !== "0x" ? 300_000n : 1_200_000n;
82
+ const gasPriceBid = childGasPrice * 2n;
83
+ const submission = await parent(parentRpcUrl).readContract({
84
+ address: prismChainContracts.inbox,
85
+ abi: inboxAbi,
86
+ functionName: "calculateRetryableSubmissionFee",
87
+ args: [2_000n, block.baseFeePerGas ?? 0n],
88
+ });
89
+ const maxSubmissionCost = submission * 4n;
90
+ return { maxGas, gasPriceBid, maxSubmissionCost, value: maxSubmissionCost + maxGas * gasPriceBid };
91
+ }
92
+
93
+ /// Move ETH from Robinhood Chain to the same address on Prism Chain. `wallet`
94
+ /// is a viem wallet client on Robinhood Chain. Returns the Robinhood Chain
95
+ /// transaction hash.
96
+ export function depositEth(wallet, amount) {
97
+ return wallet.writeContract({
98
+ chain: robinhoodChain,
99
+ address: prismChainContracts.inbox,
100
+ abi: inboxAbi,
101
+ functionName: "depositEth",
102
+ value: amount,
103
+ });
104
+ }
105
+
106
+ /// Move an ERC-20 such as USDG from Robinhood Chain to the same address on
107
+ /// Prism Chain. Approves the token's gateway first when the allowance is short.
108
+ export async function depositToken(wallet, token, amount, { parentRpcUrl, childRpcUrl } = {}) {
109
+ const account = wallet.account.address;
110
+ const reader = parent(parentRpcUrl);
111
+ const gateway = await reader.readContract({
112
+ address: prismChainContracts.parentRouter,
113
+ abi: parentRouterAbi,
114
+ functionName: "getGateway",
115
+ args: [token],
116
+ });
117
+ const allowance = await reader.readContract({ address: token, abi: erc20Abi, functionName: "allowance", args: [account, gateway] });
118
+ if (allowance < amount) {
119
+ const approval = await wallet.writeContract({
120
+ chain: robinhoodChain,
121
+ address: token,
122
+ abi: erc20Abi,
123
+ functionName: "approve",
124
+ args: [gateway, amount],
125
+ });
126
+ await reader.waitForTransactionReceipt({ hash: approval });
127
+ }
128
+ const fees = await tokenDepositFees(token, { parentRpcUrl, childRpcUrl });
129
+ const data = encodeAbiParameters([{ type: "uint256" }, { type: "bytes" }], [fees.maxSubmissionCost, "0x"]);
130
+ return wallet.writeContract({
131
+ chain: robinhoodChain,
132
+ address: prismChainContracts.parentRouter,
133
+ abi: parentRouterAbi,
134
+ functionName: "outboundTransferCustomRefund",
135
+ args: [token, account, account, amount, fees.maxGas, fees.gasPriceBid, data],
136
+ value: fees.value,
137
+ });
138
+ }
139
+
140
+ /// Start moving ETH, or a bridged token given by its Robinhood Chain address,
141
+ /// back to Robinhood Chain. `wallet` is a viem wallet client on Prism Chain.
142
+ /// The withdrawal is claimable on Robinhood Chain after about a day, at
143
+ /// PRISM_CHAIN_BRIDGE_URL. Returns the Prism Chain transaction hash.
144
+ export function withdraw(wallet, amount, { token = null } = {}) {
145
+ const account = wallet.account.address;
146
+ if (!token) {
147
+ return wallet.writeContract({
148
+ chain: prismChain,
149
+ address: prismChainContracts.arbSys,
150
+ abi: arbSysAbi,
151
+ functionName: "withdrawEth",
152
+ args: [account],
153
+ value: amount,
154
+ });
155
+ }
156
+ return wallet.writeContract({
157
+ chain: prismChain,
158
+ address: prismChainContracts.childRouter,
159
+ abi: childRouterAbi,
160
+ functionName: "outboundTransfer",
161
+ args: [token, account, amount, "0x"],
162
+ });
163
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prismnetwork/agent-sdk",
3
- "version": "0.7.12",
3
+ "version": "0.8.0",
4
4
  "description": "Headless GPU leasing and renter-encrypted storage on Prism Network for wallet-holding agents.",
5
5
  "type": "module",
6
6
  "main": "prism.mjs",
@@ -9,6 +9,10 @@
9
9
  "types": "./prism.d.mts",
10
10
  "default": "./prism.mjs"
11
11
  },
12
+ "./chain": {
13
+ "types": "./chain.d.mts",
14
+ "default": "./chain.mjs"
15
+ },
12
16
  "./decision": {
13
17
  "default": "./decision.mjs"
14
18
  },
@@ -40,6 +44,8 @@
40
44
  "files": [
41
45
  "prism.mjs",
42
46
  "prism.d.mts",
47
+ "chain.mjs",
48
+ "chain.d.mts",
43
49
  "attest.mjs",
44
50
  "attest.d.mts",
45
51
  "decision.mjs",
package/prism.d.mts CHANGED
@@ -1,6 +1,7 @@
1
1
  import type { AttestationResult, VerifyConfidentialOptions, WorkloadPin } from "./attest.d.mts";
2
2
 
3
3
  export declare const robinhoodChain: unknown;
4
+ export { PRISM_CHAIN_BRIDGE_URL, prismChain, prismChainContracts } from "./chain.d.mts";
4
5
  export declare const USDG: string;
5
6
  export declare const DEFAULT_IMAGE: string;
6
7
  export declare const TRUST_CLASSES: readonly ["open", "isolated", "attested", "confidential"];
package/prism.mjs CHANGED
@@ -15,6 +15,7 @@ import {
15
15
  stringToBytes,
16
16
  } from "viem";
17
17
  import { privateKeyToAccount } from "viem/accounts";
18
+ export { PRISM_CHAIN_BRIDGE_URL, prismChain, prismChainContracts } from "./chain.mjs";
18
19
  import { appraiseWorkload, DEFAULT_CONFIDENTIAL_BASE, EXPECTED_WORKLOAD, verifyConfidential } from "./attest.mjs";
19
20
  import { decryptResponse, encryptChatRequest } from "./e2ee.mjs";
20
21
  import { hostKeyArgs, HostKeyError } from "./hostkey.mjs";