mppx 0.6.30 → 0.7.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/CHANGELOG.md +25 -0
- package/dist/Challenge.d.ts.map +1 -1
- package/dist/Challenge.js +9 -7
- package/dist/Challenge.js.map +1 -1
- package/dist/Constants.d.ts +46 -0
- package/dist/Constants.d.ts.map +1 -0
- package/dist/Constants.js +46 -0
- package/dist/Constants.js.map +1 -0
- package/dist/Credential.d.ts.map +1 -1
- package/dist/Credential.js +5 -4
- package/dist/Credential.js.map +1 -1
- package/dist/Method.d.ts +32 -4
- package/dist/Method.d.ts.map +1 -1
- package/dist/Method.js +5 -2
- package/dist/Method.js.map +1 -1
- package/dist/Receipt.d.ts.map +1 -1
- package/dist/Receipt.js +3 -2
- package/dist/Receipt.js.map +1 -1
- package/dist/cli/cli.d.ts.map +1 -1
- package/dist/cli/cli.js +19 -11
- package/dist/cli/cli.js.map +1 -1
- package/dist/cli/plugins/tempo.d.ts.map +1 -1
- package/dist/cli/plugins/tempo.js +17 -6
- package/dist/cli/plugins/tempo.js.map +1 -1
- package/dist/cli/utils.d.ts +5 -0
- package/dist/cli/utils.d.ts.map +1 -1
- package/dist/cli/utils.js +10 -0
- package/dist/cli/utils.js.map +1 -1
- package/dist/client/Methods.d.ts +5 -2
- package/dist/client/Methods.d.ts.map +1 -1
- package/dist/client/Methods.js +5 -2
- package/dist/client/Methods.js.map +1 -1
- package/dist/client/Transport.d.ts.map +1 -1
- package/dist/client/Transport.js +4 -5
- package/dist/client/Transport.js.map +1 -1
- package/dist/client/index.d.ts +2 -1
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +2 -1
- package/dist/client/index.js.map +1 -1
- package/dist/client/internal/Fetch.d.ts.map +1 -1
- package/dist/client/internal/Fetch.js +14 -6
- package/dist/client/internal/Fetch.js.map +1 -1
- package/dist/evm/server/Methods.d.ts +1 -1
- package/dist/evm/server/Methods.d.ts.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/internal/AcceptPayment.d.ts +3 -0
- package/dist/internal/AcceptPayment.d.ts.map +1 -1
- package/dist/internal/AcceptPayment.js +15 -11
- package/dist/internal/AcceptPayment.js.map +1 -1
- package/dist/mcp-sdk/client/McpClient.d.ts +12 -5
- package/dist/mcp-sdk/client/McpClient.d.ts.map +1 -1
- package/dist/mcp-sdk/client/McpClient.js +55 -42
- package/dist/mcp-sdk/client/McpClient.js.map +1 -1
- package/dist/server/Mppx.d.ts +11 -3
- package/dist/server/Mppx.d.ts.map +1 -1
- package/dist/server/Mppx.js +76 -27
- package/dist/server/Mppx.js.map +1 -1
- package/dist/server/Request.js +24 -10
- package/dist/server/Request.js.map +1 -1
- package/dist/server/Response.d.ts.map +1 -1
- package/dist/server/Response.js +2 -1
- package/dist/server/Response.js.map +1 -1
- package/dist/server/Transport.d.ts.map +1 -1
- package/dist/server/Transport.js +4 -3
- package/dist/server/Transport.js.map +1 -1
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +1 -0
- package/dist/server/index.js.map +1 -1
- package/dist/stripe/client/Charge.d.ts +1 -1
- package/dist/stripe/client/Charge.d.ts.map +1 -1
- package/dist/stripe/client/Charge.js +3 -1
- package/dist/stripe/client/Charge.js.map +1 -1
- package/dist/stripe/server/Charge.d.ts +1 -1
- package/dist/stripe/server/Charge.d.ts.map +1 -1
- package/dist/stripe/server/Charge.js +9 -2
- package/dist/stripe/server/Charge.js.map +1 -1
- package/dist/stripe/server/Methods.d.ts +1 -1
- package/dist/stripe/server/Methods.d.ts.map +1 -1
- package/dist/stripe/server/internal/html.gen.d.ts +1 -1
- package/dist/stripe/server/internal/html.gen.d.ts.map +1 -1
- package/dist/stripe/server/internal/html.gen.js +1 -1
- package/dist/stripe/server/internal/html.gen.js.map +1 -1
- package/dist/tempo/Methods.d.ts +18 -0
- package/dist/tempo/Methods.d.ts.map +1 -1
- package/dist/tempo/Methods.js +16 -1
- package/dist/tempo/Methods.js.map +1 -1
- package/dist/tempo/client/Charge.d.ts +6 -0
- package/dist/tempo/client/Charge.d.ts.map +1 -1
- package/dist/tempo/client/Charge.js +9 -2
- package/dist/tempo/client/Charge.js.map +1 -1
- package/dist/tempo/client/Methods.d.ts +36 -7
- package/dist/tempo/client/Methods.d.ts.map +1 -1
- package/dist/tempo/client/Methods.js +12 -5
- package/dist/tempo/client/Methods.js.map +1 -1
- package/dist/tempo/client/index.d.ts +7 -4
- package/dist/tempo/client/index.d.ts.map +1 -1
- package/dist/tempo/client/index.js +5 -3
- package/dist/tempo/client/index.js.map +1 -1
- package/dist/tempo/index.d.ts +1 -0
- package/dist/tempo/index.d.ts.map +1 -1
- package/dist/tempo/index.js +1 -0
- package/dist/tempo/index.js.map +1 -1
- package/dist/tempo/internal/fee-payer.d.ts +21 -1
- package/dist/tempo/internal/fee-payer.d.ts.map +1 -1
- package/dist/tempo/internal/fee-payer.js +109 -4
- package/dist/tempo/internal/fee-payer.js.map +1 -1
- package/dist/tempo/{client → legacy/client}/ChannelOps.d.ts +19 -6
- package/dist/tempo/legacy/client/ChannelOps.d.ts.map +1 -0
- package/dist/tempo/{client → legacy/client}/ChannelOps.js +9 -3
- package/dist/tempo/legacy/client/ChannelOps.js.map +1 -0
- package/dist/tempo/{client → legacy/client}/Session.d.ts +23 -4
- package/dist/tempo/legacy/client/Session.d.ts.map +1 -0
- package/dist/tempo/{client → legacy/client}/Session.js +14 -7
- package/dist/tempo/legacy/client/Session.js.map +1 -0
- package/dist/tempo/{client → legacy/client}/SessionManager.d.ts +20 -5
- package/dist/tempo/legacy/client/SessionManager.d.ts.map +1 -0
- package/dist/tempo/{client → legacy/client}/SessionManager.js +20 -16
- package/dist/tempo/legacy/client/SessionManager.js.map +1 -0
- package/dist/tempo/legacy/client/index.d.ts +7 -0
- package/dist/tempo/legacy/client/index.d.ts.map +1 -0
- package/dist/tempo/legacy/client/index.js +5 -0
- package/dist/tempo/legacy/client/index.js.map +1 -0
- package/dist/tempo/legacy/index.d.ts +7 -0
- package/dist/tempo/legacy/index.d.ts.map +1 -0
- package/dist/tempo/legacy/index.js +7 -0
- package/dist/tempo/legacy/index.js.map +1 -0
- package/dist/tempo/{server → legacy/server}/Session.d.ts +28 -11
- package/dist/tempo/legacy/server/Session.d.ts.map +1 -0
- package/dist/tempo/{server → legacy/server}/Session.js +28 -23
- package/dist/tempo/legacy/server/Session.js.map +1 -0
- package/dist/tempo/legacy/server/index.d.ts +5 -0
- package/dist/tempo/legacy/server/index.d.ts.map +1 -0
- package/dist/tempo/legacy/server/index.js +5 -0
- package/dist/tempo/legacy/server/index.js.map +1 -0
- package/dist/tempo/{session → legacy/session}/Chain.d.ts +30 -23
- package/dist/tempo/legacy/session/Chain.d.ts.map +1 -0
- package/dist/tempo/{session → legacy/session}/Chain.js +12 -11
- package/dist/tempo/legacy/session/Chain.js.map +1 -0
- package/dist/tempo/{session → legacy/session}/Channel.d.ts +1 -0
- package/dist/tempo/legacy/session/Channel.d.ts.map +1 -0
- package/dist/tempo/legacy/session/Channel.js.map +1 -0
- package/dist/tempo/legacy/session/ChannelStore.d.ts +22 -0
- package/dist/tempo/legacy/session/ChannelStore.d.ts.map +1 -0
- package/dist/tempo/legacy/session/ChannelStore.js +6 -0
- package/dist/tempo/legacy/session/ChannelStore.js.map +1 -0
- package/dist/tempo/legacy/session/Types.d.ts +73 -0
- package/dist/tempo/legacy/session/Types.d.ts.map +1 -0
- package/dist/tempo/legacy/session/Types.js.map +1 -0
- package/dist/tempo/{session → legacy/session}/Voucher.d.ts +4 -4
- package/dist/tempo/legacy/session/Voucher.d.ts.map +1 -0
- package/dist/tempo/{session → legacy/session}/Voucher.js +1 -1
- package/dist/tempo/legacy/session/Voucher.js.map +1 -0
- package/dist/tempo/{session → legacy/session}/escrow.abi.d.ts +1 -0
- package/dist/tempo/{session → legacy/session}/escrow.abi.d.ts.map +1 -1
- package/dist/tempo/{session → legacy/session}/escrow.abi.js +1 -0
- package/dist/tempo/legacy/session/escrow.abi.js.map +1 -0
- package/dist/tempo/legacy/session/index.d.ts +9 -0
- package/dist/tempo/legacy/session/index.d.ts.map +1 -0
- package/dist/tempo/legacy/session/index.js +9 -0
- package/dist/tempo/legacy/session/index.js.map +1 -0
- package/dist/tempo/server/Charge.d.ts +1 -1
- package/dist/tempo/server/Charge.d.ts.map +1 -1
- package/dist/tempo/server/Charge.js +13 -16
- package/dist/tempo/server/Charge.js.map +1 -1
- package/dist/tempo/server/Methods.d.ts +63 -6
- package/dist/tempo/server/Methods.d.ts.map +1 -1
- package/dist/tempo/server/Methods.js +36 -8
- package/dist/tempo/server/Methods.js.map +1 -1
- package/dist/tempo/server/Subscription.d.ts +1 -1
- package/dist/tempo/server/Subscription.d.ts.map +1 -1
- package/dist/tempo/server/index.d.ts +6 -5
- package/dist/tempo/server/index.d.ts.map +1 -1
- package/dist/tempo/server/index.js +5 -5
- package/dist/tempo/server/index.js.map +1 -1
- package/dist/tempo/server/internal/html.gen.d.ts +1 -1
- package/dist/tempo/server/internal/html.gen.d.ts.map +1 -1
- package/dist/tempo/server/internal/html.gen.js +1 -1
- package/dist/tempo/server/internal/html.gen.js.map +1 -1
- package/dist/tempo/server/internal/request-body.d.ts +7 -2
- package/dist/tempo/server/internal/request-body.d.ts.map +1 -1
- package/dist/tempo/server/internal/request-body.js +20 -3
- package/dist/tempo/server/internal/request-body.js.map +1 -1
- package/dist/tempo/server/internal/transport.d.ts +8 -4
- package/dist/tempo/server/internal/transport.d.ts.map +1 -1
- package/dist/tempo/server/internal/transport.js +8 -7
- package/dist/tempo/server/internal/transport.js.map +1 -1
- package/dist/tempo/session/Snapshot.d.ts +32 -0
- package/dist/tempo/session/Snapshot.d.ts.map +1 -0
- package/dist/tempo/session/Snapshot.js +37 -0
- package/dist/tempo/session/Snapshot.js.map +1 -0
- package/dist/tempo/session/client/ChannelOps.d.ts +82 -0
- package/dist/tempo/session/client/ChannelOps.d.ts.map +1 -0
- package/dist/tempo/session/client/ChannelOps.js +204 -0
- package/dist/tempo/session/client/ChannelOps.js.map +1 -0
- package/dist/tempo/session/client/CredentialState.d.ts +262 -0
- package/dist/tempo/session/client/CredentialState.d.ts.map +1 -0
- package/dist/tempo/session/client/CredentialState.js +417 -0
- package/dist/tempo/session/client/CredentialState.js.map +1 -0
- package/dist/tempo/session/client/ReceiptCoordinator.d.ts +26 -0
- package/dist/tempo/session/client/ReceiptCoordinator.d.ts.map +1 -0
- package/dist/tempo/session/client/ReceiptCoordinator.js +61 -0
- package/dist/tempo/session/client/ReceiptCoordinator.js.map +1 -0
- package/dist/tempo/session/client/Runtime.d.ts +464 -0
- package/dist/tempo/session/client/Runtime.d.ts.map +1 -0
- package/dist/tempo/session/client/Runtime.js +499 -0
- package/dist/tempo/session/client/Runtime.js.map +1 -0
- package/dist/tempo/session/client/Session.d.ts +132 -0
- package/dist/tempo/session/client/Session.d.ts.map +1 -0
- package/dist/tempo/session/client/Session.js +55 -0
- package/dist/tempo/session/client/Session.js.map +1 -0
- package/dist/tempo/session/client/SessionManager.d.ts +120 -0
- package/dist/tempo/session/client/SessionManager.d.ts.map +1 -0
- package/dist/tempo/session/client/SessionManager.js +627 -0
- package/dist/tempo/session/client/SessionManager.js.map +1 -0
- package/dist/tempo/session/client/Transports.d.ts +449 -0
- package/dist/tempo/session/client/Transports.d.ts.map +1 -0
- package/dist/tempo/session/client/Transports.js +721 -0
- package/dist/tempo/session/client/Transports.js.map +1 -0
- package/dist/tempo/session/client/index.d.ts +12 -0
- package/dist/tempo/session/client/index.d.ts.map +1 -0
- package/dist/tempo/session/client/index.js +5 -0
- package/dist/tempo/session/client/index.js.map +1 -0
- package/dist/tempo/session/index.d.ts +7 -8
- package/dist/tempo/session/index.d.ts.map +1 -1
- package/dist/tempo/session/index.js +7 -8
- package/dist/tempo/session/index.js.map +1 -1
- package/dist/tempo/session/precompile/Chain.d.ts +319 -0
- package/dist/tempo/session/precompile/Chain.d.ts.map +1 -0
- package/dist/tempo/session/precompile/Chain.js +492 -0
- package/dist/tempo/session/precompile/Chain.js.map +1 -0
- package/dist/tempo/session/precompile/Channel.d.ts +46 -0
- package/dist/tempo/session/precompile/Channel.d.ts.map +1 -0
- package/dist/tempo/session/precompile/Channel.js +56 -0
- package/dist/tempo/session/precompile/Channel.js.map +1 -0
- package/dist/tempo/session/precompile/Protocol.d.ts +308 -0
- package/dist/tempo/session/precompile/Protocol.d.ts.map +1 -0
- package/dist/tempo/session/precompile/Protocol.js +264 -0
- package/dist/tempo/session/precompile/Protocol.js.map +1 -0
- package/dist/tempo/session/precompile/Voucher.d.ts +40 -0
- package/dist/tempo/session/precompile/Voucher.d.ts.map +1 -0
- package/dist/tempo/session/precompile/Voucher.js +126 -0
- package/dist/tempo/session/precompile/Voucher.js.map +1 -0
- package/dist/tempo/session/precompile/escrow.abi.d.ts +522 -0
- package/dist/tempo/session/precompile/escrow.abi.d.ts.map +1 -0
- package/dist/tempo/session/precompile/escrow.abi.js +224 -0
- package/dist/tempo/session/precompile/escrow.abi.js.map +1 -0
- package/dist/tempo/session/precompile/index.d.ts +24 -0
- package/dist/tempo/session/precompile/index.d.ts.map +1 -0
- package/dist/tempo/session/precompile/index.js +22 -0
- package/dist/tempo/session/precompile/index.js.map +1 -0
- package/dist/tempo/session/server/ChannelOps.d.ts +56 -0
- package/dist/tempo/session/server/ChannelOps.d.ts.map +1 -0
- package/dist/tempo/session/server/ChannelOps.js +91 -0
- package/dist/tempo/session/server/ChannelOps.js.map +1 -0
- package/dist/tempo/session/server/ChannelStore.d.ts +347 -0
- package/dist/tempo/session/server/ChannelStore.d.ts.map +1 -0
- package/dist/tempo/session/server/ChannelStore.js +404 -0
- package/dist/tempo/session/server/ChannelStore.js.map +1 -0
- package/dist/tempo/session/server/CredentialVerification.d.ts +85 -0
- package/dist/tempo/session/server/CredentialVerification.d.ts.map +1 -0
- package/dist/tempo/session/server/CredentialVerification.js +494 -0
- package/dist/tempo/session/server/CredentialVerification.js.map +1 -0
- package/dist/tempo/session/server/MeteredStream.d.ts +40 -0
- package/dist/tempo/session/server/MeteredStream.d.ts.map +1 -0
- package/dist/tempo/session/server/MeteredStream.js +42 -0
- package/dist/tempo/session/server/MeteredStream.js.map +1 -0
- package/dist/tempo/session/server/RequestState.d.ts +208 -0
- package/dist/tempo/session/server/RequestState.d.ts.map +1 -0
- package/dist/tempo/session/server/RequestState.js +252 -0
- package/dist/tempo/session/server/RequestState.js.map +1 -0
- package/dist/tempo/session/server/Session.d.ts +169 -0
- package/dist/tempo/session/server/Session.d.ts.map +1 -0
- package/dist/tempo/session/server/Session.js +351 -0
- package/dist/tempo/session/server/Session.js.map +1 -0
- package/dist/tempo/session/server/Settlement.d.ts +185 -0
- package/dist/tempo/session/server/Settlement.d.ts.map +1 -0
- package/dist/tempo/session/server/Settlement.js +250 -0
- package/dist/tempo/session/server/Settlement.js.map +1 -0
- package/dist/tempo/session/{Sse.d.ts → server/Sse.d.ts} +9 -56
- package/dist/tempo/session/server/Sse.d.ts.map +1 -0
- package/dist/tempo/session/server/Sse.js +184 -0
- package/dist/tempo/session/server/Sse.js.map +1 -0
- package/dist/tempo/session/server/Transports.d.ts +89 -0
- package/dist/tempo/session/server/Transports.d.ts.map +1 -0
- package/dist/tempo/session/server/Transports.js +149 -0
- package/dist/tempo/session/server/Transports.js.map +1 -0
- package/dist/tempo/session/server/Ws.d.ts +48 -0
- package/dist/tempo/session/server/Ws.d.ts.map +1 -0
- package/dist/tempo/session/server/Ws.js +244 -0
- package/dist/tempo/session/server/Ws.js.map +1 -0
- package/dist/tempo/session/server/index.d.ts +4 -0
- package/dist/tempo/session/server/index.d.ts.map +1 -0
- package/dist/tempo/session/server/index.js +2 -0
- package/dist/tempo/session/server/index.js.map +1 -0
- package/package.json +8 -3
- package/src/Challenge.ts +9 -7
- package/src/Constants.ts +58 -0
- package/src/Credential.ts +5 -4
- package/src/Method.ts +46 -5
- package/src/Receipt.ts +3 -2
- package/src/cli/cli.test.ts +23 -28
- package/src/cli/cli.ts +23 -10
- package/src/cli/mcp.test.ts +21 -7
- package/src/cli/plugins/tempo.ts +21 -8
- package/src/cli/utils.test.ts +25 -1
- package/src/cli/utils.ts +10 -0
- package/src/client/Methods.ts +5 -2
- package/src/client/Mppx.test-d.ts +10 -0
- package/src/client/Mppx.test.ts +75 -0
- package/src/client/Transport.ts +4 -5
- package/src/client/index.ts +11 -1
- package/src/client/internal/Fetch.test.ts +29 -4
- package/src/client/internal/Fetch.ts +17 -5
- package/src/env.d.ts +1 -1
- package/src/index.ts +1 -0
- package/src/internal/AcceptPayment.test.ts +61 -0
- package/src/internal/AcceptPayment.ts +21 -14
- package/src/mcp-sdk/client/McpClient.integration.test.ts +8 -7
- package/src/mcp-sdk/client/McpClient.test-d.ts +7 -0
- package/src/mcp-sdk/client/McpClient.ts +99 -67
- package/src/mcp-sdk/client/McpClient.unit.test.ts +131 -0
- package/src/middlewares/elysia.test.ts +8 -4
- package/src/middlewares/express.test.ts +8 -4
- package/src/middlewares/hono.test.ts +4 -4
- package/src/middlewares/nextjs.test.ts +8 -4
- package/src/proxy/Proxy.test.ts +8 -8
- package/src/server/Mppx.test-d.ts +54 -0
- package/src/server/Mppx.test.ts +274 -7
- package/src/server/Mppx.ts +487 -406
- package/src/server/Request.test.ts +81 -0
- package/src/server/Request.ts +23 -9
- package/src/server/Response.ts +2 -1
- package/src/server/Transport.ts +4 -3
- package/src/server/index.ts +1 -0
- package/src/stripe/client/Charge.test.ts +20 -5
- package/src/stripe/client/Charge.ts +6 -2
- package/src/stripe/server/Charge.test.ts +114 -1
- package/src/stripe/server/Charge.ts +13 -2
- package/src/stripe/server/internal/html/package.json +1 -1
- package/src/stripe/server/internal/html.gen.ts +1 -1
- package/src/tempo/AccessKeyAuthorization.test.ts +4 -94
- package/src/tempo/Methods.test.ts +45 -17
- package/src/tempo/Methods.ts +22 -0
- package/src/tempo/PublicExports.test-d.ts +105 -0
- package/src/tempo/client/Charge.test.ts +85 -0
- package/src/tempo/client/Charge.ts +19 -2
- package/src/tempo/client/Methods.ts +18 -6
- package/src/tempo/client/index.ts +15 -4
- package/src/tempo/index.ts +1 -0
- package/src/tempo/internal/fee-payer.test.ts +241 -17
- package/src/tempo/internal/fee-payer.ts +150 -4
- package/src/tempo/internal/fee-token.test.ts +14 -9
- package/src/tempo/legacy/AccessKeyAuthorization.test.ts +162 -0
- package/src/tempo/legacy/README.md +9 -0
- package/src/tempo/{client → legacy/client}/ChannelOps.test.ts +6 -7
- package/src/tempo/{client → legacy/client}/ChannelOps.ts +22 -9
- package/src/tempo/{client → legacy/client}/Session.test.ts +51 -9
- package/src/tempo/{client → legacy/client}/Session.ts +25 -11
- package/src/tempo/{client → legacy/client}/SessionManager.test.ts +81 -9
- package/src/tempo/{client → legacy/client}/SessionManager.ts +41 -20
- package/src/tempo/legacy/client/index.ts +6 -0
- package/src/tempo/legacy/index.ts +6 -0
- package/src/tempo/{server → legacy/server}/Session.test.ts +162 -63
- package/src/tempo/{server → legacy/server}/Session.ts +49 -37
- package/src/tempo/legacy/server/index.ts +4 -0
- package/src/tempo/{session → legacy/session}/Chain.test.ts +3 -4
- package/src/tempo/{session → legacy/session}/Chain.ts +94 -63
- package/src/tempo/{session → legacy/session}/Channel.ts +1 -0
- package/src/tempo/legacy/session/ChannelStore.test.ts +58 -0
- package/src/tempo/legacy/session/ChannelStore.ts +39 -0
- package/src/tempo/legacy/session/Types.ts +91 -0
- package/src/tempo/{session → legacy/session}/Voucher.ts +12 -8
- package/src/tempo/{session → legacy/session}/escrow.abi.ts +1 -0
- package/src/tempo/legacy/session/index.ts +8 -0
- package/src/tempo/server/AtomicStore.test-d.ts +16 -11
- package/src/tempo/server/Charge.test.ts +92 -14
- package/src/tempo/server/Charge.ts +18 -16
- package/src/tempo/server/Methods.ts +54 -8
- package/src/tempo/server/Sse.test.ts +2 -2
- package/src/tempo/server/index.ts +6 -5
- package/src/tempo/server/internal/html/package.json +1 -1
- package/src/tempo/server/internal/html.gen.ts +1 -1
- package/src/tempo/server/internal/request-body.test.ts +37 -4
- package/src/tempo/server/internal/request-body.ts +25 -6
- package/src/tempo/server/internal/transport.test.ts +4 -4
- package/src/tempo/server/internal/transport.ts +19 -10
- package/src/tempo/session/Snapshot.test.ts +41 -0
- package/src/tempo/session/Snapshot.ts +74 -0
- package/src/tempo/session/client/ChannelOps.test.ts +163 -0
- package/src/tempo/session/client/ChannelOps.ts +344 -0
- package/src/tempo/session/client/CredentialState.test.ts +645 -0
- package/src/tempo/session/client/CredentialState.ts +814 -0
- package/src/tempo/session/client/ReceiptCoordinator.ts +95 -0
- package/src/tempo/session/client/Runtime.test.ts +1092 -0
- package/src/tempo/session/client/Runtime.ts +986 -0
- package/src/tempo/session/client/Session.test.ts +734 -0
- package/src/tempo/session/client/Session.ts +97 -0
- package/src/tempo/session/client/SessionManager.test.ts +1308 -0
- package/src/tempo/session/client/SessionManager.ts +845 -0
- package/src/tempo/session/client/Transports.test.ts +837 -0
- package/src/tempo/session/client/Transports.ts +1292 -0
- package/src/tempo/session/client/index.ts +37 -0
- package/src/tempo/session/index.ts +7 -8
- package/src/tempo/session/precompile/Chain.integration.test.ts +321 -0
- package/src/tempo/session/precompile/Chain.test.ts +1258 -0
- package/src/tempo/session/precompile/Chain.ts +979 -0
- package/src/tempo/session/precompile/Channel.test.ts +138 -0
- package/src/tempo/session/precompile/Channel.ts +103 -0
- package/src/tempo/session/precompile/Protocol.test.ts +358 -0
- package/src/tempo/session/precompile/Protocol.ts +520 -0
- package/src/tempo/session/precompile/Voucher.test.ts +316 -0
- package/src/tempo/session/precompile/Voucher.ts +160 -0
- package/src/tempo/session/precompile/escrow.abi.ts +226 -0
- package/src/tempo/session/precompile/index.ts +33 -0
- package/src/tempo/session/server/ChannelOps.test.ts +129 -0
- package/src/tempo/session/server/ChannelOps.ts +157 -0
- package/src/tempo/session/{ChannelStore.test.ts → server/ChannelStore.test.ts} +536 -29
- package/src/tempo/session/server/ChannelStore.ts +835 -0
- package/src/tempo/session/server/CredentialVerification.test.ts +146 -0
- package/src/tempo/session/server/CredentialVerification.ts +710 -0
- package/src/tempo/session/server/MeteredStream.ts +88 -0
- package/src/tempo/session/server/RequestState.test.ts +531 -0
- package/src/tempo/session/server/RequestState.ts +499 -0
- package/src/tempo/session/server/Session.integration.test.ts +444 -0
- package/src/tempo/session/server/Session.test.ts +3253 -0
- package/src/tempo/session/server/Session.ts +543 -0
- package/src/tempo/session/server/Settlement.test.ts +242 -0
- package/src/tempo/session/server/Settlement.ts +470 -0
- package/src/tempo/session/{Sse.test.ts → server/Sse.test.ts} +37 -3
- package/src/tempo/session/server/Sse.ts +256 -0
- package/src/tempo/session/server/Transports.test.ts +346 -0
- package/src/tempo/session/server/Transports.ts +255 -0
- package/src/tempo/session/{Ws.test.ts → server/Ws.test.ts} +4 -4
- package/src/tempo/session/server/Ws.ts +384 -0
- package/src/tempo/session/server/index.ts +8 -0
- package/dist/tempo/client/ChannelOps.d.ts.map +0 -1
- package/dist/tempo/client/ChannelOps.js.map +0 -1
- package/dist/tempo/client/Session.d.ts.map +0 -1
- package/dist/tempo/client/Session.js.map +0 -1
- package/dist/tempo/client/SessionManager.d.ts.map +0 -1
- package/dist/tempo/client/SessionManager.js.map +0 -1
- package/dist/tempo/server/Session.d.ts.map +0 -1
- package/dist/tempo/server/Session.js.map +0 -1
- package/dist/tempo/session/Chain.d.ts.map +0 -1
- package/dist/tempo/session/Chain.js.map +0 -1
- package/dist/tempo/session/Channel.d.ts.map +0 -1
- package/dist/tempo/session/Channel.js.map +0 -1
- package/dist/tempo/session/ChannelStore.d.ts +0 -117
- package/dist/tempo/session/ChannelStore.d.ts.map +0 -1
- package/dist/tempo/session/ChannelStore.js +0 -172
- package/dist/tempo/session/ChannelStore.js.map +0 -1
- package/dist/tempo/session/Receipt.d.ts +0 -22
- package/dist/tempo/session/Receipt.d.ts.map +0 -1
- package/dist/tempo/session/Receipt.js +0 -34
- package/dist/tempo/session/Receipt.js.map +0 -1
- package/dist/tempo/session/Sse.d.ts.map +0 -1
- package/dist/tempo/session/Sse.js +0 -363
- package/dist/tempo/session/Sse.js.map +0 -1
- package/dist/tempo/session/Types.d.ts +0 -78
- package/dist/tempo/session/Types.d.ts.map +0 -1
- package/dist/tempo/session/Types.js.map +0 -1
- package/dist/tempo/session/Voucher.d.ts.map +0 -1
- package/dist/tempo/session/Voucher.js.map +0 -1
- package/dist/tempo/session/Ws.d.ts +0 -87
- package/dist/tempo/session/Ws.d.ts.map +0 -1
- package/dist/tempo/session/Ws.js +0 -443
- package/dist/tempo/session/Ws.js.map +0 -1
- package/dist/tempo/session/escrow.abi.js.map +0 -1
- package/src/tempo/session/ChannelStore.ts +0 -308
- package/src/tempo/session/Receipt.test.ts +0 -89
- package/src/tempo/session/Receipt.ts +0 -46
- package/src/tempo/session/Sse.ts +0 -462
- package/src/tempo/session/Types.ts +0 -86
- package/src/tempo/session/Ws.ts +0 -576
- /package/dist/tempo/{session → legacy/session}/Channel.js +0 -0
- /package/dist/tempo/{session → legacy/session}/Types.js +0 -0
- /package/src/tempo/{session → legacy/session}/Channel.test.ts +0 -0
- /package/src/tempo/{session → legacy/session}/Voucher.test.ts +0 -0
- /package/src/tempo/session/{Sse.fuzz.test.ts → server/Sse.fuzz.test.ts} +0 -0
|
@@ -0,0 +1,979 @@
|
|
|
1
|
+
import type { Account, Address, Client, Hex } from 'viem'
|
|
2
|
+
import { encodeFunctionData, isAddressEqual, parseEventLogs } from 'viem'
|
|
3
|
+
import {
|
|
4
|
+
call,
|
|
5
|
+
prepareTransactionRequest,
|
|
6
|
+
readContract,
|
|
7
|
+
sendRawTransaction,
|
|
8
|
+
sendRawTransactionSync,
|
|
9
|
+
sendTransaction as sendViemTransaction,
|
|
10
|
+
signTransaction,
|
|
11
|
+
waitForTransactionReceipt,
|
|
12
|
+
} from 'viem/actions'
|
|
13
|
+
import { Transaction } from 'viem/tempo'
|
|
14
|
+
|
|
15
|
+
import { BadRequestError, VerificationFailedError } from '../../../Errors.js'
|
|
16
|
+
import * as FeePayer from '../../internal/fee-payer.js'
|
|
17
|
+
import { resolveFeeToken } from '../../internal/fee-token.js'
|
|
18
|
+
import * as ChannelOps from '../server/ChannelOps.js'
|
|
19
|
+
import * as ChannelUtils from './Channel.js'
|
|
20
|
+
import type { ChannelDescriptor } from './Channel.js'
|
|
21
|
+
import { escrowAbi } from './escrow.abi.js'
|
|
22
|
+
import { tip20ChannelEscrow } from './Protocol.js'
|
|
23
|
+
|
|
24
|
+
/** Minimal on-chain state read back after precompile transaction receipts. */
|
|
25
|
+
export type ReceiptValidationChannelState = {
|
|
26
|
+
/** Cumulative amount settled on-chain. */
|
|
27
|
+
settled: bigint
|
|
28
|
+
/** Current on-chain channel deposit. */
|
|
29
|
+
deposit: bigint
|
|
30
|
+
/** Close-request timestamp, or zero when open. */
|
|
31
|
+
closeRequestedAt: number
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** Inputs used to validate a ChannelOpened event against the verified open calldata. */
|
|
35
|
+
export type ValidateChannelOpenedReceiptParameters = {
|
|
36
|
+
/** Chain ID used in descriptor-derived channel ID. */
|
|
37
|
+
chainId: number
|
|
38
|
+
/** Descriptor reconstructed from the open calldata. */
|
|
39
|
+
descriptor: ChannelDescriptor
|
|
40
|
+
/** Channel ID emitted by the ChannelOpened event. */
|
|
41
|
+
emittedChannelId: Hex
|
|
42
|
+
/** Deposit emitted by the ChannelOpened event. */
|
|
43
|
+
emittedDeposit: bigint
|
|
44
|
+
/** Expiring nonce hash emitted by the ChannelOpened event. */
|
|
45
|
+
emittedExpiringNonceHash: Hex
|
|
46
|
+
/** Escrow precompile address used in descriptor-derived channel ID. */
|
|
47
|
+
escrow: Address
|
|
48
|
+
/** Channel ID expected from the credential. */
|
|
49
|
+
expectedChannelId: Hex
|
|
50
|
+
/** Deposit parsed from open calldata. */
|
|
51
|
+
openDeposit: bigint
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** Inputs used to validate open read-back state after ChannelOpened. */
|
|
55
|
+
export type ValidateOpenReadbackStateParameters = {
|
|
56
|
+
/** Deposit emitted by the ChannelOpened event. */
|
|
57
|
+
emittedDeposit: bigint
|
|
58
|
+
/** State read back from the precompile. */
|
|
59
|
+
state: ReceiptValidationChannelState
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** Inputs used to validate a TopUp event against the credential channel ID. */
|
|
63
|
+
export type ValidateTopUpReceiptParameters = {
|
|
64
|
+
/** Channel ID emitted by the TopUp event. */
|
|
65
|
+
emittedChannelId: Hex
|
|
66
|
+
/** Channel ID expected from the credential. */
|
|
67
|
+
expectedChannelId: Hex
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** Inputs used to validate top-up read-back state after TopUp. */
|
|
71
|
+
export type ValidateTopUpReadbackStateParameters = {
|
|
72
|
+
/** New deposit emitted by the TopUp event. */
|
|
73
|
+
newDeposit: bigint
|
|
74
|
+
/** State read back from the precompile. */
|
|
75
|
+
state: ReceiptValidationChannelState
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** Typed fields decoded from a ChannelOpened receipt event. */
|
|
79
|
+
export type ChannelOpenedReceiptFields = {
|
|
80
|
+
/** Channel ID emitted by the precompile. */
|
|
81
|
+
channelId: Hex
|
|
82
|
+
/** Deposit emitted by the precompile. */
|
|
83
|
+
deposit: bigint
|
|
84
|
+
/** Expiring nonce hash emitted by the precompile. */
|
|
85
|
+
expiringNonceHash: Hex
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/** Typed fields decoded from a TopUp receipt event. */
|
|
89
|
+
export type TopUpReceiptFields = {
|
|
90
|
+
/** Channel ID emitted by the precompile. */
|
|
91
|
+
channelId: Hex
|
|
92
|
+
/** New total deposit emitted by the precompile. */
|
|
93
|
+
newDeposit: bigint
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** Typed fields decoded from a Settled receipt event. */
|
|
97
|
+
export type SettledReceiptFields = {
|
|
98
|
+
/** New cumulative amount settled on-chain. */
|
|
99
|
+
newSettled: bigint
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/** Typed fields decoded from a ChannelClosed receipt event. */
|
|
103
|
+
export type ChannelClosedReceiptFields = {
|
|
104
|
+
/** Amount captured by the payee. */
|
|
105
|
+
settledToPayee: bigint
|
|
106
|
+
/** Amount refunded to the payer. */
|
|
107
|
+
refundedToPayer: bigint
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
type ReceiptEventWithArgs = {
|
|
111
|
+
args: Record<string, unknown>
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const uint96Max = 2n ** 96n - 1n
|
|
115
|
+
|
|
116
|
+
function readBytes32(value: unknown, label: string): Hex {
|
|
117
|
+
if (typeof value === 'string' && /^0x[0-9a-fA-F]{64}$/.test(value)) return value as Hex
|
|
118
|
+
throw new VerificationFailedError({ reason: `${label} missing from receipt event` })
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function readUint96(value: unknown, label: string): bigint {
|
|
122
|
+
if (typeof value !== 'bigint')
|
|
123
|
+
throw new VerificationFailedError({ reason: `${label} missing from receipt event` })
|
|
124
|
+
if (value < 0n || value > uint96Max)
|
|
125
|
+
throw new VerificationFailedError({ reason: `${label} exceeds uint96 range` })
|
|
126
|
+
return value
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/** Reads and validates typed fields from a ChannelOpened receipt event. */
|
|
130
|
+
export function readChannelOpenedReceiptFields(
|
|
131
|
+
event: ReceiptEventWithArgs,
|
|
132
|
+
): ChannelOpenedReceiptFields {
|
|
133
|
+
return {
|
|
134
|
+
channelId: readBytes32(event.args.channelId, 'ChannelOpened channelId'),
|
|
135
|
+
deposit: readUint96(event.args.deposit, 'ChannelOpened deposit'),
|
|
136
|
+
expiringNonceHash: readBytes32(event.args.expiringNonceHash, 'ChannelOpened expiringNonceHash'),
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/** Reads and validates typed fields from a TopUp receipt event. */
|
|
141
|
+
export function readTopUpReceiptFields(event: ReceiptEventWithArgs): TopUpReceiptFields {
|
|
142
|
+
return {
|
|
143
|
+
channelId: readBytes32(event.args.channelId, 'TopUp channelId'),
|
|
144
|
+
newDeposit: readUint96(event.args.newDeposit, 'TopUp newDeposit'),
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/** Reads and validates typed fields from a Settled receipt event. */
|
|
149
|
+
export function readSettledReceiptFields(event: ReceiptEventWithArgs): SettledReceiptFields {
|
|
150
|
+
return {
|
|
151
|
+
newSettled: readUint96(event.args.newSettled, 'Settled newSettled'),
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/** Reads and validates typed fields from a ChannelClosed receipt event. */
|
|
156
|
+
export function readChannelClosedReceiptFields(
|
|
157
|
+
event: ReceiptEventWithArgs,
|
|
158
|
+
): ChannelClosedReceiptFields {
|
|
159
|
+
return {
|
|
160
|
+
settledToPayee: readUint96(event.args.settledToPayee, 'ChannelClosed settledToPayee'),
|
|
161
|
+
refundedToPayer: readUint96(event.args.refundedToPayer, 'ChannelClosed refundedToPayer'),
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/** Validates that ChannelOpened receipt fields match calldata, descriptor, and credential. */
|
|
166
|
+
export function validateChannelOpenedReceipt(
|
|
167
|
+
parameters: ValidateChannelOpenedReceiptParameters,
|
|
168
|
+
): void {
|
|
169
|
+
const {
|
|
170
|
+
chainId,
|
|
171
|
+
descriptor,
|
|
172
|
+
emittedChannelId,
|
|
173
|
+
emittedDeposit,
|
|
174
|
+
emittedExpiringNonceHash,
|
|
175
|
+
escrow,
|
|
176
|
+
expectedChannelId,
|
|
177
|
+
openDeposit,
|
|
178
|
+
} = parameters
|
|
179
|
+
|
|
180
|
+
if (emittedChannelId.toLowerCase() !== expectedChannelId.toLowerCase())
|
|
181
|
+
throw new VerificationFailedError({
|
|
182
|
+
reason: 'ChannelOpened channelId does not match credential',
|
|
183
|
+
})
|
|
184
|
+
if (emittedExpiringNonceHash.toLowerCase() !== descriptor.expiringNonceHash.toLowerCase())
|
|
185
|
+
throw new VerificationFailedError({
|
|
186
|
+
reason: 'ChannelOpened expiringNonceHash does not match descriptor',
|
|
187
|
+
})
|
|
188
|
+
if (emittedDeposit !== openDeposit)
|
|
189
|
+
throw new VerificationFailedError({ reason: 'ChannelOpened deposit does not match calldata' })
|
|
190
|
+
|
|
191
|
+
const confirmedChannelId = ChannelUtils.computeId({ ...descriptor, chainId, escrow })
|
|
192
|
+
if (confirmedChannelId.toLowerCase() !== emittedChannelId.toLowerCase())
|
|
193
|
+
throw new VerificationFailedError({
|
|
194
|
+
reason: 'descriptor does not match ChannelOpened channelId',
|
|
195
|
+
})
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/** Validates the state read back after a successful open transaction. */
|
|
199
|
+
export function validateOpenReadbackState(parameters: ValidateOpenReadbackStateParameters): void {
|
|
200
|
+
const { emittedDeposit, state } = parameters
|
|
201
|
+
if (state.deposit !== emittedDeposit || state.settled !== 0n || state.closeRequestedAt !== 0)
|
|
202
|
+
throw new VerificationFailedError({
|
|
203
|
+
reason: 'on-chain channel state does not match open receipt',
|
|
204
|
+
})
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/** Validates that a TopUp receipt belongs to the credential channel. */
|
|
208
|
+
export function validateTopUpReceipt(parameters: ValidateTopUpReceiptParameters): void {
|
|
209
|
+
if (parameters.emittedChannelId.toLowerCase() !== parameters.expectedChannelId.toLowerCase())
|
|
210
|
+
throw new VerificationFailedError({ reason: 'TopUp channelId does not match credential' })
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/** Validates the state read back after a successful top-up transaction. */
|
|
214
|
+
export function validateTopUpReadbackState(parameters: ValidateTopUpReadbackStateParameters): void {
|
|
215
|
+
if (parameters.state.deposit !== parameters.newDeposit)
|
|
216
|
+
throw new VerificationFailedError({
|
|
217
|
+
reason: 'on-chain channel state does not match topUp receipt',
|
|
218
|
+
})
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/** Fee fields produced by viem transaction preparation for direct precompile calls. */
|
|
222
|
+
export type PreparedPrecompileFeePayerTransaction = {
|
|
223
|
+
/** Estimated gas units for the transaction. */
|
|
224
|
+
gas?: bigint | undefined
|
|
225
|
+
/** Maximum fee per gas unit. */
|
|
226
|
+
maxFeePerGas?: bigint | undefined
|
|
227
|
+
/** Maximum priority fee per gas unit. */
|
|
228
|
+
maxPriorityFeePerGas?: bigint | undefined
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/** Parameters for checking a direct precompile transaction against sponsor limits. */
|
|
232
|
+
export type AssertPrecompileFeePayerPolicyParameters = {
|
|
233
|
+
/** Prepared transaction fee fields to validate. */
|
|
234
|
+
prepared: PreparedPrecompileFeePayerTransaction
|
|
235
|
+
/** Optional sponsor policy overrides. Missing fields are not enforced here. */
|
|
236
|
+
policy?: Partial<FeePayer.Policy> | undefined
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/** Enforces sponsor gas and fee limits before co-signing a direct precompile call. */
|
|
240
|
+
export function assertPrecompileFeePayerPolicy(
|
|
241
|
+
parameters: AssertPrecompileFeePayerPolicyParameters,
|
|
242
|
+
) {
|
|
243
|
+
const { policy, prepared } = parameters
|
|
244
|
+
if (!policy) return
|
|
245
|
+
if (policy.maxGas !== undefined && (prepared.gas ?? 0n) > policy.maxGas)
|
|
246
|
+
throw new BadRequestError({ reason: 'fee-payer policy maxGas exceeded' })
|
|
247
|
+
if (policy.maxFeePerGas !== undefined && (prepared.maxFeePerGas ?? 0n) > policy.maxFeePerGas)
|
|
248
|
+
throw new BadRequestError({ reason: 'fee-payer policy maxFeePerGas exceeded' })
|
|
249
|
+
if (
|
|
250
|
+
policy.maxPriorityFeePerGas !== undefined &&
|
|
251
|
+
(prepared.maxPriorityFeePerGas ?? 0n) > policy.maxPriorityFeePerGas
|
|
252
|
+
)
|
|
253
|
+
throw new BadRequestError({ reason: 'fee-payer policy maxPriorityFeePerGas exceeded' })
|
|
254
|
+
if (
|
|
255
|
+
policy.maxTotalFee !== undefined &&
|
|
256
|
+
(prepared.gas ?? 0n) * (prepared.maxFeePerGas ?? 0n) > policy.maxTotalFee
|
|
257
|
+
)
|
|
258
|
+
throw new BadRequestError({ reason: 'fee-payer policy maxTotalFee exceeded' })
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
const UINT96_MAX = 2n ** 96n - 1n
|
|
262
|
+
|
|
263
|
+
/** viem client shape accepted by raw Tempo transaction actions. */
|
|
264
|
+
export type TransactionClient = Parameters<typeof sendRawTransaction>[0]
|
|
265
|
+
|
|
266
|
+
function assertUint96(amount: bigint): void {
|
|
267
|
+
if (amount < 0n || amount > UINT96_MAX) {
|
|
268
|
+
throw new VerificationFailedError({ reason: 'amount exceeds uint96 range' })
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* On-chain channel state from the TIP20EscrowChannel precompile.
|
|
274
|
+
*/
|
|
275
|
+
export type ChannelState = {
|
|
276
|
+
settled: bigint
|
|
277
|
+
deposit: bigint
|
|
278
|
+
closeRequestedAt: number
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* On-chain channel descriptor and state from the TIP20EscrowChannel precompile.
|
|
283
|
+
*/
|
|
284
|
+
export type Channel = {
|
|
285
|
+
descriptor: ChannelDescriptor
|
|
286
|
+
state: ChannelState
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Read channel descriptor and state from the TIP20EscrowChannel precompile.
|
|
291
|
+
*/
|
|
292
|
+
export async function getChannel(
|
|
293
|
+
client: Client,
|
|
294
|
+
descriptor: ChannelDescriptor,
|
|
295
|
+
escrow: Address = tip20ChannelEscrow,
|
|
296
|
+
): Promise<Channel> {
|
|
297
|
+
const channel = await readContract(client, {
|
|
298
|
+
address: escrow,
|
|
299
|
+
abi: escrowAbi,
|
|
300
|
+
functionName: 'getChannel',
|
|
301
|
+
args: [descriptorTuple(descriptor)],
|
|
302
|
+
})
|
|
303
|
+
return {
|
|
304
|
+
descriptor: channel.descriptor,
|
|
305
|
+
state: stateFromTuple(channel.state),
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* Read channel state from the TIP20EscrowChannel precompile.
|
|
311
|
+
*/
|
|
312
|
+
export async function getChannelState(
|
|
313
|
+
client: Client,
|
|
314
|
+
channelId: Hex,
|
|
315
|
+
escrow: Address = tip20ChannelEscrow,
|
|
316
|
+
): Promise<ChannelState> {
|
|
317
|
+
const state = await readContract(client, {
|
|
318
|
+
address: escrow,
|
|
319
|
+
abi: escrowAbi,
|
|
320
|
+
functionName: 'getChannelState',
|
|
321
|
+
args: [channelId],
|
|
322
|
+
})
|
|
323
|
+
return stateFromTuple(state)
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
/**
|
|
327
|
+
* Read channel states from the TIP20EscrowChannel precompile.
|
|
328
|
+
*/
|
|
329
|
+
export async function getChannelStatesBatch(
|
|
330
|
+
client: Client,
|
|
331
|
+
channelIds: readonly Hex[],
|
|
332
|
+
escrow: Address = tip20ChannelEscrow,
|
|
333
|
+
): Promise<ChannelState[]> {
|
|
334
|
+
const states = await readContract(client, {
|
|
335
|
+
address: escrow,
|
|
336
|
+
abi: escrowAbi,
|
|
337
|
+
functionName: 'getChannelStatesBatch',
|
|
338
|
+
args: [channelIds],
|
|
339
|
+
})
|
|
340
|
+
return states.map(stateFromTuple)
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
/** Options accepted by low-level TIP-1034 on-chain management helpers. */
|
|
344
|
+
export type ChannelTransactionOptions = {
|
|
345
|
+
/** Account used to send the transaction when the viem client has no default account. */
|
|
346
|
+
account?: Account | undefined
|
|
347
|
+
/** Candidate fee tokens used when resolving a fee token for fee-sponsored transactions. */
|
|
348
|
+
candidateFeeTokens?: readonly Address[] | undefined
|
|
349
|
+
/** Fee-payer account used to co-sign Tempo fee-sponsored transactions. */
|
|
350
|
+
feePayer?: Account | undefined
|
|
351
|
+
/** Optional fee-payer gas and total-fee limits enforced before co-signing. */
|
|
352
|
+
feePayerPolicy?: Partial<FeePayer.Policy> | undefined
|
|
353
|
+
/** Explicit fee token for the transaction. */
|
|
354
|
+
feeToken?: Address | undefined
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
type ParsedPrecompileCredentialTransaction = {
|
|
358
|
+
call: Transaction.TransactionTempo['calls'][number] & { data: Hex; to: Address }
|
|
359
|
+
transaction: ReturnType<(typeof Transaction)['deserialize']>
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
function parsePrecompileCredentialTransaction(parameters: {
|
|
363
|
+
escrowContract: Address
|
|
364
|
+
feePayer?: Account | undefined
|
|
365
|
+
label: 'open' | 'topUp'
|
|
366
|
+
serializedTransaction: Hex
|
|
367
|
+
}): ParsedPrecompileCredentialTransaction {
|
|
368
|
+
const { escrowContract, feePayer, label, serializedTransaction } = parameters
|
|
369
|
+
if (feePayer && !FeePayer.isTempoTransaction(serializedTransaction))
|
|
370
|
+
throw new BadRequestError({ reason: 'Only Tempo (0x76/0x78) transactions are supported' })
|
|
371
|
+
|
|
372
|
+
const transaction = Transaction.deserialize(
|
|
373
|
+
serializedTransaction as Transaction.TransactionSerializedTempo,
|
|
374
|
+
)
|
|
375
|
+
const calls = transaction.calls
|
|
376
|
+
if (calls.length !== 1)
|
|
377
|
+
throw new VerificationFailedError({
|
|
378
|
+
reason: `TIP-1034 ${label} transaction must contain exactly one call`,
|
|
379
|
+
})
|
|
380
|
+
const call = calls[0]!
|
|
381
|
+
if (!call.to || !isAddressEqual(call.to, escrowContract))
|
|
382
|
+
throw new VerificationFailedError({
|
|
383
|
+
reason: `TIP-1034 ${label} transaction targets the wrong address`,
|
|
384
|
+
})
|
|
385
|
+
if (!call.data)
|
|
386
|
+
throw new VerificationFailedError({
|
|
387
|
+
reason: `TIP-1034 ${label} transaction is missing calldata`,
|
|
388
|
+
})
|
|
389
|
+
return { transaction, call: { ...call, data: call.data, to: call.to } }
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
async function simulateTempoTransaction(client: Client, transaction: Transaction.TransactionTempo) {
|
|
393
|
+
// viem's public `call` type does not yet model Tempo's multi-call and
|
|
394
|
+
// fee-payer fields together. Keep that compatibility cast in one place.
|
|
395
|
+
await call(client, {
|
|
396
|
+
...transaction,
|
|
397
|
+
account: transaction.from,
|
|
398
|
+
calls: transaction.calls ?? [],
|
|
399
|
+
feePayerSignature: undefined,
|
|
400
|
+
} as never)
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
async function signTempoTransaction(client: Client, transaction: unknown): Promise<Hex> {
|
|
404
|
+
return (await signTransaction(client, transaction as never)) as Hex
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
async function prepareFeePayerCallTransaction(
|
|
408
|
+
client: Client,
|
|
409
|
+
parameters: {
|
|
410
|
+
account: Account
|
|
411
|
+
data: Hex
|
|
412
|
+
feeToken?: Address | undefined
|
|
413
|
+
to: Address
|
|
414
|
+
},
|
|
415
|
+
) {
|
|
416
|
+
const { account, data, feeToken, to } = parameters
|
|
417
|
+
// viem's stable request type does not expose Tempo fee-payer transaction
|
|
418
|
+
// fields for this call shape. Keep the cast at the boundary.
|
|
419
|
+
return prepareTransactionRequest(client, {
|
|
420
|
+
account,
|
|
421
|
+
calls: [{ to, data }],
|
|
422
|
+
feePayer: true,
|
|
423
|
+
...(feeToken ? { feeToken } : {}),
|
|
424
|
+
} as never)
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
function sendPrecompileContractCall(
|
|
428
|
+
client: Client,
|
|
429
|
+
parameters: {
|
|
430
|
+
account?: Account | undefined
|
|
431
|
+
data: Hex
|
|
432
|
+
feeToken?: Address | undefined
|
|
433
|
+
to: Address
|
|
434
|
+
},
|
|
435
|
+
): Promise<Hex> {
|
|
436
|
+
const { account, data, feeToken, to } = parameters
|
|
437
|
+
// `feeToken` is Tempo-specific and not represented on viem's base
|
|
438
|
+
// transaction request type.
|
|
439
|
+
return sendViemTransaction(client, {
|
|
440
|
+
...(account ? { account } : {}),
|
|
441
|
+
to,
|
|
442
|
+
data,
|
|
443
|
+
...(feeToken ? { feeToken } : {}),
|
|
444
|
+
} as never)
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
/**
|
|
448
|
+
* Submit a settle transaction on-chain.
|
|
449
|
+
*/
|
|
450
|
+
export async function settleOnChain(
|
|
451
|
+
client: Client,
|
|
452
|
+
descriptor: ChannelDescriptor,
|
|
453
|
+
cumulativeAmount: bigint,
|
|
454
|
+
signature: Hex,
|
|
455
|
+
escrow: Address = tip20ChannelEscrow,
|
|
456
|
+
options?: ChannelTransactionOptions,
|
|
457
|
+
): Promise<Hex> {
|
|
458
|
+
assertUint96(cumulativeAmount)
|
|
459
|
+
const args = [descriptorTuple(descriptor), cumulativeAmount, signature] as const
|
|
460
|
+
return sendPrecompileTransaction(
|
|
461
|
+
client,
|
|
462
|
+
escrow,
|
|
463
|
+
encodeFunctionData({ abi: escrowAbi, functionName: 'settle', args }),
|
|
464
|
+
'settle',
|
|
465
|
+
options,
|
|
466
|
+
)
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
/**
|
|
470
|
+
* Submit a top-up transaction on-chain.
|
|
471
|
+
*/
|
|
472
|
+
export async function topUpOnChain(
|
|
473
|
+
client: Client,
|
|
474
|
+
descriptor: ChannelDescriptor,
|
|
475
|
+
additionalDeposit: bigint,
|
|
476
|
+
escrow: Address = tip20ChannelEscrow,
|
|
477
|
+
options?: ChannelTransactionOptions,
|
|
478
|
+
): Promise<Hex> {
|
|
479
|
+
assertUint96(additionalDeposit)
|
|
480
|
+
const args = [descriptorTuple(descriptor), additionalDeposit] as const
|
|
481
|
+
return sendPrecompileTransaction(
|
|
482
|
+
client,
|
|
483
|
+
escrow,
|
|
484
|
+
encodeFunctionData({ abi: escrowAbi, functionName: 'topUp', args }),
|
|
485
|
+
'topUp',
|
|
486
|
+
options,
|
|
487
|
+
)
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
/**
|
|
491
|
+
* Submit a request-close transaction on-chain.
|
|
492
|
+
*/
|
|
493
|
+
export async function requestCloseOnChain(
|
|
494
|
+
client: Client,
|
|
495
|
+
descriptor: ChannelDescriptor,
|
|
496
|
+
escrow: Address = tip20ChannelEscrow,
|
|
497
|
+
options?: ChannelTransactionOptions,
|
|
498
|
+
): Promise<Hex> {
|
|
499
|
+
const args = [descriptorTuple(descriptor)] as const
|
|
500
|
+
return sendPrecompileTransaction(
|
|
501
|
+
client,
|
|
502
|
+
escrow,
|
|
503
|
+
encodeFunctionData({ abi: escrowAbi, functionName: 'requestClose', args }),
|
|
504
|
+
'requestClose',
|
|
505
|
+
options,
|
|
506
|
+
)
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
/**
|
|
510
|
+
* Submit a withdraw transaction on-chain.
|
|
511
|
+
*/
|
|
512
|
+
export async function withdrawOnChain(
|
|
513
|
+
client: Client,
|
|
514
|
+
descriptor: ChannelDescriptor,
|
|
515
|
+
escrow: Address = tip20ChannelEscrow,
|
|
516
|
+
options?: ChannelTransactionOptions,
|
|
517
|
+
): Promise<Hex> {
|
|
518
|
+
const args = [descriptorTuple(descriptor)] as const
|
|
519
|
+
return sendPrecompileTransaction(
|
|
520
|
+
client,
|
|
521
|
+
escrow,
|
|
522
|
+
encodeFunctionData({ abi: escrowAbi, functionName: 'withdraw', args }),
|
|
523
|
+
'withdraw',
|
|
524
|
+
options,
|
|
525
|
+
)
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
/**
|
|
529
|
+
* Submit a close transaction on-chain.
|
|
530
|
+
*/
|
|
531
|
+
export async function closeOnChain(
|
|
532
|
+
client: Client,
|
|
533
|
+
descriptor: ChannelDescriptor,
|
|
534
|
+
cumulativeAmount: bigint,
|
|
535
|
+
captureAmount: bigint,
|
|
536
|
+
signature: Hex,
|
|
537
|
+
escrow: Address = tip20ChannelEscrow,
|
|
538
|
+
options?: ChannelTransactionOptions,
|
|
539
|
+
): Promise<Hex> {
|
|
540
|
+
assertUint96(cumulativeAmount)
|
|
541
|
+
assertUint96(captureAmount)
|
|
542
|
+
const args = [descriptorTuple(descriptor), cumulativeAmount, captureAmount, signature] as const
|
|
543
|
+
return sendPrecompileTransaction(
|
|
544
|
+
client,
|
|
545
|
+
escrow,
|
|
546
|
+
encodeFunctionData({ abi: escrowAbi, functionName: 'close', args }),
|
|
547
|
+
'close',
|
|
548
|
+
options,
|
|
549
|
+
)
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
/** Receipt event shape emitted by TIP20EscrowChannel precompile management calls. */
|
|
553
|
+
export type ChannelReceiptEvent = {
|
|
554
|
+
args: {
|
|
555
|
+
channelId: Hex
|
|
556
|
+
expiringNonceHash?: Hex | undefined
|
|
557
|
+
deposit?: bigint | undefined
|
|
558
|
+
newDeposit?: bigint | undefined
|
|
559
|
+
newSettled?: bigint | undefined
|
|
560
|
+
settledToPayee?: bigint | undefined
|
|
561
|
+
refundedToPayer?: bigint | undefined
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
/** Receipt-like input used when extracting channel events from transaction logs. */
|
|
566
|
+
export type ChannelEventReceipt = {
|
|
567
|
+
logs: Parameters<typeof parseEventLogs>[0]['logs']
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
/**
|
|
571
|
+
* Asserts that a deserialized transaction has an existing sender signature.
|
|
572
|
+
*/
|
|
573
|
+
export function assertSenderSigned(
|
|
574
|
+
transaction: ReturnType<(typeof Transaction)['deserialize']>,
|
|
575
|
+
): void {
|
|
576
|
+
if (!transaction.signature || !transaction.from)
|
|
577
|
+
throw new BadRequestError({
|
|
578
|
+
reason: 'Transaction must be signed by the sender before fee payer co-signing',
|
|
579
|
+
})
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
/** Broadcast a raw serialized transaction. */
|
|
583
|
+
export async function sendTransaction(client: TransactionClient, transaction: Hex) {
|
|
584
|
+
return sendRawTransaction(client, { serializedTransaction: transaction })
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
/** Wait for a receipt and reject reverted precompile transactions. */
|
|
588
|
+
export async function waitForSuccessfulReceipt(client: TransactionClient, hash: Hex) {
|
|
589
|
+
const receipt = await waitForTransactionReceipt(client, { hash })
|
|
590
|
+
if (receipt.status !== 'success')
|
|
591
|
+
throw new VerificationFailedError({ reason: 'precompile transaction reverted' })
|
|
592
|
+
return receipt
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
/** Extract exactly one channel event for a channel ID from a receipt. */
|
|
596
|
+
export function getChannelEvent(
|
|
597
|
+
receipt: ChannelEventReceipt,
|
|
598
|
+
name: 'ChannelOpened' | 'TopUp' | 'Settled' | 'ChannelClosed',
|
|
599
|
+
channelId: Hex,
|
|
600
|
+
): ChannelReceiptEvent {
|
|
601
|
+
const logs = parseEventLogs({
|
|
602
|
+
abi: escrowAbi,
|
|
603
|
+
eventName: name,
|
|
604
|
+
logs: receipt.logs,
|
|
605
|
+
}) as ChannelReceiptEvent[]
|
|
606
|
+
const matches = logs.filter((log) => log.args.channelId.toLowerCase() === channelId.toLowerCase())
|
|
607
|
+
if (matches.length !== 1)
|
|
608
|
+
throw new VerificationFailedError({
|
|
609
|
+
reason: `expected one ${name} event for credential channelId in receipt`,
|
|
610
|
+
})
|
|
611
|
+
return matches[0]!
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
/** Inputs for broadcasting a client-signed precompile management transaction. */
|
|
615
|
+
export type SendCredentialTransactionParameters = {
|
|
616
|
+
/** Challenge expiration propagated into fee-payer policy checks. */
|
|
617
|
+
challengeExpires?: string | undefined
|
|
618
|
+
/** Chain ID used for fee-payer transaction signing. */
|
|
619
|
+
chainId: number
|
|
620
|
+
/** viem client used to submit the transaction. */
|
|
621
|
+
client: TransactionClient
|
|
622
|
+
/** Fee tokens allowed by the server for sponsored transactions. */
|
|
623
|
+
allowedFeeTokens?: readonly Address[] | undefined
|
|
624
|
+
/** Human-readable transaction details used by fee-payer policy hooks. */
|
|
625
|
+
details: Record<string, string>
|
|
626
|
+
/** Fee-payer account used to co-sign Tempo transactions. */
|
|
627
|
+
feePayer?: Account | undefined
|
|
628
|
+
/** Optional fee-payer policy enforced before co-signing. */
|
|
629
|
+
feePayerPolicy?: Partial<FeePayer.Policy> | undefined
|
|
630
|
+
/** Management transaction kind, used for validation errors. */
|
|
631
|
+
label: 'open' | 'topUp'
|
|
632
|
+
/** Client-signed serialized transaction. */
|
|
633
|
+
serializedTransaction: Hex
|
|
634
|
+
/** Deserialized transaction corresponding to `serializedTransaction`. */
|
|
635
|
+
transaction: ReturnType<(typeof Transaction)['deserialize']>
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
/** Broadcasts a client-signed management transaction, adding a fee-payer co-signature when requested. */
|
|
639
|
+
export async function sendCredentialTransaction(parameters: SendCredentialTransactionParameters) {
|
|
640
|
+
const {
|
|
641
|
+
challengeExpires,
|
|
642
|
+
chainId,
|
|
643
|
+
client,
|
|
644
|
+
allowedFeeTokens,
|
|
645
|
+
details,
|
|
646
|
+
feePayer,
|
|
647
|
+
feePayerPolicy,
|
|
648
|
+
label,
|
|
649
|
+
serializedTransaction,
|
|
650
|
+
transaction,
|
|
651
|
+
} = parameters
|
|
652
|
+
|
|
653
|
+
if (!feePayer) {
|
|
654
|
+
const txHash = await sendTransaction(client, serializedTransaction)
|
|
655
|
+
return waitForSuccessfulReceipt(client, txHash)
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
if (!FeePayer.isTempoTransaction(serializedTransaction))
|
|
659
|
+
throw new BadRequestError({ reason: 'Only Tempo (0x76/0x78) transactions are supported' })
|
|
660
|
+
assertSenderSigned(transaction)
|
|
661
|
+
|
|
662
|
+
await simulateTempoTransaction(client, transaction)
|
|
663
|
+
|
|
664
|
+
const sponsored = FeePayer.prepareSponsoredTransaction({
|
|
665
|
+
account: feePayer,
|
|
666
|
+
allowedFeeTokens,
|
|
667
|
+
challengeExpires,
|
|
668
|
+
chainId,
|
|
669
|
+
details,
|
|
670
|
+
policy: feePayerPolicy,
|
|
671
|
+
transaction: {
|
|
672
|
+
...transaction,
|
|
673
|
+
...(allowedFeeTokens?.[0] ? { feeToken: transaction.feeToken ?? allowedFeeTokens[0] } : {}),
|
|
674
|
+
},
|
|
675
|
+
})
|
|
676
|
+
const serialized = await signTempoTransaction(client, sponsored)
|
|
677
|
+
const receipt = await sendRawTransactionSync(client, {
|
|
678
|
+
serializedTransaction: serialized as Transaction.TransactionSerializedTempo,
|
|
679
|
+
})
|
|
680
|
+
if (receipt.status !== 'success')
|
|
681
|
+
throw new VerificationFailedError({
|
|
682
|
+
reason: `${label} precompile transaction reverted: ${receipt.transactionHash}`,
|
|
683
|
+
})
|
|
684
|
+
return receipt
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
/** Result returned after a TIP-1034 open transaction is broadcast and verified. */
|
|
688
|
+
export type BroadcastOpenTransactionResult = {
|
|
689
|
+
/** Broadcast transaction hash. */
|
|
690
|
+
txHash: Hex
|
|
691
|
+
/** Descriptor recovered from the verified open transaction. */
|
|
692
|
+
descriptor: ChannelDescriptor
|
|
693
|
+
/** Latest on-chain channel state after open. */
|
|
694
|
+
state: ChannelState
|
|
695
|
+
/** Expiring nonce hash emitted by the open receipt. */
|
|
696
|
+
expiringNonceHash: Hex
|
|
697
|
+
/** Deposit amount encoded in the open calldata. */
|
|
698
|
+
openDeposit: bigint
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
/** Inputs for broadcasting and verifying a client-signed TIP-1034 open transaction. */
|
|
702
|
+
export type BroadcastOpenTransactionParameters = {
|
|
703
|
+
/** Hook invoked after calldata validation but before broadcasting. */
|
|
704
|
+
beforeBroadcast?:
|
|
705
|
+
| ((result: Omit<BroadcastOpenTransactionResult, 'txHash' | 'state'>) => Promise<void> | void)
|
|
706
|
+
| undefined
|
|
707
|
+
/** Challenge expiration propagated into fee-payer policy checks. */
|
|
708
|
+
challengeExpires?: string | undefined
|
|
709
|
+
/** Chain ID used for channel ID and voucher domain separation. */
|
|
710
|
+
chainId: number
|
|
711
|
+
/** viem client used for transaction submission and readback. */
|
|
712
|
+
client: TransactionClient
|
|
713
|
+
/** TIP20EscrowChannel precompile address. */
|
|
714
|
+
escrowContract: Address
|
|
715
|
+
/** Authorized voucher signer expected in the open calldata. */
|
|
716
|
+
expectedAuthorizedSigner: Address
|
|
717
|
+
/** Channel ID expected from descriptor, escrow, and chain ID. */
|
|
718
|
+
expectedChannelId: Hex
|
|
719
|
+
/** Payment token expected in the open calldata. */
|
|
720
|
+
expectedCurrency: Address
|
|
721
|
+
/** Transaction-bound nonce hash expected in the descriptor. */
|
|
722
|
+
expectedExpiringNonceHash: Hex
|
|
723
|
+
/** Payee-side operator expected in the open calldata. */
|
|
724
|
+
expectedOperator: Address
|
|
725
|
+
/** Payment recipient expected in the open calldata. */
|
|
726
|
+
expectedPayee: Address
|
|
727
|
+
/** Payer expected to have signed the open transaction. */
|
|
728
|
+
expectedPayer: Address
|
|
729
|
+
/** Fee-payer account used to co-sign sponsored open transactions. */
|
|
730
|
+
feePayer?: Account | undefined
|
|
731
|
+
/** Optional fee-payer policy enforced before co-signing. */
|
|
732
|
+
feePayerPolicy?: Partial<FeePayer.Policy> | undefined
|
|
733
|
+
/** Client-signed serialized open transaction. */
|
|
734
|
+
serializedTransaction: Hex
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
/** Broadcast and validate a client-signed TIP-1034 open transaction. */
|
|
738
|
+
export async function broadcastOpenTransaction(
|
|
739
|
+
parameters: BroadcastOpenTransactionParameters,
|
|
740
|
+
): Promise<BroadcastOpenTransactionResult> {
|
|
741
|
+
const { transaction, call } = parsePrecompileCredentialTransaction({
|
|
742
|
+
escrowContract: parameters.escrowContract,
|
|
743
|
+
feePayer: parameters.feePayer,
|
|
744
|
+
label: 'open',
|
|
745
|
+
serializedTransaction: parameters.serializedTransaction,
|
|
746
|
+
})
|
|
747
|
+
const payer = transaction.from ?? parameters.expectedPayer
|
|
748
|
+
const open = ChannelOps.parseOpenCall({
|
|
749
|
+
data: call.data,
|
|
750
|
+
expected: {
|
|
751
|
+
payee: parameters.expectedPayee,
|
|
752
|
+
token: parameters.expectedCurrency,
|
|
753
|
+
operator: parameters.expectedOperator,
|
|
754
|
+
authorizedSigner: parameters.expectedAuthorizedSigner,
|
|
755
|
+
},
|
|
756
|
+
})
|
|
757
|
+
const descriptor = ChannelOps.descriptorFromOpen({
|
|
758
|
+
chainId: parameters.chainId,
|
|
759
|
+
escrow: parameters.escrowContract,
|
|
760
|
+
payer,
|
|
761
|
+
open,
|
|
762
|
+
expiringNonceHash: parameters.expectedExpiringNonceHash,
|
|
763
|
+
channelId: parameters.expectedChannelId,
|
|
764
|
+
})
|
|
765
|
+
if (parameters.feePayer) assertSenderSigned(transaction)
|
|
766
|
+
const expiringNonceHash = ChannelUtils.computeExpiringNonceHash(
|
|
767
|
+
ChannelUtils.transactionForExpiringNonceHash({
|
|
768
|
+
feePayer: parameters.feePayer,
|
|
769
|
+
transaction,
|
|
770
|
+
}),
|
|
771
|
+
{ sender: payer },
|
|
772
|
+
)
|
|
773
|
+
if (expiringNonceHash.toLowerCase() !== descriptor.expiringNonceHash.toLowerCase())
|
|
774
|
+
throw new VerificationFailedError({
|
|
775
|
+
reason: 'credential expiringNonceHash does not match transaction',
|
|
776
|
+
})
|
|
777
|
+
await parameters.beforeBroadcast?.({
|
|
778
|
+
descriptor,
|
|
779
|
+
expiringNonceHash,
|
|
780
|
+
openDeposit: open.deposit,
|
|
781
|
+
})
|
|
782
|
+
const receipt = await sendCredentialTransaction({
|
|
783
|
+
challengeExpires: parameters.challengeExpires,
|
|
784
|
+
chainId: parameters.chainId,
|
|
785
|
+
client: parameters.client,
|
|
786
|
+
allowedFeeTokens: [parameters.expectedCurrency],
|
|
787
|
+
details: {
|
|
788
|
+
channelId: parameters.expectedChannelId,
|
|
789
|
+
currency: parameters.expectedCurrency,
|
|
790
|
+
recipient: parameters.expectedPayee,
|
|
791
|
+
},
|
|
792
|
+
feePayer: parameters.feePayer,
|
|
793
|
+
feePayerPolicy: parameters.feePayerPolicy,
|
|
794
|
+
label: 'open',
|
|
795
|
+
serializedTransaction: parameters.serializedTransaction,
|
|
796
|
+
transaction,
|
|
797
|
+
})
|
|
798
|
+
const opened = readChannelOpenedReceiptFields(
|
|
799
|
+
getChannelEvent(receipt, 'ChannelOpened', parameters.expectedChannelId),
|
|
800
|
+
)
|
|
801
|
+
validateChannelOpenedReceipt({
|
|
802
|
+
chainId: parameters.chainId,
|
|
803
|
+
descriptor,
|
|
804
|
+
emittedChannelId: opened.channelId,
|
|
805
|
+
emittedDeposit: opened.deposit,
|
|
806
|
+
emittedExpiringNonceHash: opened.expiringNonceHash,
|
|
807
|
+
escrow: parameters.escrowContract,
|
|
808
|
+
expectedChannelId: parameters.expectedChannelId,
|
|
809
|
+
openDeposit: open.deposit,
|
|
810
|
+
})
|
|
811
|
+
const chainChannel = await getChannel(parameters.client, descriptor, parameters.escrowContract)
|
|
812
|
+
const state = chainChannel.state
|
|
813
|
+
validateOpenReadbackState({ emittedDeposit: opened.deposit, state })
|
|
814
|
+
return {
|
|
815
|
+
txHash: receipt.transactionHash,
|
|
816
|
+
descriptor,
|
|
817
|
+
state,
|
|
818
|
+
expiringNonceHash: opened.expiringNonceHash,
|
|
819
|
+
openDeposit: open.deposit,
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
/** Result returned after a TIP-1034 top-up transaction is broadcast and verified. */
|
|
824
|
+
export type BroadcastTopUpTransactionResult = {
|
|
825
|
+
/** Broadcast transaction hash. */
|
|
826
|
+
txHash: Hex
|
|
827
|
+
/** New on-chain deposit emitted by the top-up receipt. */
|
|
828
|
+
newDeposit: bigint
|
|
829
|
+
/** Latest on-chain channel state after top-up. */
|
|
830
|
+
state: ChannelState
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
/** Inputs for broadcasting and verifying a client-signed TIP-1034 top-up transaction. */
|
|
834
|
+
export type BroadcastTopUpTransactionParameters = {
|
|
835
|
+
/** Additional deposit amount expected in the top-up calldata. */
|
|
836
|
+
additionalDeposit: bigint
|
|
837
|
+
/** Challenge expiration propagated into fee-payer policy checks. */
|
|
838
|
+
challengeExpires?: string | undefined
|
|
839
|
+
/** Chain ID used for fee-payer transaction signing. */
|
|
840
|
+
chainId: number
|
|
841
|
+
/** viem client used for transaction submission and readback. */
|
|
842
|
+
client: TransactionClient
|
|
843
|
+
/** Descriptor expected in the top-up calldata. */
|
|
844
|
+
descriptor: ChannelDescriptor
|
|
845
|
+
/** TIP20EscrowChannel precompile address. */
|
|
846
|
+
escrowContract: Address
|
|
847
|
+
/** Channel ID expected in the top-up receipt. */
|
|
848
|
+
expectedChannelId: Hex
|
|
849
|
+
/** Payment token expected for sponsored transaction fee token checks. */
|
|
850
|
+
expectedCurrency: Address
|
|
851
|
+
/** Fee-payer account used to co-sign sponsored top-up transactions. */
|
|
852
|
+
feePayer?: Account | undefined
|
|
853
|
+
/** Optional fee-payer policy enforced before co-signing. */
|
|
854
|
+
feePayerPolicy?: Partial<FeePayer.Policy> | undefined
|
|
855
|
+
/** Client-signed serialized top-up transaction. */
|
|
856
|
+
serializedTransaction: Hex
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
/** Broadcast and validate a client-signed TIP-1034 top-up transaction. */
|
|
860
|
+
export async function broadcastTopUpTransaction(
|
|
861
|
+
parameters: BroadcastTopUpTransactionParameters,
|
|
862
|
+
): Promise<BroadcastTopUpTransactionResult> {
|
|
863
|
+
const { transaction, call } = parsePrecompileCredentialTransaction({
|
|
864
|
+
escrowContract: parameters.escrowContract,
|
|
865
|
+
feePayer: parameters.feePayer,
|
|
866
|
+
label: 'topUp',
|
|
867
|
+
serializedTransaction: parameters.serializedTransaction,
|
|
868
|
+
})
|
|
869
|
+
ChannelOps.parseTopUpCall({
|
|
870
|
+
data: call.data,
|
|
871
|
+
expected: {
|
|
872
|
+
descriptor: parameters.descriptor,
|
|
873
|
+
additionalDeposit: parameters.additionalDeposit,
|
|
874
|
+
},
|
|
875
|
+
})
|
|
876
|
+
const receipt = await sendCredentialTransaction({
|
|
877
|
+
challengeExpires: parameters.challengeExpires,
|
|
878
|
+
chainId: parameters.chainId,
|
|
879
|
+
client: parameters.client,
|
|
880
|
+
allowedFeeTokens: [parameters.expectedCurrency],
|
|
881
|
+
details: {
|
|
882
|
+
additionalDeposit: parameters.additionalDeposit.toString(),
|
|
883
|
+
channelId: parameters.expectedChannelId,
|
|
884
|
+
currency: parameters.expectedCurrency,
|
|
885
|
+
},
|
|
886
|
+
feePayer: parameters.feePayer,
|
|
887
|
+
feePayerPolicy: parameters.feePayerPolicy,
|
|
888
|
+
label: 'topUp',
|
|
889
|
+
serializedTransaction: parameters.serializedTransaction,
|
|
890
|
+
transaction,
|
|
891
|
+
})
|
|
892
|
+
const toppedUp = readTopUpReceiptFields(
|
|
893
|
+
getChannelEvent(receipt, 'TopUp', parameters.expectedChannelId),
|
|
894
|
+
)
|
|
895
|
+
validateTopUpReceipt({
|
|
896
|
+
emittedChannelId: toppedUp.channelId,
|
|
897
|
+
expectedChannelId: parameters.expectedChannelId,
|
|
898
|
+
})
|
|
899
|
+
const state = await getChannelState(
|
|
900
|
+
parameters.client,
|
|
901
|
+
toppedUp.channelId,
|
|
902
|
+
parameters.escrowContract,
|
|
903
|
+
)
|
|
904
|
+
validateTopUpReadbackState({ newDeposit: toppedUp.newDeposit, state })
|
|
905
|
+
return { txHash: receipt.transactionHash, newDeposit: toppedUp.newDeposit, state }
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
function stateFromTuple(state: {
|
|
909
|
+
settled: bigint
|
|
910
|
+
deposit: bigint
|
|
911
|
+
closeRequestedAt: number
|
|
912
|
+
}): ChannelState {
|
|
913
|
+
assertUint96(state.settled)
|
|
914
|
+
assertUint96(state.deposit)
|
|
915
|
+
return {
|
|
916
|
+
settled: state.settled,
|
|
917
|
+
deposit: state.deposit,
|
|
918
|
+
closeRequestedAt: state.closeRequestedAt,
|
|
919
|
+
}
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
function descriptorTuple(descriptor: ChannelDescriptor) {
|
|
923
|
+
return {
|
|
924
|
+
payer: descriptor.payer,
|
|
925
|
+
payee: descriptor.payee,
|
|
926
|
+
operator: descriptor.operator,
|
|
927
|
+
token: descriptor.token,
|
|
928
|
+
salt: descriptor.salt,
|
|
929
|
+
authorizedSigner: descriptor.authorizedSigner,
|
|
930
|
+
expiringNonceHash: descriptor.expiringNonceHash,
|
|
931
|
+
} as const
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
async function sendPrecompileTransaction(
|
|
935
|
+
client: Client,
|
|
936
|
+
to: Address,
|
|
937
|
+
data: Hex,
|
|
938
|
+
label: string,
|
|
939
|
+
options?: ChannelTransactionOptions,
|
|
940
|
+
): Promise<Hex> {
|
|
941
|
+
if (options?.feePayer) {
|
|
942
|
+
const account = options.account ?? client.account
|
|
943
|
+
if (!account) throw new Error(`Cannot ${label} precompile channel: no account available.`)
|
|
944
|
+
const feeToken =
|
|
945
|
+
options.feeToken ??
|
|
946
|
+
(await resolveFeeToken({
|
|
947
|
+
account: options.feePayer.address,
|
|
948
|
+
candidateTokens: options.candidateFeeTokens,
|
|
949
|
+
client,
|
|
950
|
+
}))
|
|
951
|
+
const prepared = await prepareFeePayerCallTransaction(client, {
|
|
952
|
+
account,
|
|
953
|
+
data,
|
|
954
|
+
feeToken,
|
|
955
|
+
to,
|
|
956
|
+
})
|
|
957
|
+
assertPrecompileFeePayerPolicy({ prepared, policy: options.feePayerPolicy })
|
|
958
|
+
const serialized = await signTempoTransaction(client, {
|
|
959
|
+
...prepared,
|
|
960
|
+
account,
|
|
961
|
+
feePayer: options.feePayer,
|
|
962
|
+
})
|
|
963
|
+
const receipt = await sendRawTransactionSync(client, {
|
|
964
|
+
serializedTransaction: serialized as Transaction.TransactionSerializedTempo,
|
|
965
|
+
})
|
|
966
|
+
if (receipt.status !== 'success')
|
|
967
|
+
throw new VerificationFailedError({
|
|
968
|
+
reason: `${label} precompile transaction reverted: ${receipt.transactionHash}`,
|
|
969
|
+
})
|
|
970
|
+
return receipt.transactionHash
|
|
971
|
+
}
|
|
972
|
+
|
|
973
|
+
return sendPrecompileContractCall(client, {
|
|
974
|
+
account: options?.account,
|
|
975
|
+
to,
|
|
976
|
+
data,
|
|
977
|
+
feeToken: options?.feeToken,
|
|
978
|
+
})
|
|
979
|
+
}
|