From 7c71e4cc558ce2754c62ad28505c98f06b2342b9 Mon Sep 17 00:00:00 2001 From: o-az Date: Wed, 28 Jan 2026 10:06:27 -0800 Subject: [PATCH 01/20] chore: `next` branch --- package.json | 2 +- pnpm-lock.yaml | 70 +++++++++++++++++++++++++------------------------- 2 files changed, 36 insertions(+), 36 deletions(-) diff --git a/package.json b/package.json index 0ad304da..f4841690 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,7 @@ "devDependencies": { "@biomejs/biome": "^2.3.11", "@playwright/test": "^1.58.0", - "@types/node": "^25.0.10", + "@types/node": "^25.1.0", "@types/react": "^19.2.9", "@types/react-dom": "^19.2.3", "@typescript/native-preview": "7.0.0-dev.20260122.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f6d09881..ea6af60a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -87,13 +87,13 @@ importers: version: 2.44.4(typescript@5.9.3)(zod@4.3.5) vocs: specifier: https://pkg.pr.new/wevm/vocs@082ea99 - version: https://pkg.pr.new/wevm/vocs@082ea99(@types/react@19.2.9)(mermaid@11.12.2)(react-dom@19.2.3(react@19.2.3))(react-server-dom-webpack@19.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(webpack@5.104.1))(react@19.2.3)(rollup@4.56.0)(typescript@5.9.3)(vite@7.3.1(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))(waku@1.0.0-alpha.2(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(react-dom@19.2.3(react@19.2.3))(react-server-dom-webpack@19.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(webpack@5.104.1))(react@19.2.3)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) + version: https://pkg.pr.new/wevm/vocs@082ea99(@types/react@19.2.9)(mermaid@11.12.2)(react-dom@19.2.3(react@19.2.3))(react-server-dom-webpack@19.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(webpack@5.104.1))(react@19.2.3)(rollup@4.56.0)(typescript@5.9.3)(vite@7.3.1(@types/node@25.1.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))(waku@1.0.0-alpha.2(@types/node@25.1.0)(jiti@2.6.1)(lightningcss@1.30.2)(react-dom@19.2.3(react@19.2.3))(react-server-dom-webpack@19.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(webpack@5.104.1))(react@19.2.3)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) wagmi: specifier: 3.4.1 version: 3.4.1(@tanstack/query-core@5.90.19)(@tanstack/react-query@5.90.19(react@19.2.3))(@types/react@19.2.9)(ox@0.11.3(typescript@5.9.3)(zod@4.3.5))(react@19.2.3)(typescript@5.9.3)(viem@2.44.4(typescript@5.9.3)(zod@4.3.5)) waku: specifier: 1.0.0-alpha.2 - version: 1.0.0-alpha.2(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(react-dom@19.2.3(react@19.2.3))(react-server-dom-webpack@19.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(webpack@5.104.1))(react@19.2.3)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) + version: 1.0.0-alpha.2(@types/node@25.1.0)(jiti@2.6.1)(lightningcss@1.30.2)(react-dom@19.2.3(react@19.2.3))(react-server-dom-webpack@19.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(webpack@5.104.1))(react@19.2.3)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) zod: specifier: ^4.3.5 version: 4.3.5 @@ -105,8 +105,8 @@ importers: specifier: ^1.58.0 version: 1.58.0 '@types/node': - specifier: ^25.0.10 - version: 25.0.10 + specifier: ^25.1.0 + version: 25.1.0 '@types/react': specifier: ^19.2.9 version: 19.2.9 @@ -118,7 +118,7 @@ importers: version: 7.0.0-dev.20260122.3 '@vitejs/plugin-react': specifier: ^5.1.2 - version: 5.1.2(vite@7.3.1(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) + version: 5.1.2(vite@7.3.1(@types/node@25.1.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) anser: specifier: ^2.3.5 version: 2.3.5 @@ -136,7 +136,7 @@ importers: version: 1.6.0(react@19.2.3) vite: specifier: ^7.3.1 - version: 7.3.1(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) + version: 7.3.1(@types/node@25.1.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) packages: @@ -1350,8 +1350,8 @@ packages: '@types/ms@2.1.0': resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} - '@types/node@25.0.10': - resolution: {integrity: sha512-zWW5KPngR/yvakJgGOmZ5vTBemDoSqF3AcV/LrO5u5wTWyEAVVh+IT39G4gtyAkh3CtTZs8aX/yRM82OfzHJRg==} + '@types/node@25.1.0': + resolution: {integrity: sha512-t7frlewr6+cbx+9Ohpl0NOTKXZNV9xHRmNOvql47BFJKcEG1CxtxlPEEe+gR9uhVWM4DwhnvTF110mIL4yP9RA==} '@types/react-dom@19.2.3': resolution: {integrity: sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==} @@ -4961,12 +4961,12 @@ snapshots: '@tailwindcss/oxide-win32-arm64-msvc': 4.1.18 '@tailwindcss/oxide-win32-x64-msvc': 4.1.18 - '@tailwindcss/vite@4.1.18(vite@7.3.1(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))': + '@tailwindcss/vite@4.1.18(vite@7.3.1(@types/node@25.1.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))': dependencies: '@tailwindcss/node': 4.1.18 '@tailwindcss/oxide': 4.1.18 tailwindcss: 4.1.18 - vite: 7.3.1(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) + vite: 7.3.1(@types/node@25.1.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) '@takumi-rs/core-darwin-arm64@0.62.8': optional: true @@ -5194,7 +5194,7 @@ snapshots: '@types/ms@2.1.0': {} - '@types/node@25.0.10': + '@types/node@25.1.0': dependencies: undici-types: 7.16.0 @@ -5261,7 +5261,7 @@ snapshots: optionalDependencies: react: 19.2.3 - '@vitejs/plugin-react@5.1.2(vite@7.3.1(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))': + '@vitejs/plugin-react@5.1.2(vite@7.3.1(@types/node@25.1.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))': dependencies: '@babel/core': 7.28.6 '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.6) @@ -5269,11 +5269,11 @@ snapshots: '@rolldown/pluginutils': 1.0.0-beta.53 '@types/babel__core': 7.20.5 react-refresh: 0.18.0 - vite: 7.3.1(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) + vite: 7.3.1(@types/node@25.1.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) transitivePeerDependencies: - supports-color - '@vitejs/plugin-rsc@0.5.16(react-dom@19.2.3(react@19.2.3))(react-server-dom-webpack@19.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(webpack@5.104.1))(react@19.2.3)(vite@7.3.1(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))': + '@vitejs/plugin-rsc@0.5.16(react-dom@19.2.3(react@19.2.3))(react-server-dom-webpack@19.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(webpack@5.104.1))(react@19.2.3)(vite@7.3.1(@types/node@25.1.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))': dependencies: es-module-lexer: 2.0.0 estree-walker: 3.0.3 @@ -5284,8 +5284,8 @@ snapshots: srvx: 0.10.1 strip-literal: 3.1.0 turbo-stream: 3.1.0 - vite: 7.3.1(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) - vitefu: 1.1.1(vite@7.3.1(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) + vite: 7.3.1(@types/node@25.1.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) + vitefu: 1.1.1(vite@7.3.1(@types/node@25.1.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) optionalDependencies: react-server-dom-webpack: 19.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(webpack@5.104.1) @@ -6326,7 +6326,7 @@ snapshots: jest-worker@27.5.1: dependencies: - '@types/node': 25.0.10 + '@types/node': 25.1.0 merge-stream: 2.0.0 supports-color: 8.1.1 @@ -7213,7 +7213,7 @@ snapshots: '@protobufjs/path': 1.1.2 '@protobufjs/pool': 1.1.0 '@protobufjs/utf8': 1.1.0 - '@types/node': 25.0.10 + '@types/node': 25.1.0 long: 5.3.2 proxy-addr@2.0.7: @@ -7930,11 +7930,11 @@ snapshots: vite-plugin-arraybuffer@0.1.2: {} - vite-plugin-wasm@3.5.0(vite@7.3.1(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)): + vite-plugin-wasm@3.5.0(vite@7.3.1(@types/node@25.1.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)): dependencies: - vite: 7.3.1(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) + vite: 7.3.1(@types/node@25.1.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) - vite@7.3.1(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2): + vite@7.3.1(@types/node@25.1.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2): dependencies: esbuild: 0.27.2 fdir: 6.5.0(picomatch@4.0.3) @@ -7943,7 +7943,7 @@ snapshots: rollup: 4.56.0 tinyglobby: 0.2.15 optionalDependencies: - '@types/node': 25.0.10 + '@types/node': 25.1.0 fsevents: 2.3.3 jiti: 2.6.1 lightningcss: 1.30.2 @@ -7951,11 +7951,11 @@ snapshots: tsx: 4.21.0 yaml: 2.8.2 - vitefu@1.1.1(vite@7.3.1(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)): + vitefu@1.1.1(vite@7.3.1(@types/node@25.1.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)): optionalDependencies: - vite: 7.3.1(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) + vite: 7.3.1(@types/node@25.1.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) - vocs@https://pkg.pr.new/wevm/vocs@082ea99(@types/react@19.2.9)(mermaid@11.12.2)(react-dom@19.2.3(react@19.2.3))(react-server-dom-webpack@19.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(webpack@5.104.1))(react@19.2.3)(rollup@4.56.0)(typescript@5.9.3)(vite@7.3.1(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))(waku@1.0.0-alpha.2(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(react-dom@19.2.3(react@19.2.3))(react-server-dom-webpack@19.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(webpack@5.104.1))(react@19.2.3)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)): + vocs@https://pkg.pr.new/wevm/vocs@082ea99(@types/react@19.2.9)(mermaid@11.12.2)(react-dom@19.2.3(react@19.2.3))(react-server-dom-webpack@19.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(webpack@5.104.1))(react@19.2.3)(rollup@4.56.0)(typescript@5.9.3)(vite@7.3.1(@types/node@25.1.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))(waku@1.0.0-alpha.2(@types/node@25.1.0)(jiti@2.6.1)(lightningcss@1.30.2)(react-dom@19.2.3(react@19.2.3))(react-server-dom-webpack@19.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(webpack@5.104.1))(react@19.2.3)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)): dependencies: '@base-ui/react': 1.1.0(@types/react@19.2.9)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@codesandbox/sandpack-react': 2.20.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) @@ -7975,11 +7975,11 @@ snapshots: '@shikijs/types': 3.21.0 '@svgr/core': 8.1.0(typescript@5.9.3) '@svgr/plugin-jsx': 8.1.0(@svgr/core@8.1.0(typescript@5.9.3)) - '@tailwindcss/vite': 4.1.18(vite@7.3.1(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) + '@tailwindcss/vite': 4.1.18(vite@7.3.1(@types/node@25.1.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) '@takumi-rs/image-response': 0.62.8 '@takumi-rs/wasm': 0.62.8 - '@vitejs/plugin-react': 5.1.2(vite@7.3.1(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) - '@vitejs/plugin-rsc': 0.5.16(react-dom@19.2.3(react@19.2.3))(react-server-dom-webpack@19.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(webpack@5.104.1))(react@19.2.3)(vite@7.3.1(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) + '@vitejs/plugin-react': 5.1.2(vite@7.3.1(@types/node@25.1.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) + '@vitejs/plugin-rsc': 0.5.16(react-dom@19.2.3(react@19.2.3))(react-server-dom-webpack@19.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(webpack@5.104.1))(react@19.2.3)(vite@7.3.1(@types/node@25.1.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) cac: 6.7.14 cva: class-variance-authority@0.7.1 esast-util-from-js: 2.0.1 @@ -8023,13 +8023,13 @@ snapshots: urlpattern-polyfill: 10.1.0 vfile: 6.0.3 vite-plugin-arraybuffer: 0.1.2 - vite-plugin-wasm: 3.5.0(vite@7.3.1(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) + vite-plugin-wasm: 3.5.0(vite@7.3.1(@types/node@25.1.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) yaml: 2.8.2 zod: 4.3.5 optionalDependencies: mermaid: 11.12.2 - vite: 7.3.1(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) - waku: 1.0.0-alpha.2(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(react-dom@19.2.3(react@19.2.3))(react-server-dom-webpack@19.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(webpack@5.104.1))(react@19.2.3)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) + vite: 7.3.1(@types/node@25.1.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) + waku: 1.0.0-alpha.2(@types/node@25.1.0)(jiti@2.6.1)(lightningcss@1.30.2)(react-dom@19.2.3(react@19.2.3))(react-server-dom-webpack@19.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(webpack@5.104.1))(react@19.2.3)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) transitivePeerDependencies: - '@cfworker/json-schema' - '@remix-run/react' @@ -8091,11 +8091,11 @@ snapshots: - ox - porto - waku@1.0.0-alpha.2(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(react-dom@19.2.3(react@19.2.3))(react-server-dom-webpack@19.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(webpack@5.104.1))(react@19.2.3)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2): + waku@1.0.0-alpha.2(@types/node@25.1.0)(jiti@2.6.1)(lightningcss@1.30.2)(react-dom@19.2.3(react@19.2.3))(react-server-dom-webpack@19.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(webpack@5.104.1))(react@19.2.3)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2): dependencies: '@hono/node-server': 1.19.9(hono@4.11.5) - '@vitejs/plugin-react': 5.1.2(vite@7.3.1(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) - '@vitejs/plugin-rsc': 0.5.16(react-dom@19.2.3(react@19.2.3))(react-server-dom-webpack@19.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(webpack@5.104.1))(react@19.2.3)(vite@7.3.1(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) + '@vitejs/plugin-react': 5.1.2(vite@7.3.1(@types/node@25.1.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) + '@vitejs/plugin-rsc': 0.5.16(react-dom@19.2.3(react@19.2.3))(react-server-dom-webpack@19.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(webpack@5.104.1))(react@19.2.3)(vite@7.3.1(@types/node@25.1.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) dotenv: 17.2.3 hono: 4.11.5 magic-string: 0.30.21 @@ -8104,7 +8104,7 @@ snapshots: react-dom: 19.2.3(react@19.2.3) react-server-dom-webpack: 19.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(webpack@5.104.1) rsc-html-stream: 0.0.7 - vite: 7.3.1(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) + vite: 7.3.1(@types/node@25.1.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) transitivePeerDependencies: - '@types/node' - jiti From 7160ff7a7060e22dcc7ba916c7721e12d6c6148d Mon Sep 17 00:00:00 2001 From: o-az Date: Wed, 28 Jan 2026 10:15:58 -0800 Subject: [PATCH 02/20] chore: trigger deployment to `next` --- .gitignore | 2 +- package.json | 2 +- pnpm-lock.yaml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index af326290..b03dc1a3 100644 --- a/.gitignore +++ b/.gitignore @@ -26,7 +26,7 @@ src/pages.gen.ts .env .vercel .vocs - +.env*.local src/pages/protocol/tips/tip-* # Playwright diff --git a/package.json b/package.json index f4841690..a3f1da12 100644 --- a/package.json +++ b/package.json @@ -51,7 +51,7 @@ "@vitejs/plugin-react": "^5.1.2", "anser": "^2.3.5", "tsx": "^4.21.0", - "typescript": "~5.9.3", + "typescript": "^5.9.3", "use-sync-external-store": "^1.6.0", "vite": "^7.3.1" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ea6af60a..262dd04b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -129,7 +129,7 @@ importers: specifier: ^4.21.0 version: 4.21.0 typescript: - specifier: ~5.9.3 + specifier: ^5.9.3 version: 5.9.3 use-sync-external-store: specifier: ^1.6.0 From 57625e81622de68e0a5c89ea83855fbf57e5baa5 Mon Sep 17 00:00:00 2001 From: o-az Date: Wed, 28 Jan 2026 10:21:14 -0800 Subject: [PATCH 03/20] chore: trigger deployment to `next` 2 From 993b0b6ff29e659ff2e06071110f9a0827643d93 Mon Sep 17 00:00:00 2001 From: o-az Date: Wed, 28 Jan 2026 10:25:04 -0800 Subject: [PATCH 04/20] chore: trigger deployment to `next` 3 From 52347c81cc0cc02601aea6c9dabdcf8554a13ae7 Mon Sep 17 00:00:00 2001 From: o-az Date: Thu, 29 Jan 2026 14:28:36 -0800 Subject: [PATCH 05/20] feat: update to include release notes --- src/pages/guide/node/installation.mdx | 7 ++-- src/pages/guide/node/operate-validator.mdx | 10 ++++++ src/pages/guide/node/validator.mdx | 8 +++-- .../payments/send-parallel-transactions.mdx | 32 ++++++++++++++++--- src/pages/protocol/fees/spec-fee.mdx | 12 +++++++ .../protocol/transactions/AccountKeychain.mdx | 4 +-- src/pages/quickstart/evm-compatibility.mdx | 13 ++++++++ src/pages/quickstart/verify-contracts.mdx | 5 ++- src/pages/sdk/go/index.mdx | 2 +- 9 files changed, 81 insertions(+), 12 deletions(-) diff --git a/src/pages/guide/node/installation.mdx b/src/pages/guide/node/installation.mdx index a89919b3..6bc64d92 100644 --- a/src/pages/guide/node/installation.mdx +++ b/src/pages/guide/node/installation.mdx @@ -12,8 +12,11 @@ The versions across networks may not be compatible, as such, please consult the | Network | Version | |----------|---------| -| Andantino | v0.8.2 | -| Moderato | v1.0.0-rc.1 | +| Moderato (Testnet) | v1.1.0 | + +:::warning +The `andantino` chainspec has been removed as of v1.1.0. Testnet nodes must use `--chain moderato`. +::: ## Pre-built Binary diff --git a/src/pages/guide/node/operate-validator.mdx b/src/pages/guide/node/operate-validator.mdx index 9c0a9a0b..c2c98496 100644 --- a/src/pages/guide/node/operate-validator.mdx +++ b/src/pages/guide/node/operate-validator.mdx @@ -172,6 +172,16 @@ The old validator identity must be deactivated before the new one is activated If you lose your signing share (stored on the database in `/consensus/`), you will need to rotate to a new validator identity. This requires coordinating with the Tempo team to deactivate your old identity and register a new one. We're planning to release a high-availability feature that allows storing consensus data in an external database, which will enable signing share recovery without the need for key rotation. +### Deleting Signing Shares + +:::warning[Breaking Change in v1.1.0] +`--delete-signing-share` now requires the `--force` flag to prevent accidental deletion of validator signing keys. **Update any automation scripts that manage validator key lifecycle.** +::: + +```bash +tempo consensus --delete-signing-share --force +``` + ## Log Management ### Parsing Logs diff --git a/src/pages/guide/node/validator.mdx b/src/pages/guide/node/validator.mdx index 36b3bb10..f5f57a70 100644 --- a/src/pages/guide/node/validator.mdx +++ b/src/pages/guide/node/validator.mdx @@ -38,12 +38,12 @@ The public key should match the output of the `generate-private-key` command. The process for running a validator node is very similar to [running a full node](/guide/node/rpc). -You should start by downloading the latest snapshot using `tempo download --chain `. Downloading the snapshot allows your validator to start participating in consensus much faster. +You should start by downloading the latest snapshot using `tempo download --chain `. Downloading the snapshot allows your validator to start participating in consensus much faster. Once you've downloaded the snapshot and have been whitelisted on-chain, you can proceed to run the validator node as such: ```bash tempo node --datadir \ - --chain \ + --chain moderato \ --port 30303 \ --discovery.addr 0.0.0.0 \ --discovery.port 30303 \ @@ -51,6 +51,10 @@ tempo node --datadir \ --consensus.fee-recipient \ ``` +:::warning[Testnet Chain Name Change] +As of v1.1.0, testnet nodes must use `--chain moderato`. The previous `andantino` chainspec has been removed. +::: + The notable difference between RPC nodes and validator nodes is the omission of the `--follow` argument and the addition of the `--consensus.signing-key` and `--consensus.fee-recipient` arguments. The fee recipient is the address that will receive transaction fees in your validators' proposed blocks. Once your node is up, it may not start syncing immediately. This is because your node might not be part of the active set. In most cases, your validator will enter the active set in under 6 hours after the on-chain addition of the validator identity. diff --git a/src/pages/guide/payments/send-parallel-transactions.mdx b/src/pages/guide/payments/send-parallel-transactions.mdx index aea1ddf0..15abaae1 100644 --- a/src/pages/guide/payments/send-parallel-transactions.mdx +++ b/src/pages/guide/payments/send-parallel-transactions.mdx @@ -1,5 +1,5 @@ --- -description: Submit multiple transactions concurrently using Tempo's 2D nonce system. Use nonce keys to avoid waiting for sequential confirmations. +description: Submit multiple transactions concurrently using Tempo's nonce system. Choose between 2D nonces for ordered sequences or expiring nonces for fire-and-forget. --- import * as Demo from '../../../components/guides/Demo.tsx' @@ -9,11 +9,35 @@ import { Cards, Card } from 'vocs' # Send Parallel Transactions -Submit multiple transactions in parallel using Tempo's [2D nonces](/protocol/transactions/spec-tempo-transaction). The `nonceKey` property allow you to send concurrent transactions without waiting for each one to confirm sequentially. +Submit multiple transactions in parallel using Tempo's flexible nonce system. Choose between: -## Understanding nonce keys +- **[2D nonces](/protocol/transactions/spec-tempo-transaction)**: Independent nonce sequences for ordered transaction groups +- **[Expiring nonces](/protocol/tips/tip-1009)**: Time-bounded replay protection for fire-and-forget transactions *(recommended for most use cases)* -Tempo uses a **2D nonce system** that enables parallel transaction execution: +## Expiring Nonces (Recommended) + +[TIP-1009](/protocol/tips/tip-1009) introduces expiring nonces: transactions specify a `validBefore` timestamp (max 30s in the future) instead of tracking sequential nonces. This is the simplest approach for parallel submission. + +To use expiring nonces, set `nonceKey` to `UINT256_MAX` (`0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff`). This signals to the protocol that the transaction uses time-based replay protection instead of sequential nonces. + +```typescript +const tx = await Actions.token.transfer(config, { + amount: parseUnits('100', 6), + to: recipient, + token: alphaUsd, + nonceKey: BigInt('0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'), + validBefore: Math.floor(Date.now() / 1000) + 30, +}) +``` + +Benefits: +- No nonce tracking required +- Automatic replay protection via circular buffer +- No permanent state bloat from unused nonce keys + +## 2D Nonces + +For cases requiring ordered sequences within a key, Tempo's **2D nonce system** enables parallel transaction execution: - **Protocol nonce (key 0)**: The default sequential nonce. Transactions must be processed in order. - **User nonces (keys 1+)**: Independent nonce sequences that allow concurrent transaction submission. diff --git a/src/pages/protocol/fees/spec-fee.mdx b/src/pages/protocol/fees/spec-fee.mdx index 3d5e7040..bff9a708 100644 --- a/src/pages/protocol/fees/spec-fee.mdx +++ b/src/pages/protocol/fees/spec-fee.mdx @@ -154,6 +154,18 @@ On the Moderato testnet, validators currently expect alphaUSD (one of the tokens If validators have not specified a fee token preference, the protocol falls back to expecting pathUSD as their fee token. +## Gas Parameters + +As of [TIP-1010](/protocol/tips/tip-1010), Tempo uses the following mainnet gas parameters: + +| Parameter | Value | +|-----------|-------| +| Base fee | 20 gwei | +| Total block gas limit | 500M gas | +| General gas limit | 30M gas/block | + +A standard TIP-20 transfer costs approximately 0.1 cent at the base fee. + ### Removing validator preference To remove a validator token preference, set it to the zero address: diff --git a/src/pages/protocol/transactions/AccountKeychain.mdx b/src/pages/protocol/transactions/AccountKeychain.mdx index 27b01902..51bc144b 100644 --- a/src/pages/protocol/transactions/AccountKeychain.mdx +++ b/src/pages/protocol/transactions/AccountKeychain.mdx @@ -20,7 +20,7 @@ The Tempo Transaction type unlocks a number of new signature schemes, including Access Keys are secondary signing keys authorized by an account's Root Key. They can sign transactions on behalf of the account with the following restrictions: -- **Expiry**: Unix timestamp when the key becomes invalid (0 = never expires) +- **Expiry**: Unix timestamp when the key becomes invalid (0 = never expires, non-zero values must be > current timestamp) - **Spending Limits**: Per-TIP20 token limits that deplete as tokens are spent - Limits deplete as tokens are spent and can be updated by the Root Key via `updateSpendingLimit()` - Spending limits only apply to TIP20 `transfer()`, `transferWithMemo()`, `approve()`, and `startReward()` calls @@ -136,7 +136,7 @@ interface IAccountKeychain { * The protocol enforces this restriction by checking transactionKey[msg.sender] * @param keyId The key identifier (address) to authorize * @param signatureType Signature type of the key (0: Secp256k1, 1: P256, 2: WebAuthn) - * @param expiry Unix timestamp when key expires (0 = never expires) + * @param expiry Unix timestamp when key expires (MUST be > current_timestamp, or 0 for never expires) * @param enforceLimits Whether to enforce spending limits for this key * @param limits Initial spending limits for tokens (only used if enforceLimits is true) */ diff --git a/src/pages/quickstart/evm-compatibility.mdx b/src/pages/quickstart/evm-compatibility.mdx index 24749e3e..bb2cd808 100644 --- a/src/pages/quickstart/evm-compatibility.mdx +++ b/src/pages/quickstart/evm-compatibility.mdx @@ -95,6 +95,19 @@ If a wallet wants to submit a non-TIP20 transaction without having to submit the At the VM layer, all opcodes are supported out of the box. Due to the lack of a native token, native token balance is always returning zero balances. +### State Creation Costs + +Tempo uses higher gas costs for state-creating operations to prevent state growth attacks ([TIP-1000](/protocol/tips/tip-1000)): + +| Operation | Tempo | Ethereum | +|-----------|-------|----------| +| New storage slot (SSTORE 0→non-zero) | 250,000 gas | 20,000 gas | +| Account creation | 250,000 gas | 0 gas | +| Contract creation per byte | 1,000 gas | 200 gas | +| Transaction gas cap | 30M gas | 30M gas | + +This means transfers to new addresses cost ~300k gas, and contract deployments cost 5-10x more than on Ethereum. Update your `gas_limit` estimates accordingly. + ### Balance Opcodes and RPC Methods | Feature | Behavior on Tempo | Alternatives | diff --git a/src/pages/quickstart/verify-contracts.mdx b/src/pages/quickstart/verify-contracts.mdx index f0aba7d6..0dc885c8 100644 --- a/src/pages/quickstart/verify-contracts.mdx +++ b/src/pages/quickstart/verify-contracts.mdx @@ -187,10 +187,13 @@ View the full API documentation at [contracts.tempo.xyz/docs](https://contracts. | Network | Chain ID | |---------|----------| | Tempo Mainnet | `4217` | -| Tempo Testnet (Andantino) | `42429` | | Tempo Testnet (Moderato) | `42431` | | Tempo Devnet | `31318` | +:::info +The `andantino` testnet (chain ID `42429`) has been deprecated. Use `moderato` (chain ID `42431`) for testnet development. +::: + ## Troubleshooting :::tip diff --git a/src/pages/sdk/go/index.mdx b/src/pages/sdk/go/index.mdx index f54e3b8f..961c2d11 100644 --- a/src/pages/sdk/go/index.mdx +++ b/src/pages/sdk/go/index.mdx @@ -100,7 +100,7 @@ func main() { // [!code focus:13] tx := transaction.New() tx.ChainID = big.NewInt(42431) // Tempo testnet - tx.MaxFeePerGas = big.NewInt(2000000000) + tx.MaxFeePerGas = big.NewInt(20000000000) // 20 gwei base fee tx.MaxPriorityFeePerGas = big.NewInt(1000000000) tx.Gas = 100000 tx.Calls = []transaction.Call{{ From 716e57d498af06bfc007c08765daf31d3730b6e1 Mon Sep 17 00:00:00 2001 From: tmm Date: Thu, 29 Jan 2026 12:32:53 -0500 Subject: [PATCH 06/20] test: e2e (#49) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a3f1da12..0333b5b2 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,7 @@ "devDependencies": { "@biomejs/biome": "^2.3.11", "@playwright/test": "^1.58.0", - "@types/node": "^25.1.0", + "@types/node": "^25.0.10", "@types/react": "^19.2.9", "@types/react-dom": "^19.2.3", "@typescript/native-preview": "7.0.0-dev.20260122.3", From 22b06356f97f6cbe8ecfea606d943c64c1a2e5d9 Mon Sep 17 00:00:00 2001 From: o-az Date: Wed, 28 Jan 2026 10:21:14 -0800 Subject: [PATCH 07/20] chore: trigger deployment to `next` 2 From d8d1733d27494aac5dfd0b3e2c5f283b1b6f5f78 Mon Sep 17 00:00:00 2001 From: o-az Date: Wed, 28 Jan 2026 10:25:04 -0800 Subject: [PATCH 08/20] chore: trigger deployment to `next` 3 From 5f8b04ca71b9cfef944c778e66ee59e2e686dcab Mon Sep 17 00:00:00 2001 From: o-az Date: Fri, 30 Jan 2026 06:58:45 -0800 Subject: [PATCH 09/20] chore: sync lockfile --- pnpm-lock.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 262dd04b..d37fc1ce 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -105,7 +105,7 @@ importers: specifier: ^1.58.0 version: 1.58.0 '@types/node': - specifier: ^25.1.0 + specifier: ^25.0.10 version: 25.1.0 '@types/react': specifier: ^19.2.9 @@ -3224,6 +3224,7 @@ packages: react-server-dom-webpack@19.2.3: resolution: {integrity: sha512-ifo7aqqdNJyV6U2zuvvWX4rRQ51pbleuUFNG7ZYhIuSuWZzQPbfmYv11GNsyJm/3uGNbt8buJ9wmoISn/uOAfw==} engines: {node: '>=0.10.0'} + deprecated: High Security Vulnerability in React Server Components peerDependencies: react: ^19.2.3 react-dom: ^19.2.3 From b90d3609ea98ca5683ebccb297fe170516912a4a Mon Sep 17 00:00:00 2001 From: Georgios Konstantopoulos Date: Fri, 30 Jan 2026 07:45:46 -0800 Subject: [PATCH 10/20] docs(foundry): add T1 features - 2D nonces, expiring nonces, access keys, sponsors, batching (#55) Co-authored-by: George --- src/pages/sdk/foundry/index.mdx | 69 +++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/src/pages/sdk/foundry/index.mdx b/src/pages/sdk/foundry/index.mdx index 1c28c96b..dd8de308 100644 --- a/src/pages/sdk/foundry/index.mdx +++ b/src/pages/sdk/foundry/index.mdx @@ -130,10 +130,24 @@ forge script script/Mail.s.sol \ --sender \ --broadcast \ --verify + +# Batch multiple calls into a single atomic transaction +forge script script/Deploy.s.sol \ + --broadcast --batch \ + --rpc-url $TEMPO_RPC_URL \ + --private-key $PRIVATE_KEY ``` For more verification options including verifying existing contracts and API verification, see [Contract Verification](/quickstart/verify-contracts). +:::warning[Batch Transaction Rules] +- **Atomic execution**: If any call reverts, the entire batch reverts +- **Single CREATE allowed**: At most one contract deployment per batch +- **CREATE must be first**: Deployment must be the first operation +- **Value must be zero**: Since Tempo has no native token, value must be 0 +- **Silent failures**: Calling a non-existent function without a fallback succeeds silently +::: + ### Interact & debug with `cast` ```bash @@ -173,6 +187,61 @@ cast send \ # Replay a transaction by hash: cast run \ --rpc-url $TEMPO_RPC_URL + +# Send a batch transaction with multiple calls: +cast batch-send \ + --call "::increment()" \ + --call "::setNumber(uint256):500" \ + --rpc-url $TEMPO_RPC_URL \ + --private-key $PRIVATE_KEY + +# Batch with pre-encoded calldata: +ENCODED=$(cast calldata "setNumber(uint256)" 200) +cast batch-send \ + --call "::$ENCODED" \ + --call "::setNumber(uint256):101" \ + --rpc-url $TEMPO_RPC_URL \ + --private-key $PRIVATE_KEY + +# Sponsored transaction (gasless for sender): +# Step 1: Get the fee payer signature hash +FEE_PAYER_HASH=$(cast mktx 'increment()' \ + --rpc-url $TEMPO_RPC_URL \ + --private-key $SENDER_KEY \ + --print-sponsor-hash) +# Step 2: Sponsor signs the hash +SPONSOR_SIG=$(cast wallet sign --private-key $SPONSOR_KEY "$FEE_PAYER_HASH" --no-hash) +# Step 3: Send with sponsor signature +cast send 'increment()' \ + --rpc-url $TEMPO_RPC_URL \ + --private-key $SENDER_KEY \ + --sponsor-signature "$SPONSOR_SIG" + +# Send with 2D nonce (parallel tx submission): +cast send 'increment()' \ + --rpc-url $TEMPO_RPC_URL \ + --private-key $PRIVATE_KEY \ + --nonce 0 --nonce-key 1 + +# Send with expiring nonce (time-bounded tx, max 30s): +VALID_BEFORE=$(($(date +%s) + 25)) +cast send 'increment()' \ + --rpc-url $TEMPO_RPC_URL \ + --private-key $PRIVATE_KEY \ + --expiring-nonce --valid-before $VALID_BEFORE + +# Send with access key (delegated signing): +# First authorize the key via Account Keychain precompile +cast send 0xAAAAAAAA00000000000000000000000000000000 \ + 'authorizeKey(address,uint8,uint64,bool,(address,uint256)[])' \ + $ACCESS_KEY_ADDR 0 1893456000 false "[]" \ + --rpc-url $TEMPO_RPC_URL \ + --private-key $ROOT_PRIVATE_KEY +# Then send using the access key +cast send 'increment()' \ + --rpc-url $TEMPO_RPC_URL \ + --access-key $ACCESS_KEY_PRIVATE_KEY \ + --root-account $ROOT_ADDRESS ``` ### Limitations From c4d8c29b7006dfa3b32b1c535e4e37ee173f0233 Mon Sep 17 00:00:00 2001 From: onbjerg Date: Fri, 30 Jan 2026 23:05:26 +0100 Subject: [PATCH 11/20] chore: add small Rust example for expiring nonces (#56) Co-authored-by: o-az --- .../payments/send-parallel-transactions.mdx | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/pages/guide/payments/send-parallel-transactions.mdx b/src/pages/guide/payments/send-parallel-transactions.mdx index 15abaae1..77f51c34 100644 --- a/src/pages/guide/payments/send-parallel-transactions.mdx +++ b/src/pages/guide/payments/send-parallel-transactions.mdx @@ -20,7 +20,9 @@ Submit multiple transactions in parallel using Tempo's flexible nonce system. Ch To use expiring nonces, set `nonceKey` to `UINT256_MAX` (`0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff`). This signals to the protocol that the transaction uses time-based replay protection instead of sequential nonces. -```typescript +:::code-group + +```typescript [TypeScript] const tx = await Actions.token.transfer(config, { amount: parseUnits('100', 6), to: recipient, @@ -30,6 +32,18 @@ const tx = await Actions.token.transfer(config, { }) ``` +```rust [Rust] +let pending = provider + .send_transaction(TempoTransactionRequest { + nonce_key: Some(U256::MAX), + valid_before: Some(SystemTime::now().duration_since(UNIX_EPOCH).as_secs() + 30), + ..Default::default(), + }) + .await?; +``` + +:::code-group + Benefits: - No nonce tracking required - Automatic replay protection via circular buffer From 10b216f82106aa8c442a60f9c1d83a1e335faa53 Mon Sep 17 00:00:00 2001 From: o-az Date: Fri, 30 Jan 2026 14:15:37 -0800 Subject: [PATCH 12/20] fix: prioritize `VERCEL_BRANCH_URL` --- biome.json | 27 ++++++++++++++++++++++++--- env.d.ts | 26 ++++++++++++++++++++++++++ vocs.config.ts | 3 +++ 3 files changed, 53 insertions(+), 3 deletions(-) create mode 100644 env.d.ts diff --git a/biome.json b/biome.json index 933e82b6..59c87871 100644 --- a/biome.json +++ b/biome.json @@ -1,6 +1,12 @@ { "$schema": "https://biomejs.dev/schemas/2.3.11/schema.json", - "assist": { "actions": { "source": { "organizeImports": "on" } } }, + "assist": { + "actions": { + "source": { + "organizeImports": "on" + } + } + }, "formatter": { "enabled": true, "indentStyle": "space", @@ -15,7 +21,9 @@ } }, "css": { - "parser": { "tailwindDirectives": true }, + "parser": { + "tailwindDirectives": true + }, "formatter": { "enabled": true }, @@ -41,5 +49,18 @@ "files": { "ignoreUnknown": false, "includes": ["**", "!dist", "!node_modules", "!specs/lib", "!src/snippets/unformatted"] - } + }, + "overrides": [ + { + "includes": ["env.d.ts"], + "linter": { + "rules": { + "recommended": true, + "correctness": { + "noUnusedVariables": "off" + } + } + } + } + ] } diff --git a/env.d.ts b/env.d.ts new file mode 100644 index 00000000..5a86c157 --- /dev/null +++ b/env.d.ts @@ -0,0 +1,26 @@ +interface EnvironmentVariables { + readonly NODE_ENV: 'development' | 'production' | 'test' + + readonly VITE_BASE_URL: string + readonly VITE_POSTHOG_KEY: string + readonly VITE_POSTHOG_HOST: string + readonly VITE_TEMPO_ENV: 'localnet' | 'devnet' | 'moderato' + + readonly INDEXSUPPLY_API_KEY: string + readonly SLACK_FEEDBACK_WEBHOOK: string + + readonly VERCEL_URL: string + readonly VERCEL_BRANCH_URL: string + readonly VERCEL_PROJECT_PRODUCTION_URL: string + readonly VERCEL_ENV: 'development' | 'production' | 'preview' +} + +declare namespace NodeJS { + interface ProcessEnv extends EnvironmentVariables {} +} + +interface ImportMetaEnv extends EnvironmentVariables {} + +interface ImportMeta { + readonly env: ImportMetaEnv +} diff --git a/vocs.config.ts b/vocs.config.ts index b9c657ad..e4f0a375 100644 --- a/vocs.config.ts +++ b/vocs.config.ts @@ -1,8 +1,11 @@ import { Changelog, defineConfig, Feedback, McpSource } from 'vocs/config' const baseUrl = (() => { + // VERCEL_BRANCH_URL is the stable URL for the branch (e.g., next.docs.tempo.xyz) + // VERCEL_URL is the deployment-specific URL which causes CORS issues with custom domains if (process.env.VERCEL_ENV === 'production') return `https://${process.env.VERCEL_PROJECT_PRODUCTION_URL}` + if (process.env.VERCEL_BRANCH_URL) return `https://${process.env.VERCEL_BRANCH_URL}` if (process.env.VERCEL_URL) return `https://${process.env.VERCEL_URL}` return '' })() From dce0d8d0f8c9cbb3439d917c8ff6aa838a4f8297 Mon Sep 17 00:00:00 2001 From: o-az Date: Fri, 30 Jan 2026 14:39:20 -0800 Subject: [PATCH 13/20] chore: use `VITE_BASE_URL` --- vocs.config.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/vocs.config.ts b/vocs.config.ts index e4f0a375..e5e36abd 100644 --- a/vocs.config.ts +++ b/vocs.config.ts @@ -1,6 +1,7 @@ import { Changelog, defineConfig, Feedback, McpSource } from 'vocs/config' const baseUrl = (() => { + if (process.env.VITE_BASE_URL) return process.env.VITE_BASE_URL // VERCEL_BRANCH_URL is the stable URL for the branch (e.g., next.docs.tempo.xyz) // VERCEL_URL is the deployment-specific URL which causes CORS issues with custom domains if (process.env.VERCEL_ENV === 'production') From 610534bc6b27023da0c5ec95df329f22d20f7d01 Mon Sep 17 00:00:00 2001 From: o-az Date: Fri, 30 Jan 2026 14:39:46 -0800 Subject: [PATCH 14/20] chore: use `VITE_BASE_URL` --- vocs.config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vocs.config.ts b/vocs.config.ts index e5e36abd..af65ff59 100644 --- a/vocs.config.ts +++ b/vocs.config.ts @@ -1,7 +1,7 @@ import { Changelog, defineConfig, Feedback, McpSource } from 'vocs/config' const baseUrl = (() => { - if (process.env.VITE_BASE_URL) return process.env.VITE_BASE_URL + if (URL.canParse(process.env.VITE_BASE_URL)) return process.env.VITE_BASE_URL // VERCEL_BRANCH_URL is the stable URL for the branch (e.g., next.docs.tempo.xyz) // VERCEL_URL is the deployment-specific URL which causes CORS issues with custom domains if (process.env.VERCEL_ENV === 'production') From f4d7c110b0d385de7fbc5caaf04dbe1248e6635b Mon Sep 17 00:00:00 2001 From: Georgios Konstantopoulos Date: Wed, 4 Feb 2026 09:22:18 -0800 Subject: [PATCH 15/20] docs(foundry): update tempo args to use --tempo. prefix, add anvil section (#70) Co-authored-by: Amp Co-authored-by: zerosnacks <95942363+zerosnacks@users.noreply.github.com> --- src/pages/sdk/foundry/index.mdx | 80 ++++++++++++++++++++++++++------- 1 file changed, 64 insertions(+), 16 deletions(-) diff --git a/src/pages/sdk/foundry/index.mdx b/src/pages/sdk/foundry/index.mdx index dd8de308..963cc751 100644 --- a/src/pages/sdk/foundry/index.mdx +++ b/src/pages/sdk/foundry/index.mdx @@ -107,7 +107,7 @@ forge create src/Mail.sol:Mail \ # Deploy a simple contract with custom fee token forge create src/Mail.sol:Mail \ - --fee-token \ + --tempo.fee-token \ --rpc-url $TEMPO_RPC_URL \ --interactive \ --broadcast \ @@ -124,7 +124,7 @@ forge script script/Mail.s.sol \ # Run a deployment script with custom fee token and verify forge script script/Mail.s.sol \ - --fee-token \ + --tempo.fee-token \ --rpc-url $TEMPO_RPC_URL \ --interactive \ --sender \ @@ -174,13 +174,13 @@ cast erc20 transfer \ # Transfer some of your ERC20 tokens with custom fee token: cast erc20 transfer \ - --fee-token + --tempo.fee-token \ --rpc-url $TEMPO_RPC_URL \ --interactive # Send a transaction with custom fee token: cast send \ - --fee-token \ + --tempo.fee-token \ --rpc-url $TEMPO_RPC_URL \ --interactive @@ -205,30 +205,24 @@ cast batch-send \ # Sponsored transaction (gasless for sender): # Step 1: Get the fee payer signature hash -FEE_PAYER_HASH=$(cast mktx 'increment()' \ - --rpc-url $TEMPO_RPC_URL \ - --private-key $SENDER_KEY \ - --print-sponsor-hash) +FEE_PAYER_HASH=$(cast mktx 'increment()' --rpc-url $TEMPO_RPC_URL --private-key $SENDER_KEY --tempo.print-sponsor-hash) # Step 2: Sponsor signs the hash SPONSOR_SIG=$(cast wallet sign --private-key $SPONSOR_KEY "$FEE_PAYER_HASH" --no-hash) # Step 3: Send with sponsor signature -cast send 'increment()' \ - --rpc-url $TEMPO_RPC_URL \ - --private-key $SENDER_KEY \ - --sponsor-signature "$SPONSOR_SIG" +cast send 'increment()' --rpc-url $TEMPO_RPC_URL --private-key $SENDER_KEY --tempo.sponsor-signature "$SPONSOR_SIG" # Send with 2D nonce (parallel tx submission): cast send 'increment()' \ --rpc-url $TEMPO_RPC_URL \ --private-key $PRIVATE_KEY \ - --nonce 0 --nonce-key 1 + --nonce 0 --tempo.nonce-key 1 # Send with expiring nonce (time-bounded tx, max 30s): VALID_BEFORE=$(($(date +%s) + 25)) cast send 'increment()' \ --rpc-url $TEMPO_RPC_URL \ --private-key $PRIVATE_KEY \ - --expiring-nonce --valid-before $VALID_BEFORE + --tempo.expiring-nonce --tempo.valid-before $VALID_BEFORE # Send with access key (delegated signing): # First authorize the key via Account Keychain precompile @@ -244,6 +238,60 @@ cast send 'increment()' \ --root-account $ROOT_ADDRESS ``` -### Limitations +### Local Development with Anvil + +Anvil supports Tempo mode for local testing and forking Tempo networks: + +```bash +# Start anvil in Tempo mode +anvil --tempo --hardfork t1 + +# Fork a live Tempo network for local testing +anvil --tempo --fork-url $TEMPO_RPC_URL + +# Test transactions on local anvil fork +cast send 'increment()' \ + --tempo.fee-token \ + --rpc-url http://127.0.0.1:8545 \ + --private-key $PRIVATE_KEY + +# 2D nonce on anvil fork +cast send 'increment()' \ + --tempo.fee-token \ + --rpc-url http://127.0.0.1:8545 \ + --private-key $PRIVATE_KEY \ + --nonce 0 --tempo.nonce-key 100 + +# Expiring nonce on anvil fork +cast send 'increment()' \ + --tempo.fee-token \ + --rpc-url http://127.0.0.1:8545 \ + --private-key $PRIVATE_KEY \ + --tempo.expiring-nonce --tempo.valid-before $(($(date +%s) + 25)) + +# Batch transactions on anvil fork +cast batch-send \ + --tempo.fee-token \ + --rpc-url http://127.0.0.1:8545 \ + --call "::increment()" \ + --call "::increment()" \ + --private-key $PRIVATE_KEY +``` + +## Tempo-Specific CLI Flags + +The following flags are available for `cast` and `forge script` for Tempo-specific features: + +| Flag | Description | Example | +|------|-------------|---------| +| `--tempo.fee-token
` | Specify the TIP-20 token to pay transaction fees | `--tempo.fee-token 0x20c0...0001` | +| `--tempo.nonce-key ` | 2D nonce key for parallel transaction submission | `--tempo.nonce-key 1` | +| `--tempo.expiring-nonce` | Enable expiring nonce for time-bounded transactions | `--tempo.expiring-nonce` | +| `--tempo.valid-before ` | Unix timestamp before which tx must execute (max 30s from now) | `--tempo.valid-before 1704067200` | +| `--tempo.valid-after ` | Unix timestamp after which tx can execute | `--tempo.valid-after 1704067100` | +| `--tempo.sponsor-signature ` | Pre-signed sponsor signature for gasless transactions | `--tempo.sponsor-signature 0x...` | +| `--tempo.print-sponsor-hash` | Print fee payer signature hash and exit (for sponsor to sign) | `--tempo.print-sponsor-hash` | + +Ledger and Trezor wallets are not yet compatible with any `--tempo.*` option. + -Ledger and Trezor wallets are not yet compatible with the `--fee-token` option. From fae2fc260f94db7f4101f5a5c445dc5760bb95ae Mon Sep 17 00:00:00 2001 From: jenpaff Date: Thu, 5 Feb 2026 16:52:12 +0000 Subject: [PATCH 16/20] fix: change andantino from 'removed' to 'deprecated' Amp-Thread-ID: https://ampcode.com/threads/T-019c2e2d-fdda-704c-8ebe-8ed7cda6f2d0 Co-authored-by: Amp --- src/pages/guide/node/installation.mdx | 4 ++-- src/pages/guide/node/validator.mdx | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/pages/guide/node/installation.mdx b/src/pages/guide/node/installation.mdx index 6bc64d92..1b559f1f 100644 --- a/src/pages/guide/node/installation.mdx +++ b/src/pages/guide/node/installation.mdx @@ -14,8 +14,8 @@ The versions across networks may not be compatible, as such, please consult the |----------|---------| | Moderato (Testnet) | v1.1.0 | -:::warning -The `andantino` chainspec has been removed as of v1.1.0. Testnet nodes must use `--chain moderato`. +:::info +The `andantino` chainspec is deprecated. New nodes should use `--chain moderato`. ::: ## Pre-built Binary diff --git a/src/pages/guide/node/validator.mdx b/src/pages/guide/node/validator.mdx index c5f72411..d543a256 100644 --- a/src/pages/guide/node/validator.mdx +++ b/src/pages/guide/node/validator.mdx @@ -59,8 +59,8 @@ tempo node --datadir \ | `--telemetry-url ` | Unified metrics and logs export. Pushes both reth and consensus metrics with a `consensus_id` label for node identification. **We ask all validators to configure this so we can support troubleshooting.** | | `--consensus.datadir ` | Store consensus data on a separate volume (e.g., AWS EBS) while keeping execution state on high-performance local disks. Migrate by copying `/consensus` to the new location. | -:::warning[Testnet Chain Name Change] -As of v1.1.0, testnet nodes must use `--chain moderato`. The previous `andantino` chainspec has been removed. +:::info[Testnet Chain] +The `andantino` chainspec is deprecated. New validators should use `--chain moderato`. ::: The notable difference between RPC nodes and validator nodes is the omission of the `--follow` argument and the addition of the `--consensus.signing-key` and `--consensus.fee-recipient` arguments. The fee recipient is the address that will receive transaction fees in your validators' proposed blocks. From 9c024bc684e6897d8d72e0155b38dc50a84358fd Mon Sep 17 00:00:00 2001 From: jenpaff Date: Thu, 5 Feb 2026 16:56:23 +0000 Subject: [PATCH 17/20] fix: update andantino to show as deprecated testnet with version Amp-Thread-ID: https://ampcode.com/threads/T-019c2e2d-fdda-704c-8ebe-8ed7cda6f2d0 Co-authored-by: Amp --- src/pages/guide/node/installation.mdx | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/pages/guide/node/installation.mdx b/src/pages/guide/node/installation.mdx index 1b559f1f..ef545119 100644 --- a/src/pages/guide/node/installation.mdx +++ b/src/pages/guide/node/installation.mdx @@ -13,10 +13,7 @@ The versions across networks may not be compatible, as such, please consult the | Network | Version | |----------|---------| | Moderato (Testnet) | v1.1.0 | - -:::info -The `andantino` chainspec is deprecated. New nodes should use `--chain moderato`. -::: +| Andantino (Deprecated Testnet) | v0.8.2 | ## Pre-built Binary From 1f613a52a5380175cc003bdd1217c55dc88fdae4 Mon Sep 17 00:00:00 2001 From: Georgios Konstantopoulos Date: Thu, 5 Feb 2026 09:33:01 -0800 Subject: [PATCH 18/20] docs: foundryup tempo now installs all binaries (#74) * docs: foundryup tempo now installs all binaries Amp-Thread-ID: https://ampcode.com/threads/T-019c2eb5-2219-711d-9c64-e9cf0910e66c Co-authored-by: Amp * fix: patch dead links in TIPs synced from tempo repo Amp-Thread-ID: https://ampcode.com/threads/T-019c2eb5-2219-711d-9c64-e9cf0910e66c Co-authored-by: Amp * Add --sig run(string) SALT to forge script commands Amp-Thread-ID: https://ampcode.com/threads/T-019c2ec9-3bba-7717-9aba-e0ba0880f5da Co-authored-by: Amp --------- Co-authored-by: Amp --- src/pages/sdk/foundry/index.mdx | 9 ++++++++- vite.config.ts | 7 ++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/pages/sdk/foundry/index.mdx b/src/pages/sdk/foundry/index.mdx index 963cc751..885e99df 100644 --- a/src/pages/sdk/foundry/index.mdx +++ b/src/pages/sdk/foundry/index.mdx @@ -36,7 +36,7 @@ Next, run: foundryup -n tempo ``` -It will automatically install the latest `nightly` release of the precompiled binaries: [`forge`](https://getfoundry.sh/forge/overview#forge) and [`cast`](https://getfoundry.sh/cast/overview#cast). +It will automatically install the latest `nightly` release of all precompiled binaries: [`forge`](https://getfoundry.sh/forge/overview#forge), [`cast`](https://getfoundry.sh/cast/overview#cast), [`anvil`](https://getfoundry.sh/anvil/overview#anvil), and [`chisel`](https://getfoundry.sh/chisel/overview#chisel). To install a specific version, replace `` with the desired release tag: @@ -114,8 +114,14 @@ forge create src/Mail.sol:Mail \ --verify \ --constructor-args 0x20c0000000000000000000000000000000000001 +# Set a salt for deterministic contract address derivation +# The salt is passed to TIP20_FACTORY.createToken() which uses it with the sender +# address to compute a deterministic deployment address via getTokenAddress(sender, salt) +export SALT="my-unique-salt" + # Run a deployment script and verify forge script script/Mail.s.sol \ + --sig "run(string)" $SALT \ --rpc-url $TEMPO_RPC_URL \ --interactive \ --sender \ @@ -124,6 +130,7 @@ forge script script/Mail.s.sol \ # Run a deployment script with custom fee token and verify forge script script/Mail.s.sol \ + --sig "run(string)" $SALT \ --tempo.fee-token \ --rpc-url $TEMPO_RPC_URL \ --interactive \ diff --git a/vite.config.ts b/vite.config.ts index 96bbb99e..7af2318f 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -51,7 +51,12 @@ function syncTips(): Plugin { await Promise.all( tipFiles.map(async (file) => { - const content = await fetch(file.download_url).then((r) => r.text()) + let content = await fetch(file.download_url).then((r) => r.text()) + // Fix dead links in TIPs that reference local paths instead of GitHub URLs + content = content.replace( + /\(tips\/ref-impls\/src\/interfaces\/(\w+\.sol)\)/g, + '(https://github.com/tempoxyz/tempo-std/blob/master/src/interfaces/$1)', + ) const outputPath = path.join(outputDir, file.name.replace('.md', '.mdx')) await fs.writeFile(outputPath, content) }), From 9c7d7d6d497c43912c0b331181a3d00959215624 Mon Sep 17 00:00:00 2001 From: jenpaff Date: Thu, 5 Feb 2026 18:01:17 +0000 Subject: [PATCH 19/20] fix: update expiring nonces to use nonceKey: 'expiring' for TypeScript Amp-Thread-ID: https://ampcode.com/threads/T-019c2e2d-fdda-704c-8ebe-8ed7cda6f2d0 Co-authored-by: Amp --- .../guide/payments/send-parallel-transactions.mdx | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/pages/guide/payments/send-parallel-transactions.mdx b/src/pages/guide/payments/send-parallel-transactions.mdx index aa45eb6a..c854db97 100644 --- a/src/pages/guide/payments/send-parallel-transactions.mdx +++ b/src/pages/guide/payments/send-parallel-transactions.mdx @@ -16,19 +16,16 @@ Submit multiple transactions in parallel using Tempo's flexible nonce system. Ch ## Expiring Nonces (Recommended) -[TIP-1009](/protocol/tips/tip-1009) introduces expiring nonces: transactions specify a `validBefore` timestamp (max 30s in the future) instead of tracking sequential nonces. This is the simplest approach for parallel submission. - -To use expiring nonces, set `nonceKey` to `UINT256_MAX` (`0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff`). This signals to the protocol that the transaction uses time-based replay protection instead of sequential nonces. +[TIP-1009](/protocol/tips/tip-1009) introduces expiring nonces: transactions automatically expire if not executed within a specified time window. This is the simplest approach for parallel submission—no nonce tracking required. :::code-group ```typescript [TypeScript] -const tx = await Actions.token.transfer(config, { - amount: parseUnits('100', 6), +// Set nonceKey to 'expiring' - the SDK handles everything +const tx = await client.sendTransaction({ to: recipient, - token: alphaUsd, - nonceKey: BigInt('0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'), - validBefore: Math.floor(Date.now() / 1000) + 30, + data: '0x...', + nonceKey: 'expiring', // [!code hl] }) ``` From c4ee73be182a6779416c0956351e8b9a4e2cdddc Mon Sep 17 00:00:00 2001 From: jxom <7336481+jxom@users.noreply.github.com> Date: Fri, 6 Feb 2026 06:03:02 +1100 Subject: [PATCH 20/20] docs: add expiring nonces and 2D nonces cards, improve parallel transactions guide Amp-Thread-ID: https://ampcode.com/threads/T-019c2f1f-0179-7247-8a12-ccb310a303ce Co-authored-by: Amp --- .../payments/send-parallel-transactions.mdx | 232 +++--------------- src/pages/guide/tempo-transaction/index.mdx | 12 + src/snippets/tempo-tx-properties.mdx | 201 +++++++++++++-- 3 files changed, 221 insertions(+), 224 deletions(-) diff --git a/src/pages/guide/payments/send-parallel-transactions.mdx b/src/pages/guide/payments/send-parallel-transactions.mdx index c854db97..1db8280d 100644 --- a/src/pages/guide/payments/send-parallel-transactions.mdx +++ b/src/pages/guide/payments/send-parallel-transactions.mdx @@ -1,5 +1,5 @@ --- -description: Submit multiple transactions concurrently using Tempo's nonce system. Choose between 2D nonces for ordered sequences or expiring nonces for fire-and-forget. +description: Submit multiple transactions concurrently using Tempo's expiring nonce system under-the-hood. --- import * as Demo from '../../../components/guides/Demo.tsx' @@ -9,66 +9,11 @@ import { Cards, Card } from 'vocs' # Send Parallel Transactions -Submit multiple transactions in parallel using Tempo's flexible nonce system. Choose between: - -- **[2D nonces](/protocol/transactions/spec-tempo-transaction)**: Independent nonce sequences for ordered transaction groups -- **[Expiring nonces](/protocol/tips/tip-1009)**: Time-bounded replay protection for fire-and-forget transactions *(recommended for most use cases)* - -## Expiring Nonces (Recommended) - -[TIP-1009](/protocol/tips/tip-1009) introduces expiring nonces: transactions automatically expire if not executed within a specified time window. This is the simplest approach for parallel submission—no nonce tracking required. - -:::code-group - -```typescript [TypeScript] -// Set nonceKey to 'expiring' - the SDK handles everything -const tx = await client.sendTransaction({ - to: recipient, - data: '0x...', - nonceKey: 'expiring', // [!code hl] -}) -``` - -```rust [Rust] -let pending = provider - .send_transaction(TempoTransactionRequest { - nonce_key: Some(U256::MAX), - valid_before: Some(SystemTime::now().duration_since(UNIX_EPOCH).as_secs() + 30), - ..Default::default(), - }) - .await?; -``` - -::: - -Benefits: -- No nonce tracking required -- Automatic replay protection via circular buffer -- No permanent state bloat from unused nonce keys - -## 2D Nonces - -For cases requiring ordered sequences within a key, Tempo's **2D nonce system** enables parallel transaction execution: - -- **Protocol nonce (key 0)**: The default sequential nonce. Transactions must be processed in order. -- **User nonces (keys 1+)**: Independent nonce sequences that allow concurrent transaction submission. - -When you send a transaction without specifying a `nonceKey`, it uses the protocol nonce and behaves like a standard sequential transaction. By specifying different nonce keys, you can submit multiple transactions simultaneously without waiting for confirmations. - -## Key management strategies - -There are two ways to specify a `nonceKey` for a transaction: - -### Explicit keys - -Explicit keys (1n, 2n, etc.) are best when you want to reuse keys. For high-throughput applications, these keys can be used to load-balance transaction submission to the network in a gas-efficient way. You can track the most recent call on each key in your application, and, once that transaction confirms, the same key can be used for new transactions. This approach is more gas efficient, as provisioning a new `nonceKey` [costs gas](/protocol/transactions/spec-tempo-transaction#gas-schedule). - -### `'random'` keys -For simple cases where you don't need to track keys. This approach is recommended when handling bursts of high activity, in which you need to submit transfers to the network and don't care about the added gas costs for provisioning multiple keys. +Tempo enables concurrent transaction execution through its [expiring nonce](/guide/tempo-transaction#expiring-nonces) system. Unlike traditional sequential nonces that require transactions to be processed one at a time, expiring nonces allow multiple transactions to be submitted simultaneously without nonce conflicts. Each transaction uses an independent nonce that automatically expires after a set time window, enabling true parallel execution. ## Demo -By the end of this guide you will understand how to send parallel payments using nonce keys. +By the end of this guide you will understand how to send parallel payments using expiring nonces under-the-hood. @@ -87,82 +32,37 @@ Ensure that you have set up your project with Wagmi and integrated accounts by f - [Embed Passkey accounts](/guide/use-accounts/embed-passkeys) - [Connect to wallets](/guide/use-accounts/connect-to-wallets) -### Fetch current nonces - -In order to send a transfer on a custom `nonceKey`, you need to know the current nonce value for the keys you will send on. - -:::code-group - -```ts twoslash [example.ts] -import { Actions } from 'wagmi/tempo' -import { parseUnits } from 'viem' -import { config } from './wagmi.config' - -// @noErrors - -// Fetch nonces for each key in parallel -const [nonce1, nonce2] = await Promise.all([ - Actions.nonce.getNonce(config, { account, nonceKey: 1n }), // [!code hl] - Actions.nonce.getNonce(config, { account, nonceKey: 2n }), // [!code hl] -]) - -console.log('Current nonce for nonceKey 1:', nonce1) -console.log('Current nonce for nonceKey 2:', nonce2) -``` - -```tsx twoslash [wagmi.config.ts] filename="wagmi.config.ts" -// @noErrors -// [!include ~/snippets/wagmi.config.ts:setup] -``` - -::: - -:::warning - -This nonce-fetching behavior is temporary: a forthcoming update will let the network automatically determine the nonce for a user `nonceKey`. - -::: - ### Send concurrent transactions with nonce keys -To send multiple transactions in parallel, specify different `nonceKey` values. Each nonce key maintains its own independent sequence: +To send multiple transactions in parallel, simply batch them together. [Expiring nonces](/guide/tempo-transaction#expiring-nonces) are attached to each transaction automatically. :::code-group ```ts twoslash [example.ts] -import { Actions } from 'wagmi/tempo' +// @noErrors +import { Hooks } from 'wagmi/tempo' import { parseUnits } from 'viem' -import { config } from './wagmi.config' -// @noErrors -const account = '0x...' // your sender account const alphaUsd = '0x20c0000000000000000000000000000000000001' -const [nonce1, nonce2] = await Promise.all([ - Actions.nonce.getNonce(config, { account, nonceKey: 1n }), - Actions.nonce.getNonce(config, { account, nonceKey: 2n }), -]) - -// Send both transfers in parallel using different nonce keys -const [hash1, hash2] = await Promise.all([ - Actions.token.transfer(config, { - amount: parseUnits('100', 6), - to: '0x70997970C51812dc3A010C7d01b50e0d17dc79C8', - token: alphaUsd, - nonceKey: 1n, // [!code hl] - nonce: Number(nonce1), // [!code hl] - }), - Actions.token.transfer(config, { - amount: parseUnits('50', 6), - to: '0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC', - token: alphaUsd, - nonceKey: 2n, // [!code hl] - nonce: Number(nonce2), // [!code hl] - }), -]) - -console.log('Transaction 1:', hash1) -console.log('Transaction 2:', hash2) +const { mutate: transfer } = Hooks.token.useTransferSync() + +// Send both transfers in parallel. // [!code focus] +const [receipt1, receipt2] = await Promise.all([ // [!code focus] + transfer.mutate({ // [!code focus] + amount: parseUnits('100', 6), // [!code focus] + to: '0x70997970C51812dc3A010C7d01b50e0d17dc79C8', // [!code focus] + token: alphaUsd, // [!code focus] + }), // [!code focus] + transfer.mutate({ // [!code focus] + amount: parseUnits('50', 6), // [!code focus] + to: '0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC', // [!code focus] + token: alphaUsd, // [!code focus] + }), // [!code focus] +]) // [!code focus] + +console.log('Transaction 1:', receipt1.transactionHash) // [!code focus] +console.log('Transaction 2:', receipt2.transactionHash) // [!code focus] ``` ```tsx twoslash [wagmi.config.ts] filename="wagmi.config.ts" @@ -174,91 +74,17 @@ console.log('Transaction 2:', hash2) :::: -## Recipes - -### Use random nonce keys - -For simple cases where you don't need to manage specific keys, use `'random'` to automatically generate a unique nonce key: - -:::code-group - -```ts twoslash [example.ts] -import { Actions } from 'wagmi/tempo' -import { parseUnits } from 'viem' -import { config } from './wagmi.config' - -// @noErrors -// Using 'random' automatically generates a unique nonce key -const hash = await Actions.token.transfer(config, { - amount: parseUnits('100', 6), - to: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEbb', - token: '0x20c0000000000000000000000000000000000001', - nonceKey: 'random', // [!code hl] -}) - -console.log('Transaction hash:', hash) -``` - -```tsx twoslash [wagmi.config.ts] filename="wagmi.config.ts" -// @noErrors -// [!include ~/snippets/wagmi.config.ts:setup] -``` - -::: - -### Query active nonce keys - -Track how many nonce keys your account is using: - -:::code-group - -```ts [example.ts] -import { client } from './viem.config' - -// Get the count of active nonce keys for an account -const count = await client.nonce.getNonceKeyCount({ - account: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEbb', -}) - -console.log('Active nonce keys:', count) -``` - -```ts [viem.config.ts] filename="viem.config.ts" -// [!include ~/snippets/viem.config.ts:setup] -``` - -::: - -## Best Practices - -### When to use nonce keys - -Use nonce keys when you need to: -- Send multiple independent transactions simultaneously -- Build high-throughput applications that can't wait for sequential confirmations -- Process payments to multiple recipients concurrently - -### When to use batch transactions instead - -Use [batch transactions](/guide/use-accounts/batch-transactions) instead of nonce keys when: -- Operations need to be atomic -- Calls have sequential dependencies -- You want a single transaction fee for multiple operations - -Batch transactions are not as appropriate for the payments to multiple recipients use case, because if a single payment fails, all the calls in the batch transaction roll back. - - ## Learning Resources + + @@ -459,7 +461,7 @@ enabling parallel execution and significantly improved transaction throughput fo // @noErrors import { client } from './viem.config' - const [receipt1, receipt2, receipt3] = await Promise.all([ // [!code hl] + const [receipt1, receipt2, receipt3] = await Promise.all([ client.sendTransactionSync({ data: '0xdeadbeef0000000000000000000000000000000001', to: '0xcafebabecafebabecafebabecafebabecafebabe', @@ -481,26 +483,95 @@ enabling parallel execution and significantly improved transaction throughput fo ::: + + + :::code-group ```tsx twoslash [example.ts] // @noErrors - import { client } from './viem.config' + import { useSendTransaction } from 'wagmi' - const hash1 = await client.sendTransaction({ + const { sendTransaction } = useSendTransaction() + + sendTransaction({ data: '0xdeadbeef0000000000000000000000000000000001', - nonceKey: 1n, // [!code hl] to: '0xcafebabecafebabecafebabecafebabecafebabe', }) - const hash2 = await client.sendTransaction({ + sendTransaction({ + data: '0xdeadbeef0000000000000000000000000000000001', + to: '0xcafebabecafebabecafebabecafebabecafebabe', + }) + sendTransaction({ data: '0xdeadbeef0000000000000000000000000000000001', - nonceKey: 2n, // [!code hl] to: '0xcafebabecafebabecafebabecafebabecafebabe', }) ``` - ```tsx twoslash [viem.config.ts] + ```tsx twoslash [wagmi.config.ts] + // @noErrors + // [!include ~/snippets/wagmi.config.ts:setup] + ``` + + ::: + + + + + + ```tsx + rlp([ + chain_id, + max_priority_fee_per_gas, + max_fee_per_gas, + gas, + calls, + access_list, + nonce_key, // [!code focus] + nonce, + valid_before, // [!code focus] + valid_after, + fee_token, + fee_payer_signature, + authorization_list, + key_authorization, + signature, + ]) + ``` + + + +### Expiring Nonces + +[TIP-1009](/protocol/tips/tip-1009) introduces expiring nonces: transactions automatically expire if not executed within a specified time window. + +**Benefits:** +- No nonce tracking required +- Automatic replay protection via circular buffer +- No permanent state bloat from unused nonce keys + +Expiring nonces can be used by setting `nonceKey` to `maxUint256` and `validBefore` to a time in the future (within 30 seconds). + + + + + :::code-group + + ```tsx twoslash [example.ts] + // @noErrors + import { maxUint256 } from 'viem' + import { client } from './viem.config' + + const receipt = await client.sendTransactionSync({ + data: '0xdeadbeef0000000000000000000000000000000001', + nonceKey: maxUint256, // [!code focus] + to: '0xcafebabecafebabecafebabecafebabecafebabe', + validBefore: Math.floor(Date.now() / 1000) + 20, // [!code focus] + }) + ``` + + ```tsx twoslash [viem.config.ts] filename="viem.config.ts" // [!include ~/snippets/viem.config.ts:setup] ``` @@ -514,21 +585,16 @@ enabling parallel execution and significantly improved transaction throughput fo ```tsx twoslash [example.ts] // @noErrors + import { maxUint256 } from 'viem' import { useSendTransaction } from 'wagmi' const { sendTransaction } = useSendTransaction() sendTransaction({ data: '0xdeadbeef0000000000000000000000000000000001', + nonceKey: maxUint256, // [!code focus] to: '0xcafebabecafebabecafebabecafebabecafebabe', - }) - sendTransaction({ - data: '0xdeadbeef0000000000000000000000000000000001', - to: '0xcafebabecafebabecafebabecafebabecafebabe', - }) - sendTransaction({ - data: '0xdeadbeef0000000000000000000000000000000001', - to: '0xcafebabecafebabecafebabecafebabecafebabe', + validBefore: Math.floor(Date.now() / 1000) + 20, // [!code focus] }) ``` @@ -539,7 +605,91 @@ enabling parallel execution and significantly improved transaction throughput fo ::: + + + + + ```rust + let pending = provider + .send_transaction(TempoTransactionRequest { + nonce_key: Some(U256::MAX), // [!code focus] + valid_before: Some(SystemTime::now().duration_since(UNIX_EPOCH).as_secs() + 30), // [!code focus] + ..Default::default(), + }) + .await?; + ``` + + + + + + ```tsx + rlp([ + chain_id, + max_priority_fee_per_gas, + max_fee_per_gas, + gas, + calls, + access_list, + nonce_key, // set to `maxUint256` // [!code focus] + nonce, + valid_before, // set to `now + <30 seconds` // [!code focus] + valid_after, + fee_token, + fee_payer_signature, + authorization_list, + key_authorization, + signature, + ]) + ``` + + + +### 2D Nonces + +For cases requiring ordered sequences within a key, Tempo's **2D nonce system** enables parallel transaction execution: + +- **Protocol nonce (key 0)**: The default sequential nonce. Transactions must be processed in order. +- **User nonces (keys 1+)**: Independent nonce sequences that allow concurrent transaction submission. + + + + :::code-group + + ```tsx twoslash [example.ts] + // @noErrors + import { client } from './viem.config' + + const [receipt1, receipt2, receipt3] = await Promise.all([ + client.sendTransactionSync({ + data: '0xdeadbeef0000000000000000000000000000000001', + nonceKey: 1n, // [!code focus] + to: '0xcafebabecafebabecafebabecafebabecafebabe', + }), + client.sendTransactionSync({ + data: '0xcafebabe0000000000000000000000000000000001', + nonceKey: 2n, // [!code focus] + to: '0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef', + }), + client.sendTransactionSync({ + data: '0xdeadbeef0000000000000000000000000000000001', + nonceKey: 3n, // [!code focus] + to: '0xcafebabecafebabecafebabecafebabecafebabe', + }), + ]) + ``` + + ```tsx twoslash [viem.config.ts] + // [!include ~/snippets/viem.config.ts:setup] + ``` + + ::: + + + + + :::code-group ```tsx twoslash [example.ts] @@ -550,12 +700,17 @@ enabling parallel execution and significantly improved transaction throughput fo sendTransaction({ data: '0xdeadbeef0000000000000000000000000000000001', - nonceKey: 1n, // [!code hl] + nonceKey: 1n, // [!code focus] + to: '0xcafebabecafebabecafebabecafebabecafebabe', + }) + sendTransaction({ + data: '0xdeadbeef0000000000000000000000000000000001', + nonceKey: 2n, // [!code focus] to: '0xcafebabecafebabecafebabecafebabecafebabe', }) sendTransaction({ data: '0xdeadbeef0000000000000000000000000000000001', - nonceKey: 2n, // [!code hl] + nonceKey: 3n, // [!code focus] to: '0xcafebabecafebabecafebabecafebabecafebabe', }) ``` @@ -593,6 +748,10 @@ enabling parallel execution and significantly improved transaction throughput fo +:::warning +**Reuse nonce keys instead of generating random ones.** Creating a new nonce key incurs a state creation cost that increases with the number of active keys (see [TIP-1000](/protocol/tips/tip-1000)). For most applications, using a small set of sequential nonce keys (e.g., `1n`, `2n`, `3n`) is sufficient and much more cost-effective than generating random nonce keys for each transaction. +::: + ### Scheduled Transactions Scheduled transactions allow you to sign a transaction in advance and specify a time window for when it can be