Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions pnpm-workspace.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ onlyBuiltDependencies:

overrides:
vocs: https://pkg.pr.new/vocs@1c023ba
# Configurable account hash domains matching the t14-checkpoint devnet (wevm/ox#519).
'viem@2.57.5>ox': https://pkg.pr.new/ox@bf010ee

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Production docs builds now install an ox preview tarball that the lockfile cannot integrity-check, and it ships in every page bundle that uses viem 2.57.5. The new lock entry at pnpm-lock.yaml:5092 records only resolution: {tarball: https://pkg.pr.new/ox@ bf010ee}, with no integrity. The vocs preview entry at pnpm-lock.yaml:6180 does carry one. Fix: regenerate the lock entry so it records an integrity hash for the ox tarball, or depend on an npm-published ox snapshot with an integrity hash.

Why this was flagged

The override 'viem@ 2.57.5>ox': https://pkg.pr.new/ox@ bf010ee (pnpm-workspace.yaml:35) applies to every viem@ 2.57.5 instance in the tree. That covers the site's own viem plus wagmi, accounts@ 0.19.1 and mppx (pnpm-lock.yaml:12674), not only the devnet demos. The new lock entry at pnpm-lock.yaml:5091-5093 has no integrity hash. Its version: 0.14.57-755f436.0 also names a different short sha than the bf010ee in the URL. So pnpm install --frozen-lockfile downloads whatever bytes pkg.pr.new serves for that URL and has nothing to compare them against. Other bytes reach the production browser bundle unnoticed, including wallet and signing code on mainnet and testnet pages. On base, ox@ 0.14.56 came from npm with integrity: sha512-…. The neighbouring vocs pkg.pr.new override shows the lockfile can record an integrity hash for these tarballs, so this missing hash is not inherent to pkg.pr.new.

Verification: The trigger is pkg.pr.new serving different bytes at https://pkg.pr.new/ox@ bf010ee than the ones the author tested. The lock entry at pnpm-lock.yaml:5091-5093 has no integrity field, while the vocs entry at pnpm-lock.yaml:6180 and the replaced ox@ 0.14.56 both had one. So pnpm install --frozen-lockfile installs and bundles whatever the URL serves.

# accounts 0.18.5 was published with unresolved catalog dependencies.
'tapimo>accounts': 0.18.4
'baseline-browser-mapping@<2.11.0': 2.11.0
Expand Down
2 changes: 1 addition & 1 deletion src/components/guides/UpgradeAccountDemo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ async function loadDemo() {
]),
// The configuration salt Tempo assigns an upgraded account.
upgradeSalt: (address: Address) =>
viem.keccak256(viem.concat([viem.toHex('tempo:multisig:upgrade'), address])),
viem.keccak256(viem.concat([viem.toHex('tempo:configurable-account:upgrade'), address])),
}
}

Expand Down
4 changes: 3 additions & 1 deletion src/components/guides/account-sandbox-devnet.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -488,7 +488,9 @@ describe('upgrading a plain key account', () => {

it('uses Tempo’s upgrade salt for the address', async () => {
const { concat, keccak256, toHex } = await import('viem')
expect(upgradeSalt(address)).toBe(keccak256(concat([toHex('tempo:multisig:upgrade'), address])))
expect(upgradeSalt(address)).toBe(
keccak256(concat([toHex('tempo:configurable-account:upgrade'), address])),
)
})

it('records owners sorted by address, at version 1', () => {
Expand Down
23 changes: 18 additions & 5 deletions src/components/guides/account-sandbox-devnet.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/**
* Devnet adapter for the account sandbox. It sends the sandbox's actions as real transactions on
* the internal multisig-1113 devnet, which runs configurable accounts (TIP-1107 to TIP-1114) and
* the internal t14-checkpoint devnet, which runs configurable accounts (TIP-1107 to TIP-1114) and
* configurable access keys (TIP-1111).
*
* - Only real signing runs on devnet. Passkeys are real WebAuthn passkeys, so creating and signing
Expand Down Expand Up @@ -29,6 +29,7 @@ import {
isAddressEqual,
keccak256,
parseAbi,
parseEventLogs,
toHex,
} from 'viem'
import { generatePrivateKey } from 'viem/accounts'
Expand Down Expand Up @@ -256,10 +257,15 @@ const nativeMultisig: Address = '0xAACC000000000000000000000000000000000000'
const upgradeAbi = parseAbi([
'function upgradeAccount(uint8 threshold, (address owner, uint8 weight)[] owners) returns (bytes32)',
])
// viem's `Abis.nativeMultisig` still names this event `MultisigConfigUpdated`, so
// `accounts.updateConfigSync` can't find it. Remove once viem ships the renamed ABI.
const configUpdatedAbi = parseAbi([
'event ConfigurableAccountConfigUpdated(address indexed account, bytes32 salt, uint64 version, uint8 threshold, (address owner, uint8 weight)[] owners)',
])

/** The configuration salt Tempo assigns an account upgraded in place. */
export function upgradeSalt(address: Address) {
return keccak256(concat([toHex('tempo:multisig:upgrade'), address]))
return keccak256(concat([toHex('tempo:configurable-account:upgrade'), address]))
Comment on lines 266 to +268

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Readers who follow the Accounts upgrade and watch-changes pages get a wrong upgraded config and an empty update list on the new devnet. The demos moved to tempo:configurable-account:upgrade and ConfigurableAccountConfigUpdated. The docs code samples still use the old names and point at the same t14-checkpoint client. Fix: update every docs sample and reference table that names the old salt domain or event to the new names, which covers the 2 code sites listed. Same pattern at 2 sites (accounts/account-configuration/account-upgrade.mdx:81, accounts/account-configuration.mdx:68). [also at: src/snippets/accounts-devnet.ts:14 - Readers copying the upgrade and watch-signers examples get a wrong salt and no events on the new devnet. The docs pages were not updated for the renames.]

Why this was flagged

src/pages/docs/accounts/account-configuration/account-upgrade.mdx:81 builds Account.fromConfig with salt keccak256(concat([toHex('tempo:multisig:upgrade'), original.address])). This PR changes upgradeSalt (account-sandbox-devnet.ts:268, UpgradeAccountDemo.tsx:44) to tempo:configurable-account:upgrade because the t14-checkpoint node uses that domain. A reader running the page's sample gets a local config whose salt does not match the onchain commitment, so later signatures or config updates from that account fail. src/pages/docs/accounts/account-configuration.mdx:68 queries eventName: 'MultisigConfigUpdated', but the PR says the node now emits ConfigurableAccountConfigUpdated (account-sandbox-devnet.ts:262-264), so the watch-signers sample returns no updates. On base, both samples matched the multisig-1113 devnet the client snippet targeted. Prose at development/single-key-accounts.mdx:86, configurable-accounts.mdx:119,193,195 and accounts/security.mdx:74 also names the old salt domain and event.

Verification: Trigger: a reader copies the account-upgrade or watch-changes sample after this merges. accounts/account-configuration/account-upgrade.mdx:81 still has tempo:multisig:upgrade, and account-configuration.mdx:66-68 still uses eventName: 'MultisigConfigUpdated', so updates comes back empty. On the base branch these samples matched multisig-1113, so this PR is what breaks them.

}

/**
Expand Down Expand Up @@ -997,11 +1003,18 @@ export function createDevnetAdapter(
const next = { owners, threshold: account.committed.threshold }
if (sameConfig(next, session.config)) return undefined
const approvers = updateApprovers(session, account)
const { config, receipt } = await client.accounts.updateConfigSync({
const receipt = await client.writeContractSync({
account: signingAccount(session, localAccounts(approvers)),
nextConfig: next,
...Tempo.Actions.accounts.updateConfig.call({
currentConfig: session.config,
nextConfig: next,
}),
throwOnReceiptRevert: true,
})
session.config = config
const [log] = parseEventLogs({ abi: configUpdatedAbi, logs: receipt.logs, strict: true })
if (!log)
throw new DevnetRejection('invalid-config', 'Devnet recorded no configuration update.')
session.config = Tempo.AccountConfig.from(log.args)
session.lastUpdate = receipt.transactionHash
return receipt.transactionHash
}
Expand Down
4 changes: 2 additions & 2 deletions src/components/guides/devnet-network.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ import type { Address } from 'viem'
import { developersApiPath } from '../../marketing/app/_lib/developersPaths'

/**
* Where the Accounts demos reach the multisig-1113 devnet. Kept apart from
* Where the Accounts demos reach the t14-checkpoint devnet. Kept apart from
* `account-sandbox-devnet.ts` so small demos can import these values without bundling the adapter.
*/

/** The demo devnet's Tailscale RPC, for Node scripts on the tailnet. */
export const devnetTailnetRpcUrl = 'http://multisig-1113-nodes-rpc-service.tail388b2e.ts.net:8545'
export const devnetTailnetRpcUrl = 'http://t14-checkpoint-nodes-rpc-service.tail388b2e.ts.net:8545'

/**
* Pages reach the devnet through the docs site's same-origin proxy (`/api/devnet-rpc`), which holds
Expand Down
22 changes: 19 additions & 3 deletions src/pages/_api/api/devnet-rpc.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
// Same-origin JSON-RPC proxy for the Accounts demos on the multisig-1113 devnet.
// Same-origin JSON-RPC proxy for the Accounts demos on the t14-checkpoint devnet.
// Its public endpoint sits behind the shared `previews` API key, which must stay server-side,
// and HTTPS pages can't call the Tailscale-only HTTP endpoint. Without a key (local dev on the
// tailnet), it forwards to the Tailscale RPC instead.
const publicUpstream = process.env.DEVNET_RPC_URL ?? 'https://rpc-multisig-1113.devnet.tempoxyz.dev'
const tailnetUpstream = 'http://multisig-1113-nodes-rpc-service.tail388b2e.ts.net:8545'
const publicUpstream =
process.env.DEVNET_RPC_URL ?? 'https://rpc-t14-checkpoint.devnet.tempoxyz.dev'
const tailnetUpstream = 'http://t14-checkpoint-nodes-rpc-service.tail388b2e.ts.net:8545'

const maxRequestBytes = 256 * 1024
const maxResponseBytes = 4 * 1024 * 1024
Expand All @@ -24,6 +25,7 @@ export async function POST(request: Request): Promise<Response> {
const calls = Array.isArray(parsed) ? parsed : [parsed]
if (calls.length === 0 || calls.length > maxBatch || !calls.every(isAllowedCall))
return failure(400, 'Unsupported demo RPC request')
if (calls.map(renameSimulation).includes(true)) body = JSON.stringify(parsed)
} catch {
return failure(400, 'Invalid JSON-RPC request')
}
Expand Down Expand Up @@ -73,6 +75,20 @@ function isAllowedCall(call: unknown) {
return allowedMethods.has(method) || allowedPrefixes.some((prefix) => method.startsWith(prefix))
}

// ox still sends the simulation hint as `multisigSimulation`, and the t14-checkpoint node reads
// `configurableAccountSimulation`. Without it, the node underestimates a new account's first
// transaction and it runs out of gas. Remove once ox sends the new name.
function renameSimulation(call: unknown) {
const [request] = (call as { params?: unknown[] }).params ?? []
if (!request || typeof request !== 'object' || !('multisigSimulation' in request)) return false
const { multisigSimulation, ...rest } = request as Record<string, unknown>
;(call as { params: unknown[] }).params[0] = {
...rest,
configurableAccountSimulation: multisigSimulation,
}
return true
}
Comment on lines +78 to +90

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Node readers of the Accounts snippets send a new account's first transaction without the renamed simulation hint, so it can run out of gas on t14-checkpoint. Only the browser proxy renames multisigSimulation (devnet-rpc.ts:81). The shared snippet client in src/snippets/accounts-devnet.ts:14 calls the devnet directly, so its requests keep the old field name. Fix: apply the same rename on every path that reaches t14-checkpoint, for example a request hook on the snippet's http transport, or state the limit on the pages that include the snippet.

Why this was flagged

The PR moves the snippet client (src/snippets/accounts-devnet.ts:14) to https://rpc-t14-checkpoint.devnet.tempoxyz.dev. About 15 docs pages include it (create.mdx:112, team-multisig.mdx:68, fee-sponsorship.mdx:67, and others). The workaround comment at devnet-rpc.ts:78-80 says ox, including the pinned preview, still sends multisigSimulation, while this node reads configurableAccountSimulation. Without that field, "the node underestimates a new account's first transaction and it runs out of gas". renameSimulation runs only inside the same-origin proxy POST handler (devnet-rpc.ts:28). Node scripts built from the snippet, and the fee-payer relay server in fee-sponsorship.mdx, never go through that proxy. So the first transaction from a newly created configurable account reverts out of gas. On base, multisig-1113 read multisigSimulation itself, so the same scripts estimated gas correctly. The pinned ox override does not help here, because the comment says the preview build also sends the old name.

Verification: The rename covers only the browser proxy: renameSimulation (src/pages/_api/api/devnet-rpc.ts:81-90) runs only inside the same-origin proxy's POST handler. The snippet client skips the proxy: src/snippets/accounts-devnet.ts:14 points straight at t14-checkpoint with no rename. This is a regression. On the base branch the snippet pointed at multisig-1113, which reads multisigSimulation.


function failure(status: number, message: string) {
return Response.json(
{ jsonrpc: '2.0', id: null, error: { code: -32000, message } },
Expand Down
2 changes: 1 addition & 1 deletion src/snippets/accounts-devnet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const rpcKey = process.env.TEMPO_DEVNET_RPC_KEY

export const client = createClient({
chain: tempoDevnet,
transport: http('https://rpc-multisig-1113.devnet.tempoxyz.dev', {
transport: http('https://rpc-t14-checkpoint.devnet.tempoxyz.dev', {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Readers who copy the Accounts docs samples now hit a devnet their code can't talk to. The samples break where they worked against multisig-1113 on base. This line points the shared client snippet at t14-checkpoint. The workarounds (pinned ox override, proxy field rename, local event ABI) only cover the site's own sandbox, not readers' released viem/ox. Fix: keep the published snippet on a devnet that released viem/ox supports until they ship the renames, or update every affected sample in the same change. That includes the tempo:multisig:upgrade salt at account-upgrade.mdx:81 and the updateConfigSync calls.

Why this was flagged

The client region of src/snippets/accounts-devnet.ts is included in about 17 docs pages (create.mdx, team-multisig.mdx, account-upgrade.mdx, configuration-updates.mdx, recover-an-account.mdx, and others). Readers run these with released viem and ox from npm. The PR description says released ox 0.14.56 still uses the tempo:multisig:* domains, so "the node rejects every derived address". It also says ox sends multisigSimulation, which this node ignores, so a new account's first transaction runs out of gas. Readers' traffic never passes through the renameSimulation proxy at src/pages/_api/api/devnet-rpc.ts:81. The docs also still call client.accounts.updateConfigSync (configuration-updates.mdx:68, team-multisig.mdx:131, recover-an-account.mdx:112), which the PR says throws because it expects MultisigConfigUpdated. account-upgrade.mdx:81 still builds the salt from toHex('tempo:multisig:upgrade'), so the account it derives no longer matches the node's commitment. On base, the same snippets targeted rpc-multisig-1113, where released viem/ox matched the node.

Verification: The trigger is a reader who copies a docs sample and runs it with released viem/ox from npm. src/snippets/accounts-devnet.ts:14 now has http('https://rpc-t14-checkpoint.devnet.tempoxyz.dev', ...). configuration-updates.mdx:68 still calls client.accounts.updateConfigSync(...), which lands onchain but then throws. On base, the snippet pointed at multisig-1113, which matched released viem/ox.

fetchOptions: { headers: { Authorization: `Basic ${btoa(`previews:${rpcKey}`)}` } },
}),
})
Expand Down
Loading