viem 2.56.0 → 2.56.2
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 +16 -0
- package/_cjs/actions/wallet/sendTransaction.js +9 -1
- package/_cjs/actions/wallet/sendTransaction.js.map +1 -1
- package/_cjs/actions/wallet/sendTransactionSync.js +9 -1
- package/_cjs/actions/wallet/sendTransactionSync.js.map +1 -1
- package/_cjs/errors/version.js +1 -1
- package/_cjs/tempo/Abis.js +11 -23
- package/_cjs/tempo/Abis.js.map +1 -1
- package/_cjs/tempo/Account.js +66 -61
- package/_cjs/tempo/Account.js.map +1 -1
- package/_cjs/tempo/Client.js +10 -2
- package/_cjs/tempo/Client.js.map +1 -1
- package/_cjs/tempo/Decorator.js +2 -1
- package/_cjs/tempo/Decorator.js.map +1 -1
- package/_cjs/tempo/Formatters.js +29 -9
- package/_cjs/tempo/Formatters.js.map +1 -1
- package/_cjs/tempo/Multisig.js +990 -0
- package/_cjs/tempo/Multisig.js.map +1 -0
- package/_cjs/tempo/Selectors.js +2 -3
- package/_cjs/tempo/Selectors.js.map +1 -1
- package/_cjs/tempo/{Storage.js → Store.js} +34 -9
- package/_cjs/tempo/Store.js.map +1 -0
- package/_cjs/tempo/Transaction.js +15 -30
- package/_cjs/tempo/Transaction.js.map +1 -1
- package/_cjs/tempo/Transport.js +51 -5
- package/_cjs/tempo/Transport.js.map +1 -1
- package/_cjs/tempo/actions/accessKey.js +102 -8
- package/_cjs/tempo/actions/accessKey.js.map +1 -1
- package/_cjs/tempo/actions/amm.js +6 -0
- package/_cjs/tempo/actions/amm.js.map +1 -1
- package/_cjs/tempo/actions/channel.js +12 -0
- package/_cjs/tempo/actions/channel.js.map +1 -1
- package/_cjs/tempo/actions/dex.js +10 -0
- package/_cjs/tempo/actions/dex.js.map +1 -1
- package/_cjs/tempo/actions/earn/deployment.js +13 -1
- package/_cjs/tempo/actions/earn/deployment.js.map +1 -1
- package/_cjs/tempo/actions/earn.js +17 -0
- package/_cjs/tempo/actions/earn.js.map +1 -1
- package/_cjs/tempo/actions/fee.js +4 -0
- package/_cjs/tempo/actions/fee.js.map +1 -1
- package/_cjs/tempo/actions/multisig.js +86 -28
- package/_cjs/tempo/actions/multisig.js.map +1 -1
- package/_cjs/tempo/actions/policy.js +8 -0
- package/_cjs/tempo/actions/policy.js.map +1 -1
- package/_cjs/tempo/actions/receivePolicy.js +6 -0
- package/_cjs/tempo/actions/receivePolicy.js.map +1 -1
- package/_cjs/tempo/actions/reward.js +4 -0
- package/_cjs/tempo/actions/reward.js.map +1 -1
- package/_cjs/tempo/actions/token.js +32 -0
- package/_cjs/tempo/actions/token.js.map +1 -1
- package/_cjs/tempo/actions/virtualAddress.js +2 -0
- package/_cjs/tempo/actions/virtualAddress.js.map +1 -1
- package/_cjs/tempo/actions/zone.js +7 -5
- package/_cjs/tempo/actions/zone.js.map +1 -1
- package/_cjs/tempo/chainConfig.js +180 -69
- package/_cjs/tempo/chainConfig.js.map +1 -1
- package/_cjs/tempo/index.js +5 -2
- package/_cjs/tempo/index.js.map +1 -1
- package/_cjs/tempo/internal/utils.js +2 -1
- package/_cjs/tempo/internal/utils.js.map +1 -1
- package/_cjs/tempo/multisig/Config.js +80 -0
- package/_cjs/tempo/multisig/Config.js.map +1 -0
- package/_cjs/tempo/multisig/Operation.js +163 -0
- package/_cjs/tempo/multisig/Operation.js.map +1 -0
- package/_cjs/utils/encoding/fromHex.js +1 -1
- package/_cjs/utils/encoding/fromHex.js.map +1 -1
- package/_cjs/utils/hash/isHash.js +1 -2
- package/_cjs/utils/hash/isHash.js.map +1 -1
- package/_esm/actions/wallet/sendTransaction.js +9 -1
- package/_esm/actions/wallet/sendTransaction.js.map +1 -1
- package/_esm/actions/wallet/sendTransactionSync.js +9 -1
- package/_esm/actions/wallet/sendTransactionSync.js.map +1 -1
- package/_esm/errors/version.js +1 -1
- package/_esm/tempo/Abis.js +11 -23
- package/_esm/tempo/Abis.js.map +1 -1
- package/_esm/tempo/Account.js +66 -61
- package/_esm/tempo/Account.js.map +1 -1
- package/_esm/tempo/Client.js +22 -3
- package/_esm/tempo/Client.js.map +1 -1
- package/_esm/tempo/Decorator.js +2 -1
- package/_esm/tempo/Decorator.js.map +1 -1
- package/_esm/tempo/Formatters.js +32 -11
- package/_esm/tempo/Formatters.js.map +1 -1
- package/_esm/tempo/Multisig.js +1020 -0
- package/_esm/tempo/Multisig.js.map +1 -0
- package/_esm/tempo/Selectors.js +2 -3
- package/_esm/tempo/Selectors.js.map +1 -1
- package/_esm/tempo/{Storage.js → Store.js} +37 -26
- package/_esm/tempo/Store.js.map +1 -0
- package/_esm/tempo/Transaction.js +16 -31
- package/_esm/tempo/Transaction.js.map +1 -1
- package/_esm/tempo/Transport.js +71 -6
- package/_esm/tempo/Transport.js.map +1 -1
- package/_esm/tempo/actions/accessKey.js +104 -20
- package/_esm/tempo/actions/accessKey.js.map +1 -1
- package/_esm/tempo/actions/amm.js +6 -0
- package/_esm/tempo/actions/amm.js.map +1 -1
- package/_esm/tempo/actions/channel.js +12 -0
- package/_esm/tempo/actions/channel.js.map +1 -1
- package/_esm/tempo/actions/dex.js +10 -0
- package/_esm/tempo/actions/dex.js.map +1 -1
- package/_esm/tempo/actions/earn/deployment.js +13 -1
- package/_esm/tempo/actions/earn/deployment.js.map +1 -1
- package/_esm/tempo/actions/earn.js +17 -0
- package/_esm/tempo/actions/earn.js.map +1 -1
- package/_esm/tempo/actions/fee.js +4 -0
- package/_esm/tempo/actions/fee.js.map +1 -1
- package/_esm/tempo/actions/multisig.js +129 -63
- package/_esm/tempo/actions/multisig.js.map +1 -1
- package/_esm/tempo/actions/policy.js +8 -0
- package/_esm/tempo/actions/policy.js.map +1 -1
- package/_esm/tempo/actions/receivePolicy.js +6 -0
- package/_esm/tempo/actions/receivePolicy.js.map +1 -1
- package/_esm/tempo/actions/reward.js +4 -0
- package/_esm/tempo/actions/reward.js.map +1 -1
- package/_esm/tempo/actions/token.js +32 -0
- package/_esm/tempo/actions/token.js.map +1 -1
- package/_esm/tempo/actions/virtualAddress.js +2 -0
- package/_esm/tempo/actions/virtualAddress.js.map +1 -1
- package/_esm/tempo/actions/zone.js +8 -6
- package/_esm/tempo/actions/zone.js.map +1 -1
- package/_esm/tempo/chainConfig.js +188 -86
- package/_esm/tempo/chainConfig.js.map +1 -1
- package/_esm/tempo/index.js +5 -3
- package/_esm/tempo/index.js.map +1 -1
- package/_esm/tempo/internal/utils.js +2 -1
- package/_esm/tempo/internal/utils.js.map +1 -1
- package/_esm/tempo/multisig/Config.js +84 -0
- package/_esm/tempo/multisig/Config.js.map +1 -0
- package/_esm/tempo/multisig/Operation.js +170 -0
- package/_esm/tempo/multisig/Operation.js.map +1 -0
- package/_esm/utils/encoding/fromHex.js +1 -1
- package/_esm/utils/encoding/fromHex.js.map +1 -1
- package/_esm/utils/hash/isHash.js +1 -2
- package/_esm/utils/hash/isHash.js.map +1 -1
- package/_types/actions/wallet/sendTransaction.d.ts.map +1 -1
- package/_types/actions/wallet/sendTransactionSync.d.ts.map +1 -1
- package/_types/chains/definitions/tempo.d.ts +72 -92
- package/_types/chains/definitions/tempo.d.ts.map +1 -1
- package/_types/chains/definitions/tempoDevnet.d.ts +72 -92
- package/_types/chains/definitions/tempoDevnet.d.ts.map +1 -1
- package/_types/chains/definitions/tempoLocalnet.d.ts +72 -92
- package/_types/chains/definitions/tempoLocalnet.d.ts.map +1 -1
- package/_types/chains/definitions/tempoModerato.d.ts +72 -92
- package/_types/chains/definitions/tempoModerato.d.ts.map +1 -1
- package/_types/errors/version.d.ts +1 -1
- package/_types/tempo/Abis.d.ts +54 -108
- package/_types/tempo/Abis.d.ts.map +1 -1
- package/_types/tempo/Account.d.ts +47 -20
- package/_types/tempo/Account.d.ts.map +1 -1
- package/_types/tempo/Client.d.ts +23 -1
- package/_types/tempo/Client.d.ts.map +1 -1
- package/_types/tempo/Decorator.d.ts +30 -5
- package/_types/tempo/Decorator.d.ts.map +1 -1
- package/_types/tempo/Formatters.d.ts.map +1 -1
- package/_types/tempo/Multisig.d.ts +32 -0
- package/_types/tempo/Multisig.d.ts.map +1 -0
- package/_types/tempo/Selectors.d.ts +2 -3
- package/_types/tempo/Selectors.d.ts.map +1 -1
- package/_types/tempo/Store.d.ts +62 -0
- package/_types/tempo/Store.d.ts.map +1 -0
- package/_types/tempo/Transaction.d.ts +12 -31
- package/_types/tempo/Transaction.d.ts.map +1 -1
- package/_types/tempo/Transport.d.ts +37 -5
- package/_types/tempo/Transport.d.ts.map +1 -1
- package/_types/tempo/Zone.d.ts +468 -598
- package/_types/tempo/Zone.d.ts.map +1 -1
- package/_types/tempo/actions/accessKey.d.ts +38 -8
- package/_types/tempo/actions/accessKey.d.ts.map +1 -1
- package/_types/tempo/actions/amm.d.ts.map +1 -1
- package/_types/tempo/actions/channel.d.ts.map +1 -1
- package/_types/tempo/actions/dex.d.ts.map +1 -1
- package/_types/tempo/actions/earn/deployment.d.ts +3 -3
- package/_types/tempo/actions/earn/deployment.d.ts.map +1 -1
- package/_types/tempo/actions/earn.d.ts.map +1 -1
- package/_types/tempo/actions/fee.d.ts.map +1 -1
- package/_types/tempo/actions/multisig.d.ts +139 -136
- package/_types/tempo/actions/multisig.d.ts.map +1 -1
- package/_types/tempo/actions/policy.d.ts.map +1 -1
- package/_types/tempo/actions/receivePolicy.d.ts.map +1 -1
- package/_types/tempo/actions/reward.d.ts.map +1 -1
- package/_types/tempo/actions/token.d.ts.map +1 -1
- package/_types/tempo/actions/virtualAddress.d.ts.map +1 -1
- package/_types/tempo/actions/zone.d.ts +4 -4
- package/_types/tempo/actions/zone.d.ts.map +1 -1
- package/_types/tempo/chainConfig.d.ts +38 -48
- package/_types/tempo/chainConfig.d.ts.map +1 -1
- package/_types/tempo/index.d.ts +8 -3
- package/_types/tempo/index.d.ts.map +1 -1
- package/_types/tempo/internal/types.d.ts +1 -1
- package/_types/tempo/internal/types.d.ts.map +1 -1
- package/_types/tempo/internal/utils.d.ts +1 -0
- package/_types/tempo/internal/utils.d.ts.map +1 -1
- package/_types/tempo/multisig/Config.d.ts +42 -0
- package/_types/tempo/multisig/Config.d.ts.map +1 -0
- package/_types/tempo/multisig/Operation.d.ts +32 -0
- package/_types/tempo/multisig/Operation.d.ts.map +1 -0
- package/_types/types/chain.d.ts +10 -0
- package/_types/types/chain.d.ts.map +1 -1
- package/_types/utils/hash/isHash.d.ts +1 -2
- package/_types/utils/hash/isHash.d.ts.map +1 -1
- package/actions/wallet/sendTransaction.ts +9 -1
- package/actions/wallet/sendTransactionSync.ts +9 -1
- package/errors/version.ts +1 -1
- package/package.json +2 -2
- package/tempo/Abis.ts +11 -23
- package/tempo/Account.ts +136 -105
- package/tempo/Client.ts +46 -3
- package/tempo/Decorator.ts +40 -8
- package/tempo/Formatters.ts +39 -21
- package/tempo/Multisig.ts +1349 -0
- package/tempo/Selectors.ts +2 -3
- package/tempo/Store.ts +170 -0
- package/tempo/Transaction.ts +39 -64
- package/tempo/Transport.ts +125 -10
- package/tempo/actions/accessKey.ts +210 -23
- package/tempo/actions/amm.ts +7 -0
- package/tempo/actions/channel.ts +12 -0
- package/tempo/actions/dex.ts +10 -0
- package/tempo/actions/earn/deployment.ts +16 -3
- package/tempo/actions/earn.ts +19 -0
- package/tempo/actions/fee.ts +4 -0
- package/tempo/actions/multisig.ts +192 -94
- package/tempo/actions/policy.ts +8 -0
- package/tempo/actions/receivePolicy.ts +6 -0
- package/tempo/actions/reward.ts +5 -0
- package/tempo/actions/token.ts +33 -0
- package/tempo/actions/virtualAddress.ts +2 -0
- package/tempo/actions/zone.ts +10 -8
- package/tempo/chainConfig.ts +259 -100
- package/tempo/index.ts +9 -1
- package/tempo/internal/types.ts +3 -2
- package/tempo/internal/utils.ts +2 -0
- package/tempo/multisig/Config.ts +131 -0
- package/tempo/multisig/Operation.ts +211 -0
- package/types/chain.ts +14 -0
- package/utils/encoding/fromHex.ts +1 -1
- package/utils/hash/isHash.ts +2 -3
- package/_cjs/tempo/Storage.js.map +0 -1
- package/_cjs/tempo/internal/multisig.js +0 -56
- package/_cjs/tempo/internal/multisig.js.map +0 -1
- package/_esm/tempo/Storage.js.map +0 -1
- package/_esm/tempo/internal/multisig.js +0 -56
- package/_esm/tempo/internal/multisig.js.map +0 -1
- package/_types/tempo/Storage.d.ts +0 -42
- package/_types/tempo/Storage.d.ts.map +0 -1
- package/_types/tempo/internal/multisig.d.ts +0 -13
- package/_types/tempo/internal/multisig.d.ts.map +0 -1
- package/tempo/Storage.ts +0 -115
- package/tempo/internal/multisig.ts +0 -72
package/tempo/actions/zone.ts
CHANGED
|
@@ -66,7 +66,7 @@ import {
|
|
|
66
66
|
pickWriteSyncParameters,
|
|
67
67
|
} from '../internal/utils.js'
|
|
68
68
|
import * as WithdrawalSenderTag from '../internal/WithdrawalSenderTag.js'
|
|
69
|
-
import * as
|
|
69
|
+
import * as Store from '../Store.js'
|
|
70
70
|
import type { TransactionReceipt } from '../Transaction.js'
|
|
71
71
|
|
|
72
72
|
const defaultWithdrawalGas = 10_000_000n
|
|
@@ -1707,6 +1707,8 @@ export async function requestWithdrawalSync<
|
|
|
1707
1707
|
gas: parameters.gas ?? defaultWithdrawalGas,
|
|
1708
1708
|
throwOnReceiptRevert,
|
|
1709
1709
|
} as never)
|
|
1710
|
+
if ((receipt as TransactionReceipt).status === 'pending')
|
|
1711
|
+
return { receipt } as never
|
|
1710
1712
|
const [event] = parseEventLogs({
|
|
1711
1713
|
abi: Abis.zoneOutbox,
|
|
1712
1714
|
logs: receipt.logs,
|
|
@@ -1950,7 +1952,7 @@ export namespace requestVerifiableWithdrawalSync {
|
|
|
1950
1952
|
* ```
|
|
1951
1953
|
*
|
|
1952
1954
|
* @param client - Zone wallet client.
|
|
1953
|
-
* @param parameters - Options including optional
|
|
1955
|
+
* @param parameters - Options including optional store override.
|
|
1954
1956
|
* @returns The authentication object and serialized token.
|
|
1955
1957
|
*/
|
|
1956
1958
|
export async function signAuthorizationToken<
|
|
@@ -1968,7 +1970,7 @@ export async function signAuthorizationToken<
|
|
|
1968
1970
|
account = client.account,
|
|
1969
1971
|
issuedAt = Math.floor(Date.now() / 1000),
|
|
1970
1972
|
expiresAt = issuedAt + 86_400,
|
|
1971
|
-
|
|
1973
|
+
store = Store.defaultStore(),
|
|
1972
1974
|
} = parameters
|
|
1973
1975
|
|
|
1974
1976
|
const chain = parameters.chain ?? client.chain
|
|
@@ -1980,7 +1982,7 @@ export async function signAuthorizationToken<
|
|
|
1980
1982
|
if (!account_ || !account_.sign)
|
|
1981
1983
|
throw new Error('`account` with `sign` is required.')
|
|
1982
1984
|
|
|
1983
|
-
const
|
|
1985
|
+
const storeKey = `auth:${account_.address.toLowerCase()}:${chain.id}`
|
|
1984
1986
|
|
|
1985
1987
|
const authentication = ZoneRpcAuthentication.from({
|
|
1986
1988
|
chainId: chain.id,
|
|
@@ -1996,8 +1998,8 @@ export async function signAuthorizationToken<
|
|
|
1996
1998
|
signature,
|
|
1997
1999
|
})
|
|
1998
2000
|
|
|
1999
|
-
await
|
|
2000
|
-
await
|
|
2001
|
+
await store.setItem(storeKey, token)
|
|
2002
|
+
await store.setItem(`auth:token:${chain.id}`, token)
|
|
2001
2003
|
|
|
2002
2004
|
return { authentication, token }
|
|
2003
2005
|
}
|
|
@@ -2016,8 +2018,8 @@ export namespace signAuthorizationToken {
|
|
|
2016
2018
|
expiresAt?: number | undefined
|
|
2017
2019
|
/** Token issue time as a unix timestamp (seconds). @default `Date.now() / 1000`. */
|
|
2018
2020
|
issuedAt?: number | undefined
|
|
2019
|
-
/**
|
|
2020
|
-
|
|
2021
|
+
/** Store used to persist the token. @default sessionStorage (web) or memory (server). */
|
|
2022
|
+
store?: Store.Store | undefined
|
|
2021
2023
|
/** Zone ID to scope the token to (`0` for unscoped). @default derived from `chain.id`. */
|
|
2022
2024
|
zoneId?: number | undefined
|
|
2023
2025
|
}
|
package/tempo/chainConfig.ts
CHANGED
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
import type { Address } from 'abitype'
|
|
2
2
|
import * as Hex from 'ox/Hex'
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
MultisigConfig,
|
|
5
|
+
MultisigOperation,
|
|
6
|
+
type MultisigSimulation,
|
|
7
|
+
SignatureEnvelope,
|
|
8
|
+
type TokenId,
|
|
9
|
+
} from 'ox/tempo'
|
|
4
10
|
import { getCode } from '../actions/public/getCode.js'
|
|
11
|
+
import { getTransaction } from '../actions/public/getTransaction.js'
|
|
5
12
|
import { verifyHash } from '../actions/public/verifyHash.js'
|
|
6
13
|
import { maxUint256 } from '../constants/number.js'
|
|
7
14
|
import type { Chain, ChainConfig as viem_ChainConfig } from '../types/chain.js'
|
|
@@ -15,25 +22,17 @@ import { keccak256 } from '../utils/hash/keccak256.js'
|
|
|
15
22
|
import type { SerializeTransactionFn } from '../utils/transaction/serializeTransaction.js'
|
|
16
23
|
import type { Account, MultisigAccount } from './Account.js'
|
|
17
24
|
import { getMetadata } from './actions/accessKey.js'
|
|
18
|
-
import
|
|
25
|
+
import { getConfig } from './actions/multisig.js'
|
|
19
26
|
import * as Formatters from './Formatters.js'
|
|
20
27
|
import type { Hardfork } from './Hardfork.js'
|
|
21
28
|
import * as Concurrent from './internal/concurrent.js'
|
|
22
|
-
import {
|
|
23
|
-
createMultisigStateResolver,
|
|
24
|
-
getMultisigOwnerStates,
|
|
25
|
-
} from './internal/multisig.js'
|
|
26
29
|
import * as Transaction from './Transaction.js'
|
|
27
30
|
|
|
28
31
|
const maxExpirySecs = 25
|
|
29
32
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
const latest = now - 60n
|
|
34
|
-
if (latest <= 0n) return 0
|
|
35
|
-
return Number(BigInt(Hex.random(8)) % latest)
|
|
36
|
-
}
|
|
33
|
+
// TODO: casting to satisfy viem – viem v3 to have more flexible serializer type.
|
|
34
|
+
const serializeTransaction = ((transaction, signature) =>
|
|
35
|
+
Transaction.serialize(transaction, signature)) as SerializeTransactionFn
|
|
37
36
|
|
|
38
37
|
export const chainConfig = {
|
|
39
38
|
blockTime: 1_000,
|
|
@@ -65,13 +64,75 @@ export const chainConfig = {
|
|
|
65
64
|
| undefined
|
|
66
65
|
feePayerSignature?: Transaction.TransactionSerializableTempo['feePayerSignature']
|
|
67
66
|
from?: Address | undefined
|
|
67
|
+
hash?: Hex.Hex | undefined
|
|
68
68
|
keyData?: Hex.Hex | undefined
|
|
69
69
|
keyType?: 'p256' | 'secp256k1' | 'webAuthn' | undefined
|
|
70
|
-
|
|
71
|
-
|
|
70
|
+
multisigSimulation?: MultisigSimulation.Spec | undefined
|
|
71
|
+
owner?: Account | MultisigAccount | Address | undefined
|
|
72
72
|
signatures?: readonly unknown[] | undefined
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
+
if (request.hash) {
|
|
76
|
+
if (
|
|
77
|
+
!request.account ||
|
|
78
|
+
typeof request.account === 'string' ||
|
|
79
|
+
request.account.source !== 'multisig'
|
|
80
|
+
)
|
|
81
|
+
throw new Error(
|
|
82
|
+
'A local multisig account is required to approve a stored multisig transaction.',
|
|
83
|
+
)
|
|
84
|
+
if (!request.owner || typeof request.owner === 'string')
|
|
85
|
+
throw new Error(
|
|
86
|
+
'A local owner account is required to approve a stored multisig transaction.',
|
|
87
|
+
)
|
|
88
|
+
if (
|
|
89
|
+
request.owner.source !== 'root' &&
|
|
90
|
+
request.owner.source !== 'multisig'
|
|
91
|
+
)
|
|
92
|
+
throw new Error(
|
|
93
|
+
'A Tempo owner account is required to approve a stored multisig transaction.',
|
|
94
|
+
)
|
|
95
|
+
const transaction = await getAction(
|
|
96
|
+
client,
|
|
97
|
+
getTransaction,
|
|
98
|
+
'getTransaction',
|
|
99
|
+
)({ hash: request.hash })
|
|
100
|
+
const operation =
|
|
101
|
+
'multisig' in transaction
|
|
102
|
+
? (transaction.multisig as
|
|
103
|
+
| MultisigOperation.TransactionOperation
|
|
104
|
+
| undefined)
|
|
105
|
+
: undefined
|
|
106
|
+
if (!operation)
|
|
107
|
+
throw new Error('Expected a multisig operation transaction.')
|
|
108
|
+
if (!isAddressEqual(operation.account, request.account.address))
|
|
109
|
+
throw new Error(
|
|
110
|
+
'Multisig operation account does not match the requested account.',
|
|
111
|
+
)
|
|
112
|
+
const storedTransaction = Transaction.deserialize(
|
|
113
|
+
operation.transaction as Transaction.TransactionSerializedTempo,
|
|
114
|
+
)
|
|
115
|
+
const hash = MultisigOperation.getHash({
|
|
116
|
+
account: operation.account,
|
|
117
|
+
config: operation.config,
|
|
118
|
+
transaction: operation.transaction,
|
|
119
|
+
type: 'transaction',
|
|
120
|
+
})
|
|
121
|
+
if (hash.toLowerCase() !== request.hash.toLowerCase())
|
|
122
|
+
throw new Error('Multisig operation hash does not match transaction.')
|
|
123
|
+
return {
|
|
124
|
+
...storedTransaction,
|
|
125
|
+
account: request.account,
|
|
126
|
+
from: operation.account,
|
|
127
|
+
multisigSimulation: getMultisigSimulation({
|
|
128
|
+
account: operation.account,
|
|
129
|
+
config: operation.config,
|
|
130
|
+
local: request.account,
|
|
131
|
+
}),
|
|
132
|
+
owner: request.owner,
|
|
133
|
+
} as unknown as typeof r
|
|
134
|
+
}
|
|
135
|
+
|
|
75
136
|
// FIXME: node estimates gas with secp256k1 dummy sig + null feePayerSignature.
|
|
76
137
|
// Actual tx has larger keychain/webAuthn sigs + real fee payer sig, costing more intrinsic gas.
|
|
77
138
|
if (phase === 'afterFillParameters') {
|
|
@@ -90,90 +151,65 @@ export const chainConfig = {
|
|
|
90
151
|
return request as unknown as typeof r
|
|
91
152
|
}
|
|
92
153
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
request.account.address)
|
|
106
|
-
: undefined)
|
|
107
|
-
if (multisigIdentity) {
|
|
108
|
-
const initialConfig =
|
|
109
|
-
typeof multisigIdentity === 'string'
|
|
110
|
-
? undefined
|
|
111
|
-
: MultisigConfig.from(multisigIdentity)
|
|
112
|
-
const multisigAddress =
|
|
113
|
-
typeof multisigIdentity === 'string'
|
|
114
|
-
? multisigIdentity
|
|
115
|
-
: MultisigConfig.getAddress(initialConfig!)
|
|
116
|
-
request.multisig = initialConfig ?? multisigIdentity
|
|
117
|
-
request.from = multisigAddress
|
|
118
|
-
// Key types are not part of the config, so conservatively model every
|
|
119
|
-
// approval as a maximum-size WebAuthn signature.
|
|
120
|
-
if (typeof request.keyType === 'undefined') {
|
|
121
|
-
request.keyType = 'webAuthn'
|
|
122
|
-
if (typeof request.keyData === 'undefined') request.keyData = '0x0578'
|
|
123
|
-
}
|
|
124
|
-
const getState = createMultisigStateResolver((account) =>
|
|
125
|
-
getAction(client, multisig.getConfig, 'getConfig')({ account }),
|
|
154
|
+
const multisigIdentity = (() => {
|
|
155
|
+
if (request.account?.source === 'multisig')
|
|
156
|
+
return {
|
|
157
|
+
account: request.account.address,
|
|
158
|
+
config: (request.account as MultisigAccount).config,
|
|
159
|
+
local: request.account as MultisigAccount,
|
|
160
|
+
}
|
|
161
|
+
return undefined
|
|
162
|
+
})()
|
|
163
|
+
if (request.owner && !multisigIdentity)
|
|
164
|
+
throw new Error(
|
|
165
|
+
'A multisig account is required when an owner is provided.',
|
|
126
166
|
)
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
167
|
+
if (request.owner && typeof request.owner === 'string')
|
|
168
|
+
throw new Error(
|
|
169
|
+
'A local owner account is required to approve a multisig transaction.',
|
|
170
|
+
)
|
|
171
|
+
if (
|
|
172
|
+
request.owner &&
|
|
173
|
+
request.owner.source !== 'root' &&
|
|
174
|
+
request.owner.source !== 'multisig'
|
|
175
|
+
)
|
|
176
|
+
throw new Error(
|
|
177
|
+
'A Tempo owner account is required to approve a multisig transaction.',
|
|
178
|
+
)
|
|
179
|
+
const coordinatedMultisig =
|
|
180
|
+
!!multisigIdentity &&
|
|
181
|
+
!!request.owner &&
|
|
182
|
+
(client.transport as { multisig?: boolean }).multisig === true
|
|
183
|
+
if (multisigIdentity) {
|
|
184
|
+
const { account, local } = multisigIdentity
|
|
185
|
+
if (!account)
|
|
138
186
|
throw new Error(
|
|
139
|
-
'
|
|
187
|
+
'A multisig account address is required with a current config.',
|
|
140
188
|
)
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
weight: Number(owner.weight),
|
|
166
|
-
})),
|
|
167
|
-
}
|
|
168
|
-
if (ownerStates) {
|
|
169
|
-
const states = await ownerStates
|
|
170
|
-
if (states.length > 0) request.multisigOwnerStates = states
|
|
171
|
-
}
|
|
172
|
-
// A non-multisig `account` (e.g. the client's default) isn't the sender,
|
|
173
|
-
// so drop it: core then fills nonce/gas/fees for the multisig sender via
|
|
174
|
-
// `request.from`. A multisig account *is* the sender, so keep it so the
|
|
175
|
-
// prepared request can be sent without re-passing `account`.
|
|
176
|
-
if (request.account?.source !== 'multisig') delete request.account
|
|
189
|
+
const config = await (async () => {
|
|
190
|
+
if (multisigIdentity.config) return multisigIdentity.config
|
|
191
|
+
if (!coordinatedMultisig) return undefined
|
|
192
|
+
const cachedConfig = await getAction(
|
|
193
|
+
client,
|
|
194
|
+
getConfig,
|
|
195
|
+
'getConfig',
|
|
196
|
+
)({ address: account })
|
|
197
|
+
if (!cachedConfig)
|
|
198
|
+
throw new Error(
|
|
199
|
+
`No current multisig config is cached for account ${account}. Provide the current config.`,
|
|
200
|
+
)
|
|
201
|
+
return cachedConfig
|
|
202
|
+
})()
|
|
203
|
+
if (!config)
|
|
204
|
+
throw new Error(
|
|
205
|
+
'A multisig config is required to prepare a transaction.',
|
|
206
|
+
)
|
|
207
|
+
request.from = account
|
|
208
|
+
request.multisigSimulation = getMultisigSimulation({
|
|
209
|
+
account,
|
|
210
|
+
config,
|
|
211
|
+
local,
|
|
212
|
+
})
|
|
177
213
|
}
|
|
178
214
|
|
|
179
215
|
// Register concurrency before account preparation performs storage or
|
|
@@ -181,6 +217,7 @@ export const chainConfig = {
|
|
|
181
217
|
const useExpiringNonce = await (async () => {
|
|
182
218
|
if (request.nonceKey === 'expiring' || request.nonceKey === maxUint256)
|
|
183
219
|
return true
|
|
220
|
+
if (typeof request.nonceKey !== 'undefined') return false
|
|
184
221
|
if (multisigIdentity) return false
|
|
185
222
|
if (request.feePayer && typeof request.nonceKey === 'undefined')
|
|
186
223
|
return true
|
|
@@ -195,7 +232,12 @@ export const chainConfig = {
|
|
|
195
232
|
return false
|
|
196
233
|
})()
|
|
197
234
|
|
|
198
|
-
if (
|
|
235
|
+
if (coordinatedMultisig && typeof request.nonceKey === 'undefined') {
|
|
236
|
+
// A random nonce lane lets a stored approval ceremony remain valid
|
|
237
|
+
// indefinitely without blocking other pending operations.
|
|
238
|
+
request.nonceKey = Hex.toBigInt(Hex.random(31)) + 1n
|
|
239
|
+
request.nonce = 0
|
|
240
|
+
} else if (useExpiringNonce) {
|
|
199
241
|
request.nonceKey = maxUint256
|
|
200
242
|
request.nonce = 0
|
|
201
243
|
if (typeof request.validAfter === 'undefined')
|
|
@@ -254,9 +296,27 @@ export const chainConfig = {
|
|
|
254
296
|
{ runAt: ['beforeFillTransaction', 'afterFillParameters'] },
|
|
255
297
|
],
|
|
256
298
|
serializers: {
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
299
|
+
transaction: serializeTransaction,
|
|
300
|
+
async transactionEnvelope({ serializedTransaction, transaction }) {
|
|
301
|
+
const request = transaction as Transaction.TransactionSerializableTempo
|
|
302
|
+
if (!request.multisigSimulation) return serializedTransaction
|
|
303
|
+
try {
|
|
304
|
+
SignatureEnvelope.deserialize(serializedTransaction)
|
|
305
|
+
} catch {
|
|
306
|
+
const transaction = Transaction.deserialize(
|
|
307
|
+
serializedTransaction as Transaction.TransactionSerializedTempo,
|
|
308
|
+
)
|
|
309
|
+
if (transaction.signature?.type === 'multisig')
|
|
310
|
+
return serializedTransaction
|
|
311
|
+
throw new Error(
|
|
312
|
+
'A Tempo owner account is required to approve a multisig transaction.',
|
|
313
|
+
)
|
|
314
|
+
}
|
|
315
|
+
return await serializeTransaction({
|
|
316
|
+
...request,
|
|
317
|
+
signatures: [...(request.signatures ?? []), serializedTransaction],
|
|
318
|
+
} as never)
|
|
319
|
+
},
|
|
260
320
|
},
|
|
261
321
|
async verifyHash(client, parameters) {
|
|
262
322
|
const { address, hash, signature, mode } = parameters
|
|
@@ -346,3 +406,102 @@ export const chainConfig = {
|
|
|
346
406
|
} as const satisfies viem_ChainConfig & { blockTime: number }
|
|
347
407
|
|
|
348
408
|
export type ChainConfig = typeof chainConfig
|
|
409
|
+
|
|
410
|
+
/** Builds a bounded multisig spec for gas simulation. */
|
|
411
|
+
function getMultisigSimulation(options: {
|
|
412
|
+
account: Address
|
|
413
|
+
config: MultisigConfig.Config
|
|
414
|
+
local?: MultisigAccount | undefined
|
|
415
|
+
}): MultisigSimulation.Spec {
|
|
416
|
+
const { account, config, local } = options
|
|
417
|
+
return {
|
|
418
|
+
account,
|
|
419
|
+
approvals: selectOwners(config).map((owner) => {
|
|
420
|
+
const localOwner = local?.owners.find((account) =>
|
|
421
|
+
isAddressEqual(account.address, owner.owner),
|
|
422
|
+
)
|
|
423
|
+
if (localOwner?.source === 'multisig') {
|
|
424
|
+
const nested = localOwner as MultisigAccount
|
|
425
|
+
if (!nested.config)
|
|
426
|
+
throw new Error(
|
|
427
|
+
'A nested multisig config is required for gas estimation.',
|
|
428
|
+
)
|
|
429
|
+
return {
|
|
430
|
+
type: 'multisig',
|
|
431
|
+
spec: {
|
|
432
|
+
account: nested.address,
|
|
433
|
+
approvals: selectOwners(nested.config).map((owner) => {
|
|
434
|
+
const nestedOwner = nested.owners.find((account) =>
|
|
435
|
+
isAddressEqual(account.address, owner.owner),
|
|
436
|
+
)
|
|
437
|
+
if (nestedOwner?.source === 'multisig')
|
|
438
|
+
throw new Error(
|
|
439
|
+
'Multisig simulation nesting exceeds depth two.',
|
|
440
|
+
)
|
|
441
|
+
return {
|
|
442
|
+
...getSimulationKey(nestedOwner),
|
|
443
|
+
owner: owner.owner,
|
|
444
|
+
}
|
|
445
|
+
}),
|
|
446
|
+
config: nested.config,
|
|
447
|
+
},
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
return {
|
|
451
|
+
...getSimulationKey(localOwner),
|
|
452
|
+
owner: owner.owner,
|
|
453
|
+
type: 'primitive',
|
|
454
|
+
}
|
|
455
|
+
}),
|
|
456
|
+
config,
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
/** Returns signature metadata for conservative gas estimation. */
|
|
461
|
+
function getSimulationKey(
|
|
462
|
+
account: unknown,
|
|
463
|
+
):
|
|
464
|
+
| { keyData: Hex.Hex; keyType: 'webAuthn' }
|
|
465
|
+
| { keyType: 'p256' | 'secp256k1' } {
|
|
466
|
+
const keyType = (() => {
|
|
467
|
+
if (
|
|
468
|
+
account &&
|
|
469
|
+
typeof account === 'object' &&
|
|
470
|
+
'keyType' in account &&
|
|
471
|
+
typeof account.keyType === 'string'
|
|
472
|
+
)
|
|
473
|
+
return account.keyType
|
|
474
|
+
return undefined
|
|
475
|
+
})()
|
|
476
|
+
if (!keyType || keyType === 'webAuthn')
|
|
477
|
+
return { keyData: '0x0578' as const, keyType: 'webAuthn' as const }
|
|
478
|
+
if (keyType === 'p256' || keyType === 'secp256k1') return { keyType }
|
|
479
|
+
return { keyData: '0x0578' as const, keyType: 'webAuthn' as const }
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
/** Returns random past seconds to distinguish otherwise-identical expiring transactions. */
|
|
483
|
+
function randomValidAfter(): number {
|
|
484
|
+
const now = BigInt(Math.floor(Date.now() / 1_000))
|
|
485
|
+
const latest = now - 60n
|
|
486
|
+
if (latest <= 0n) return 0
|
|
487
|
+
return Number(BigInt(Hex.random(8)) % latest)
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
/** Selects a deterministic minimum-cardinality owner quorum. */
|
|
491
|
+
function selectOwners(config: MultisigConfig.Config) {
|
|
492
|
+
const owners = [...config.owners].sort(
|
|
493
|
+
(a, b) =>
|
|
494
|
+
Number(b.weight) - Number(a.weight) ||
|
|
495
|
+
a.owner.toLowerCase().localeCompare(b.owner.toLowerCase()),
|
|
496
|
+
)
|
|
497
|
+
const selected: typeof owners = []
|
|
498
|
+
let weight = 0
|
|
499
|
+
for (const owner of owners.slice(0, MultisigConfig.maxSignatures)) {
|
|
500
|
+
if (weight >= Number(config.threshold)) break
|
|
501
|
+
selected.push(owner)
|
|
502
|
+
weight += Number(owner.weight)
|
|
503
|
+
}
|
|
504
|
+
return selected.sort((a, b) =>
|
|
505
|
+
a.owner.toLowerCase().localeCompare(b.owner.toLowerCase()),
|
|
506
|
+
)
|
|
507
|
+
}
|
package/tempo/index.ts
CHANGED
|
@@ -15,6 +15,7 @@ export {
|
|
|
15
15
|
Channel,
|
|
16
16
|
EarnShares,
|
|
17
17
|
MultisigConfig,
|
|
18
|
+
MultisigOperation,
|
|
18
19
|
Period,
|
|
19
20
|
ReceivePolicyReceipt,
|
|
20
21
|
TempoAddress,
|
|
@@ -23,6 +24,10 @@ export {
|
|
|
23
24
|
VirtualAddress,
|
|
24
25
|
VirtualMaster,
|
|
25
26
|
} from 'ox/tempo'
|
|
27
|
+
export type {
|
|
28
|
+
/** @deprecated */
|
|
29
|
+
Owner as z_MultisigConfigOwner,
|
|
30
|
+
} from 'ox/tempo/MultisigConfig'
|
|
26
31
|
export {
|
|
27
32
|
type CustomTransport,
|
|
28
33
|
type CustomTransportConfig,
|
|
@@ -67,12 +72,14 @@ export * from './errors.js'
|
|
|
67
72
|
export * as Formatters from './Formatters.js'
|
|
68
73
|
export * as Hardfork from './Hardfork.js'
|
|
69
74
|
export * as KeyAuthorizationManager from './KeyAuthorizationManager.js'
|
|
75
|
+
/** @experimental */
|
|
76
|
+
export * as Multisig from './Multisig.js'
|
|
70
77
|
export * as P256 from './P256.js'
|
|
71
78
|
/** @experimental */
|
|
72
79
|
export * as Scopes from './Scopes.js'
|
|
73
80
|
/** @experimental */
|
|
74
81
|
export * as Selectors from './Selectors.js'
|
|
75
|
-
export * as
|
|
82
|
+
export * as Store from './Store.js'
|
|
76
83
|
export * as TokenIds from './TokenIds.js'
|
|
77
84
|
// Export types required for inference.
|
|
78
85
|
export type {
|
|
@@ -110,6 +117,7 @@ export {
|
|
|
110
117
|
http,
|
|
111
118
|
walletNamespaceCompat,
|
|
112
119
|
withFeePayer,
|
|
120
|
+
withMultisig,
|
|
113
121
|
withRelay,
|
|
114
122
|
} from './Transport.js'
|
|
115
123
|
export * as WebAuthnP256 from './WebAuthnP256.js'
|
package/tempo/internal/types.ts
CHANGED
package/tempo/internal/utils.ts
CHANGED
|
@@ -197,6 +197,7 @@ export function pickWriteParameters(parameters: Record<string, unknown>) {
|
|
|
197
197
|
maxPriorityFeePerGas,
|
|
198
198
|
nonce,
|
|
199
199
|
nonceKey,
|
|
200
|
+
owner,
|
|
200
201
|
validAfter,
|
|
201
202
|
validBefore,
|
|
202
203
|
} = parameters
|
|
@@ -211,6 +212,7 @@ export function pickWriteParameters(parameters: Record<string, unknown>) {
|
|
|
211
212
|
maxPriorityFeePerGas,
|
|
212
213
|
nonce,
|
|
213
214
|
nonceKey,
|
|
215
|
+
owner,
|
|
214
216
|
validAfter,
|
|
215
217
|
validBefore,
|
|
216
218
|
}
|