viem 2.52.0 → 2.52.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 +20 -0
- package/_cjs/actions/wallet/prepareTransactionRequest.js.map +1 -1
- package/_cjs/chains/definitions/citrate.js +17 -0
- package/_cjs/chains/definitions/citrate.js.map +1 -0
- package/_cjs/chains/definitions/grav.js +24 -0
- package/_cjs/chains/definitions/grav.js.map +1 -0
- package/_cjs/chains/definitions/ladyChain.js +22 -0
- package/_cjs/chains/definitions/ladyChain.js.map +1 -0
- package/_cjs/chains/definitions/tempoModerato.js +1 -0
- package/_cjs/chains/definitions/tempoModerato.js.map +1 -1
- package/_cjs/chains/definitions/valygoNft.js +37 -0
- package/_cjs/chains/definitions/valygoNft.js.map +1 -0
- package/_cjs/chains/definitions/valygoSmartchain.js +37 -0
- package/_cjs/chains/definitions/valygoSmartchain.js.map +1 -0
- package/_cjs/chains/index.js +23 -13
- package/_cjs/chains/index.js.map +1 -1
- package/_cjs/errors/version.js +1 -1
- package/_cjs/tempo/Account.js +35 -3
- package/_cjs/tempo/Account.js.map +1 -1
- package/_cjs/tempo/Formatters.js +2 -1
- package/_cjs/tempo/Formatters.js.map +1 -1
- package/_cjs/tempo/Transaction.js +22 -0
- package/_cjs/tempo/Transaction.js.map +1 -1
- package/_cjs/tempo/chainConfig.js +10 -0
- package/_cjs/tempo/chainConfig.js.map +1 -1
- package/_cjs/tempo/index.js +2 -1
- package/_cjs/tempo/index.js.map +1 -1
- package/_esm/actions/wallet/prepareTransactionRequest.js.map +1 -1
- package/_esm/chains/definitions/citrate.js +14 -0
- package/_esm/chains/definitions/citrate.js.map +1 -0
- package/_esm/chains/definitions/grav.js +21 -0
- package/_esm/chains/definitions/grav.js.map +1 -0
- package/_esm/chains/definitions/ladyChain.js +19 -0
- package/_esm/chains/definitions/ladyChain.js.map +1 -0
- package/_esm/chains/definitions/tempoModerato.js +1 -0
- package/_esm/chains/definitions/tempoModerato.js.map +1 -1
- package/_esm/chains/definitions/valygoNft.js +34 -0
- package/_esm/chains/definitions/valygoNft.js.map +1 -0
- package/_esm/chains/definitions/valygoSmartchain.js +34 -0
- package/_esm/chains/definitions/valygoSmartchain.js.map +1 -0
- package/_esm/chains/index.js +5 -0
- package/_esm/chains/index.js.map +1 -1
- package/_esm/errors/version.js +1 -1
- package/_esm/tempo/Account.js +81 -4
- package/_esm/tempo/Account.js.map +1 -1
- package/_esm/tempo/Formatters.js +5 -1
- package/_esm/tempo/Formatters.js.map +1 -1
- package/_esm/tempo/Transaction.js +34 -0
- package/_esm/tempo/Transaction.js.map +1 -1
- package/_esm/tempo/chainConfig.js +24 -1
- package/_esm/tempo/chainConfig.js.map +1 -1
- package/_esm/tempo/index.js +1 -1
- package/_esm/tempo/index.js.map +1 -1
- package/_types/actions/wallet/prepareTransactionRequest.d.ts +12 -1
- package/_types/actions/wallet/prepareTransactionRequest.d.ts.map +1 -1
- package/_types/chains/definitions/citrate.d.ts +57 -0
- package/_types/chains/definitions/citrate.d.ts.map +1 -0
- package/_types/chains/definitions/grav.d.ts +43 -0
- package/_types/chains/definitions/grav.d.ts.map +1 -0
- package/_types/chains/definitions/ladyChain.d.ts +50 -0
- package/_types/chains/definitions/ladyChain.d.ts.map +1 -0
- package/_types/chains/definitions/tempo.d.ts +36 -0
- package/_types/chains/definitions/tempo.d.ts.map +1 -1
- package/_types/chains/definitions/tempoDevnet.d.ts +36 -0
- package/_types/chains/definitions/tempoDevnet.d.ts.map +1 -1
- package/_types/chains/definitions/tempoLocalnet.d.ts +36 -0
- package/_types/chains/definitions/tempoLocalnet.d.ts.map +1 -1
- package/_types/chains/definitions/tempoModerato.d.ts +38 -0
- package/_types/chains/definitions/tempoModerato.d.ts.map +1 -1
- package/_types/chains/definitions/valygoNft.d.ts +48 -0
- package/_types/chains/definitions/valygoNft.d.ts.map +1 -0
- package/_types/chains/definitions/valygoSmartchain.d.ts +48 -0
- package/_types/chains/definitions/valygoSmartchain.d.ts.map +1 -0
- package/_types/chains/index.d.ts +5 -0
- package/_types/chains/index.d.ts.map +1 -1
- package/_types/errors/version.d.ts +1 -1
- package/_types/tempo/Account.d.ts +48 -1
- package/_types/tempo/Account.d.ts.map +1 -1
- package/_types/tempo/Formatters.d.ts.map +1 -1
- package/_types/tempo/Transaction.d.ts +5 -1
- package/_types/tempo/Transaction.d.ts.map +1 -1
- package/_types/tempo/chainConfig.d.ts +34 -15
- package/_types/tempo/chainConfig.d.ts.map +1 -1
- package/_types/tempo/index.d.ts +1 -1
- package/_types/tempo/index.d.ts.map +1 -1
- package/_types/tempo/zones/zone.d.ts +108 -0
- package/_types/tempo/zones/zone.d.ts.map +1 -1
- package/actions/wallet/prepareTransactionRequest.ts +40 -5
- package/chains/definitions/citrate.ts +14 -0
- package/chains/definitions/grav.ts +21 -0
- package/chains/definitions/ladyChain.ts +19 -0
- package/chains/definitions/tempoModerato.ts +1 -0
- package/chains/definitions/valygoNft.ts +34 -0
- package/chains/definitions/valygoSmartchain.ts +34 -0
- package/chains/index.ts +5 -0
- package/errors/version.ts +1 -1
- package/package.json +3 -4
- package/tempo/Account.ts +97 -4
- package/tempo/Formatters.ts +12 -1
- package/tempo/Transaction.ts +42 -0
- package/tempo/chainConfig.ts +32 -3
- package/tempo/index.ts +1 -0
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { defineChain } from '../../utils/chain/defineChain.js'
|
|
2
|
+
|
|
3
|
+
export const valygoSmartchain = defineChain({
|
|
4
|
+
id: 7_771_777,
|
|
5
|
+
name: 'VALYGO Smartchain',
|
|
6
|
+
nativeCurrency: {
|
|
7
|
+
decimals: 18,
|
|
8
|
+
name: 'VYO',
|
|
9
|
+
symbol: 'VYO',
|
|
10
|
+
},
|
|
11
|
+
rpcUrls: {
|
|
12
|
+
default: {
|
|
13
|
+
http: [
|
|
14
|
+
'https://rpc-gw-1.vyoscan.com/ext/bc/2t51dXsuxUvd9teY9TKEJmgxmxMk3CRF88UYTA4HQgjeYZqzSX/rpc',
|
|
15
|
+
'https://rpc-gw-2.vyoscan.com/ext/bc/2t51dXsuxUvd9teY9TKEJmgxmxMk3CRF88UYTA4HQgjeYZqzSX/rpc',
|
|
16
|
+
],
|
|
17
|
+
webSocket: [
|
|
18
|
+
'wss://ws.vyoscan.com/ext/bc/2t51dXsuxUvd9teY9TKEJmgxmxMk3CRF88UYTA4HQgjeYZqzSX/ws',
|
|
19
|
+
],
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
blockExplorers: {
|
|
23
|
+
default: {
|
|
24
|
+
name: 'VYOScan',
|
|
25
|
+
url: 'https://vyoscan.com',
|
|
26
|
+
apiUrl: 'https://vyoscan.com/api',
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
contracts: {
|
|
30
|
+
multicall3: {
|
|
31
|
+
address: '0xeFa3c632BD275750597cE9ca2346A5becAA0F344',
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
})
|
package/chains/index.ts
CHANGED
|
@@ -114,6 +114,7 @@ export { celoSepolia } from './definitions/celoSepolia.js'
|
|
|
114
114
|
export { chang } from './definitions/chang.js'
|
|
115
115
|
export { chiliz } from './definitions/chiliz.js'
|
|
116
116
|
export { chips } from './definitions/chips.js'
|
|
117
|
+
export { citrate } from './definitions/citrate.js'
|
|
117
118
|
export { citrea } from './definitions/citrea.js'
|
|
118
119
|
export { citreaTestnet } from './definitions/citreaTestnet.js'
|
|
119
120
|
export { classic } from './definitions/classic.js'
|
|
@@ -251,6 +252,7 @@ export { godwoken } from './definitions/godwoken.js'
|
|
|
251
252
|
export { goerli } from './definitions/goerli.js'
|
|
252
253
|
export { graphite } from './definitions/graphite.js'
|
|
253
254
|
export { graphiteTestnet } from './definitions/graphiteTestnet.js'
|
|
255
|
+
export { grav } from './definitions/grav.js'
|
|
254
256
|
export { gravity } from './definitions/gravity.js'
|
|
255
257
|
export { gunz } from './definitions/gunz.js'
|
|
256
258
|
export { guruNetwork } from './definitions/guruNetwork.js'
|
|
@@ -350,6 +352,7 @@ export { kromaSepolia } from './definitions/kromaSepolia.js'
|
|
|
350
352
|
export { krown } from './definitions/krown.js'
|
|
351
353
|
export { l3x } from './definitions/l3x.js'
|
|
352
354
|
export { l3xTestnet } from './definitions/l3xTestnet.js'
|
|
355
|
+
export { ladyChain } from './definitions/ladyChain.js'
|
|
353
356
|
export { lavita } from './definitions/lavita.js'
|
|
354
357
|
export { lens } from './definitions/lens.js'
|
|
355
358
|
export { lensTestnet } from './definitions/lensTestnet.js'
|
|
@@ -675,6 +678,8 @@ export { unique } from './definitions/unique.js'
|
|
|
675
678
|
export { uniqueOpal } from './definitions/uniqueOpal.js'
|
|
676
679
|
export { uniqueQuartz } from './definitions/uniqueQuartz.js'
|
|
677
680
|
export { unreal } from './definitions/unreal.js'
|
|
681
|
+
export { valygoNft } from './definitions/valygoNft.js'
|
|
682
|
+
export { valygoSmartchain } from './definitions/valygoSmartchain.js'
|
|
678
683
|
export { vana } from './definitions/vana.js'
|
|
679
684
|
export { vanaMoksha } from './definitions/vanaMoksha.js'
|
|
680
685
|
export { vanar } from './definitions/vanar.js'
|
package/errors/version.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const version = '2.52.
|
|
1
|
+
export const version = '2.52.2'
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "viem",
|
|
3
3
|
"description": "TypeScript Interface for Ethereum",
|
|
4
|
-
"version": "2.52.
|
|
4
|
+
"version": "2.52.2",
|
|
5
5
|
"main": "./_cjs/index.js",
|
|
6
6
|
"module": "./_esm/index.js",
|
|
7
7
|
"types": "./_types/index.d.ts",
|
|
@@ -15,8 +15,7 @@
|
|
|
15
15
|
"!**/*.test.ts.snap",
|
|
16
16
|
"!**/*.test-d.ts",
|
|
17
17
|
"!**/*.tsbuildinfo",
|
|
18
|
-
"!tsconfig.build.json"
|
|
19
|
-
"!jsr.json"
|
|
18
|
+
"!tsconfig.build.json"
|
|
20
19
|
],
|
|
21
20
|
"exports": {
|
|
22
21
|
".": {
|
|
@@ -230,7 +229,7 @@
|
|
|
230
229
|
"@scure/bip39": "1.6.0",
|
|
231
230
|
"abitype": "1.2.3",
|
|
232
231
|
"isows": "1.0.7",
|
|
233
|
-
"ox": "0.14.
|
|
232
|
+
"ox": "0.14.29",
|
|
234
233
|
"ws": "8.20.1"
|
|
235
234
|
},
|
|
236
235
|
"license": "MIT",
|
package/tempo/Account.ts
CHANGED
|
@@ -4,7 +4,12 @@ import * as P256 from 'ox/P256'
|
|
|
4
4
|
import * as PublicKey from 'ox/PublicKey'
|
|
5
5
|
import * as Secp256k1 from 'ox/Secp256k1'
|
|
6
6
|
import * as Signature from 'ox/Signature'
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
Channel,
|
|
9
|
+
KeyAuthorization,
|
|
10
|
+
MultisigConfig,
|
|
11
|
+
SignatureEnvelope,
|
|
12
|
+
} from 'ox/tempo'
|
|
8
13
|
import * as WebAuthnP256 from 'ox/WebAuthnP256'
|
|
9
14
|
import * as WebCryptoP256 from 'ox/WebCryptoP256'
|
|
10
15
|
import type {
|
|
@@ -269,6 +274,78 @@ export declare namespace fromSecp256k1 {
|
|
|
269
274
|
from.ReturnValue<options>
|
|
270
275
|
}
|
|
271
276
|
|
|
277
|
+
/**
|
|
278
|
+
* Instantiates a synthetic Account for a native multisig (TIP-1061) config.
|
|
279
|
+
*
|
|
280
|
+
* The returned account does not hold a key. It is used purely to drive the
|
|
281
|
+
* standard `sendTransaction` flow: it derives the multisig address from the
|
|
282
|
+
* config and passes the prepared request (carrying the collected owner
|
|
283
|
+
* `signatures`) through to the chain serializer, which combines the approvals
|
|
284
|
+
* into the multisig signature envelope.
|
|
285
|
+
*
|
|
286
|
+
* Owner approvals are produced separately by signing with `multisig` request
|
|
287
|
+
* metadata (see `signTransaction`), and provided here via `signatures`.
|
|
288
|
+
*
|
|
289
|
+
* Accepts a raw config and normalizes it internally (via `MultisigConfig.from`),
|
|
290
|
+
* so callers don't need to call `MultisigConfig.from` themselves.
|
|
291
|
+
*
|
|
292
|
+
* @example
|
|
293
|
+
* ```ts
|
|
294
|
+
* import { Account } from 'viem/tempo'
|
|
295
|
+
*
|
|
296
|
+
* const account = Account.fromMultisig({
|
|
297
|
+
* threshold: 2,
|
|
298
|
+
* owners: [
|
|
299
|
+
* { owner: owner_1.address, weight: 1 },
|
|
300
|
+
* { owner: owner_2.address, weight: 1 },
|
|
301
|
+
* ],
|
|
302
|
+
* })
|
|
303
|
+
*
|
|
304
|
+
* // Pass the account to `prepareTransactionRequest` — the multisig config is
|
|
305
|
+
* // inferred from it, so no `multisig` field is needed.
|
|
306
|
+
* const request = await client.prepareTransactionRequest({ account, ...rest })
|
|
307
|
+
*
|
|
308
|
+
* // The prepared request carries the multisig account as sender, so it doesn't
|
|
309
|
+
* // need to be re-passed to `sendTransaction`.
|
|
310
|
+
* const transaction = await client.sendTransaction({
|
|
311
|
+
* ...request,
|
|
312
|
+
* signatures: [signature_1, signature_2],
|
|
313
|
+
* })
|
|
314
|
+
* ```
|
|
315
|
+
*
|
|
316
|
+
* @param config Multisig config (raw or from `MultisigConfig.from`).
|
|
317
|
+
* @returns Multisig account.
|
|
318
|
+
*/
|
|
319
|
+
export function fromMultisig(config: MultisigConfig.Config): MultisigAccount {
|
|
320
|
+
const normalized = MultisigConfig.from(config)
|
|
321
|
+
const address = Address.checksum(MultisigConfig.getAddress(normalized))
|
|
322
|
+
return {
|
|
323
|
+
address,
|
|
324
|
+
config: normalized,
|
|
325
|
+
publicKey: '0x',
|
|
326
|
+
source: 'multisig',
|
|
327
|
+
type: 'local',
|
|
328
|
+
async sign() {
|
|
329
|
+
throw new Error('`sign` is not supported for multisig accounts.')
|
|
330
|
+
},
|
|
331
|
+
async signMessage() {
|
|
332
|
+
throw new Error('`signMessage` is not supported for multisig accounts.')
|
|
333
|
+
},
|
|
334
|
+
async signTransaction(transaction, options) {
|
|
335
|
+
const { serializer = Transaction.serialize } = options ?? {}
|
|
336
|
+
return (await serializer(transaction as never)) as Hex.Hex
|
|
337
|
+
},
|
|
338
|
+
async signTypedData() {
|
|
339
|
+
throw new Error('`signTypedData` is not supported for multisig accounts.')
|
|
340
|
+
},
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
export type MultisigAccount = LocalAccount<'multisig'> & {
|
|
345
|
+
/** Multisig config (from `MultisigConfig.from`). */
|
|
346
|
+
config: MultisigConfig.Config
|
|
347
|
+
}
|
|
348
|
+
|
|
272
349
|
/**
|
|
273
350
|
* Instantiates an Account from a WebAuthn credential.
|
|
274
351
|
*
|
|
@@ -594,9 +671,25 @@ function fromBase(parameters: fromBase.Parameters): Account_base {
|
|
|
594
671
|
return { ...transaction, feePayerSignature: null }
|
|
595
672
|
return transaction
|
|
596
673
|
})()
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
674
|
+
|
|
675
|
+
const payload = keccak256(await serializer(presign))
|
|
676
|
+
|
|
677
|
+
// Native multisig (TIP-1061): return this owner's approval — a serialized
|
|
678
|
+
// primitive signature over the multisig owner approval digest — instead of
|
|
679
|
+
// a full serialized transaction. Approvals are combined later in
|
|
680
|
+
// `sendTransaction({ signatures })`.
|
|
681
|
+
const multisig = (
|
|
682
|
+
transaction as { multisig?: MultisigConfig.Config | undefined }
|
|
683
|
+
).multisig
|
|
684
|
+
if (multisig) {
|
|
685
|
+
const digest = MultisigConfig.getSignPayload({
|
|
686
|
+
payload,
|
|
687
|
+
genesisConfig: multisig,
|
|
688
|
+
})
|
|
689
|
+
return await sign({ hash: digest, raw: true })
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
const signature = await sign({ hash: payload })
|
|
600
693
|
const envelope = SignatureEnvelope.from(signature)
|
|
601
694
|
return await serializer(transaction, envelope as never)
|
|
602
695
|
},
|
package/tempo/Formatters.ts
CHANGED
|
@@ -79,6 +79,8 @@ export function formatTransactionRequest(
|
|
|
79
79
|
keyData?: Hex.Hex | undefined
|
|
80
80
|
keyId?: Address | undefined
|
|
81
81
|
keyType?: 'p256' | 'secp256k1' | 'webAuthn' | undefined
|
|
82
|
+
multisig?: unknown
|
|
83
|
+
signatures?: unknown
|
|
82
84
|
}
|
|
83
85
|
const account = request.account
|
|
84
86
|
? parseAccount<Account | viem_Account | Address>(request.account)
|
|
@@ -116,8 +118,17 @@ export function formatTransactionRequest(
|
|
|
116
118
|
if (request.feePayer === true && !request.feePayerSignature)
|
|
117
119
|
delete request.feeToken
|
|
118
120
|
|
|
121
|
+
// `multisig` / `signatures` are client-side only (TIP-1061). They drive
|
|
122
|
+
// sender derivation, owner signing, and final envelope assembly, but are
|
|
123
|
+
// never sent as raw RPC fields — the wire payload is the serialized tx.
|
|
124
|
+
const {
|
|
125
|
+
multisig: _multisig,
|
|
126
|
+
signatures: _signatures,
|
|
127
|
+
...rpcRequest
|
|
128
|
+
} = request
|
|
129
|
+
|
|
119
130
|
const rpc = ox_TransactionRequest.toRpc({
|
|
120
|
-
...
|
|
131
|
+
...rpcRequest,
|
|
121
132
|
type: 'tempo',
|
|
122
133
|
} as never)
|
|
123
134
|
|
package/tempo/Transaction.ts
CHANGED
|
@@ -7,6 +7,7 @@ import * as Signature from 'ox/Signature'
|
|
|
7
7
|
import {
|
|
8
8
|
type AuthorizationTempo,
|
|
9
9
|
type KeyAuthorization,
|
|
10
|
+
type MultisigConfig,
|
|
10
11
|
type TransactionReceipt as ox_TransactionReceipt,
|
|
11
12
|
SignatureEnvelope,
|
|
12
13
|
type TempoAddress,
|
|
@@ -124,7 +125,9 @@ export type TransactionRequestTempo<
|
|
|
124
125
|
feePayer?: Account | true | undefined
|
|
125
126
|
feeToken?: TempoAddress.Address | bigint | undefined
|
|
126
127
|
keyAuthorization?: KeyAuthorization.Signed<quantity, index> | undefined
|
|
128
|
+
multisig?: MultisigConfig.Config<index> | undefined
|
|
127
129
|
nonceKey?: 'expiring' | quantity | undefined
|
|
130
|
+
signatures?: readonly SignatureEnvelope.Serialized[] | undefined
|
|
128
131
|
validBefore?: index | undefined
|
|
129
132
|
validAfter?: index | undefined
|
|
130
133
|
}
|
|
@@ -145,8 +148,10 @@ export type TransactionSerializableTempo<
|
|
|
145
148
|
feePayerSignature?: viem_Signature | null | undefined
|
|
146
149
|
from?: Address | undefined
|
|
147
150
|
keyAuthorization?: KeyAuthorization.Signed<quantity, index> | undefined
|
|
151
|
+
multisig?: MultisigConfig.Config<index> | undefined
|
|
148
152
|
nonceKey?: quantity | undefined
|
|
149
153
|
signature?: SignatureEnvelope.SignatureEnvelope<quantity, index> | undefined
|
|
154
|
+
signatures?: readonly SignatureEnvelope.Serialized[] | undefined
|
|
150
155
|
validBefore?: index | undefined
|
|
151
156
|
validAfter?: index | undefined
|
|
152
157
|
type?: 'tempo' | undefined
|
|
@@ -170,12 +175,16 @@ export function getType(
|
|
|
170
175
|
if (
|
|
171
176
|
(account?.keyType && account.keyType !== 'secp256k1') ||
|
|
172
177
|
account?.source === 'accessKey' ||
|
|
178
|
+
account?.source === 'multisig' ||
|
|
173
179
|
typeof transaction.calls !== 'undefined' ||
|
|
174
180
|
typeof transaction.feePayer !== 'undefined' ||
|
|
181
|
+
typeof transaction.feePayerSignature !== 'undefined' ||
|
|
175
182
|
typeof transaction.feeToken !== 'undefined' ||
|
|
176
183
|
typeof transaction.keyAuthorization !== 'undefined' ||
|
|
184
|
+
typeof transaction.multisig !== 'undefined' ||
|
|
177
185
|
typeof transaction.nonceKey !== 'undefined' ||
|
|
178
186
|
typeof transaction.signature !== 'undefined' ||
|
|
187
|
+
typeof transaction.signatures !== 'undefined' ||
|
|
179
188
|
typeof transaction.validBefore !== 'undefined' ||
|
|
180
189
|
typeof transaction.validAfter !== 'undefined'
|
|
181
190
|
)
|
|
@@ -337,6 +346,39 @@ async function serializeTempo(
|
|
|
337
346
|
// the fee payer.
|
|
338
347
|
if (shouldStripFeeTokenForSponsorship) delete transaction_ox.feeToken
|
|
339
348
|
|
|
349
|
+
// Native multisig (TIP-1061): combine the collected owner approvals into the
|
|
350
|
+
// multisig signature envelope and serialize the broadcast transaction. The
|
|
351
|
+
// approvals are recovered against the multisig owner digest and ordered into
|
|
352
|
+
// the strictly-ascending owner address order the node requires.
|
|
353
|
+
//
|
|
354
|
+
// Bootstrap (`init`) is auto-detected from the nonce: the protocol requires
|
|
355
|
+
// (and consumes) nonce `0` for the first transaction from a derived account,
|
|
356
|
+
// so `nonce == 0` uniquely identifies a bootstrap. This matches the serialized
|
|
357
|
+
// nonce above (a falsy `nonce` serializes as `0`). The owner approval digest
|
|
358
|
+
// doesn't commit to `init`, so attaching it here (rather than at owner-signing)
|
|
359
|
+
// is safe.
|
|
360
|
+
// NOTE: fee-payer + multisig is handled in a later phase.
|
|
361
|
+
if (transaction.multisig && transaction.signatures && !feePayer) {
|
|
362
|
+
const payload = TxTempo.getSignPayload(TxTempo.from(transaction_ox))
|
|
363
|
+
const signatures = transaction.signatures.map((approval) =>
|
|
364
|
+
SignatureEnvelope.from(approval),
|
|
365
|
+
)
|
|
366
|
+
const sorted = SignatureEnvelope.sortMultisigApprovals({
|
|
367
|
+
payload,
|
|
368
|
+
signatures,
|
|
369
|
+
genesisConfig: transaction.multisig,
|
|
370
|
+
})
|
|
371
|
+
const signature = SignatureEnvelope.from({
|
|
372
|
+
genesisConfig: transaction.multisig,
|
|
373
|
+
signatures: sorted,
|
|
374
|
+
...(nonce ? {} : { init: true }),
|
|
375
|
+
})
|
|
376
|
+
return TxTempo.serialize(transaction_ox, {
|
|
377
|
+
feePayerSignature: undefined,
|
|
378
|
+
signature,
|
|
379
|
+
})
|
|
380
|
+
}
|
|
381
|
+
|
|
340
382
|
if (signature && typeof transaction.feePayer === 'object') {
|
|
341
383
|
const tx = TxTempo.from(transaction_ox, {
|
|
342
384
|
signature,
|
package/tempo/chainConfig.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import type { Address } from 'abitype'
|
|
1
2
|
import * as Hex from 'ox/Hex'
|
|
2
|
-
import { SignatureEnvelope, type TokenId } from 'ox/tempo'
|
|
3
|
+
import { MultisigConfig, SignatureEnvelope, type TokenId } from 'ox/tempo'
|
|
3
4
|
import { getCode } from '../actions/public/getCode.js'
|
|
4
5
|
import { verifyHash } from '../actions/public/verifyHash.js'
|
|
5
6
|
import { maxUint256 } from '../constants/number.js'
|
|
@@ -12,7 +13,7 @@ import { defineTransactionRequest } from '../utils/formatters/transactionRequest
|
|
|
12
13
|
import { getAction } from '../utils/getAction.js'
|
|
13
14
|
import { keccak256 } from '../utils/hash/keccak256.js'
|
|
14
15
|
import type { SerializeTransactionFn } from '../utils/transaction/serializeTransaction.js'
|
|
15
|
-
import type { Account } from './Account.js'
|
|
16
|
+
import type { Account, MultisigAccount } from './Account.js'
|
|
16
17
|
import { getMetadata } from './actions/accessKey.js'
|
|
17
18
|
import * as Formatters from './Formatters.js'
|
|
18
19
|
import type { Hardfork } from './Hardfork.js'
|
|
@@ -42,13 +43,16 @@ export const chainConfig = {
|
|
|
42
43
|
prepareTransactionRequest: [
|
|
43
44
|
async (r, { client, phase }) => {
|
|
44
45
|
const request = r as Transaction.TransactionRequest & {
|
|
45
|
-
account?: Account | undefined
|
|
46
|
+
account?: Account | MultisigAccount | undefined
|
|
46
47
|
chainId?: number | undefined
|
|
47
48
|
chain?:
|
|
48
49
|
| (Chain & {
|
|
49
50
|
feeToken?: TokenId.TokenIdOrAddress | undefined
|
|
50
51
|
})
|
|
51
52
|
| undefined
|
|
53
|
+
from?: Address | undefined
|
|
54
|
+
multisig?: MultisigConfig.Config | undefined
|
|
55
|
+
signatures?: readonly unknown[] | undefined
|
|
52
56
|
}
|
|
53
57
|
|
|
54
58
|
// FIXME: node estimates gas with secp256k1 dummy sig + null feePayerSignature.
|
|
@@ -60,9 +64,34 @@ export const chainConfig = {
|
|
|
60
64
|
else if (request.account?.source === 'accessKey')
|
|
61
65
|
request.gas = (request.gas ?? 0n) + 10_000n
|
|
62
66
|
}
|
|
67
|
+
|
|
63
68
|
return request as unknown as typeof r
|
|
64
69
|
}
|
|
65
70
|
|
|
71
|
+
// Native multisig (TIP-1061). The transaction sender is the derived
|
|
72
|
+
// multisig account, not a signing account (owner accounts only contribute
|
|
73
|
+
// approvals later via `signTransaction`). Derive the sender from the
|
|
74
|
+
// config; core fills nonce/gas/fees for it via `request.from`, and the
|
|
75
|
+
// serializer auto-detects bootstrap (`init`) from `nonce == 0`.
|
|
76
|
+
//
|
|
77
|
+
// The config is taken from an explicit `multisig` field, or inferred from
|
|
78
|
+
// a multisig account (so callers can just pass `account` to
|
|
79
|
+
// `prepareTransactionRequest` without also passing `multisig`).
|
|
80
|
+
const multisig =
|
|
81
|
+
request.multisig ??
|
|
82
|
+
(request.account?.source === 'multisig'
|
|
83
|
+
? (request.account as MultisigAccount).config
|
|
84
|
+
: undefined)
|
|
85
|
+
if (multisig) {
|
|
86
|
+
request.multisig = multisig
|
|
87
|
+
request.from = MultisigConfig.getAddress(multisig)
|
|
88
|
+
// A non-multisig `account` (e.g. the client's default) isn't the sender,
|
|
89
|
+
// so drop it: core then fills nonce/gas/fees for the multisig sender via
|
|
90
|
+
// `request.from`. A multisig account *is* the sender — keep it so the
|
|
91
|
+
// prepared request can be sent without re-passing `account`.
|
|
92
|
+
if (request.account?.source !== 'multisig') delete request.account
|
|
93
|
+
}
|
|
94
|
+
|
|
66
95
|
if (
|
|
67
96
|
!request.keyAuthorization &&
|
|
68
97
|
request.account?.source === 'accessKey'
|