signet.js 0.0.6 → 0.0.7
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/.eslintrc.json +67 -0
- package/.prettierrc +1 -0
- package/babel.config.js +6 -0
- package/docs/dist/.vocs/icons/arrow-diagonal.svg +3 -0
- package/docs/dist/.vocs/icons/chevron-down.svg +13 -0
- package/docs/dist/.vocs/icons/chevron-up.svg +13 -0
- package/docs/dist/.vocs/icons/link.svg +3 -0
- package/docs/dist/.vocs/search-index-7b499e25.json +1 -0
- package/docs/dist/assets/arbitrary-hash-Cd6eo8ZD.js +309 -0
- package/docs/dist/assets/broadcast-tx-CeTEE9yX.js +8 -0
- package/docs/dist/assets/btc-rpc-adapter-C-qSHpFV.js +226 -0
- package/docs/dist/assets/chain-adapter-interface-B9TpOgQv.js +1280 -0
- package/docs/dist/assets/chain-contract-interface-DEku3k45.js +392 -0
- package/docs/dist/assets/constructor-73n7bp3b.js +161 -0
- package/docs/dist/assets/constructor-Bg7nvLe0.js +14 -0
- package/docs/dist/assets/contract-addresses-BYlrAOs3.js +200 -0
- package/docs/dist/assets/derive-address-and-public-key-DExrKiGV.js +14 -0
- package/docs/dist/assets/finalize-message-signing-W435d71R.js +20 -0
- package/docs/dist/assets/finalize-transaction-signing-BIgJ2dnc.js +36 -0
- package/docs/dist/assets/finalize-transaction-signing-C--HJs8D.js +24 -0
- package/docs/dist/assets/finalize-transaction-signing-CjGmN7d9.js +24 -0
- package/docs/dist/assets/finalize-typed-data-signing-CEOp_GWt.js +21 -0
- package/docs/dist/assets/get-balance-DBC-i6KG.js +13 -0
- package/docs/dist/assets/get-current-signature-deposit-BXm9AzYy.js +6 -0
- package/docs/dist/assets/get-current-signature-deposit-nOw4j1MN.js +6 -0
- package/docs/dist/assets/get-derived-public-key-BXvfo2m2.js +14 -0
- package/docs/dist/assets/get-derived-public-key-DQ1pyiFS.js +14 -0
- package/docs/dist/assets/get-latest-key-version-DWlkMCre.js +6 -0
- package/docs/dist/assets/get-public-key-B4PFoVqu.js +6 -0
- package/docs/dist/assets/get-public-key-B9xkYkD_.js +6 -0
- package/docs/dist/assets/index-BFuwoY4w.js +601 -0
- package/docs/dist/assets/index-C62Mf-vy.js +426 -0
- package/docs/dist/assets/index-D8xhaiVb.js +121 -0
- package/docs/dist/assets/index-DTr0DlO0.js +36 -0
- package/docs/dist/assets/index-V9dXf-ik.js +457 -0
- package/docs/dist/assets/prepare-message-for-signing-DESTq-Hg.js +16 -0
- package/docs/dist/assets/prepare-transaction-for-signing-DIKTU0zj.js +33 -0
- package/docs/dist/assets/prepare-transaction-for-signing-DV_wkZ5g.js +21 -0
- package/docs/dist/assets/prepare-transaction-for-signing-LVDP0COu.js +33 -0
- package/docs/dist/assets/prepare-typed-data-for-signing-CWcmJvw0.js +192 -0
- package/docs/dist/assets/sign-CwtS5LnB.js +13 -0
- package/docs/dist/assets/sign-OQxf9yn7.js +15 -0
- package/docs/dist/assets/signet-quick-start-CQK52nVG.js +350 -0
- package/docs/dist/assets/sponsor-foreign-chain-gas-C9iWXM8Q.js +1 -0
- package/docs/dist/assets/style-CKGXuRqx.css +1 -0
- package/docs/dist/examples/arbitrary-hash/index.html +88 -0
- package/docs/dist/examples/sponsor-foreign-chain-gas/index.html +21 -0
- package/docs/dist/index.html +56 -0
- package/docs/dist/initializeTheme.iife.js +1 -0
- package/docs/dist/introduction/signet-quick-start/index.html +109 -0
- package/docs/dist/primitives/chain-adapter-interface/index.html +515 -0
- package/docs/dist/primitives/chain-contract-interface/index.html +306 -0
- package/docs/dist/primitives/contract-addresses/index.html +97 -0
- package/docs/dist/signet-logo.png +0 -0
- package/docs/dist/signetjs/chain-adapters/bitcoin/btc-rpc-adapter/index.html +148 -0
- package/docs/dist/signetjs/chain-adapters/bitcoin/finalize-transaction-signing/index.html +41 -0
- package/docs/dist/signetjs/chain-adapters/bitcoin/index.html +187 -0
- package/docs/dist/signetjs/chain-adapters/bitcoin/prepare-transaction-for-signing/index.html +34 -0
- package/docs/dist/signetjs/chain-adapters/broadcast-tx/index.html +28 -0
- package/docs/dist/signetjs/chain-adapters/cosmos/finalize-transaction-signing/index.html +41 -0
- package/docs/dist/signetjs/chain-adapters/cosmos/index.html +166 -0
- package/docs/dist/signetjs/chain-adapters/cosmos/prepare-transaction-for-signing/index.html +43 -0
- package/docs/dist/signetjs/chain-adapters/derive-address-and-public-key/index.html +31 -0
- package/docs/dist/signetjs/chain-adapters/evm/finalize-message-signing/index.html +38 -0
- package/docs/dist/signetjs/chain-adapters/evm/finalize-transaction-signing/index.html +41 -0
- package/docs/dist/signetjs/chain-adapters/evm/finalize-typed-data-signing/index.html +39 -0
- package/docs/dist/signetjs/chain-adapters/evm/index.html +129 -0
- package/docs/dist/signetjs/chain-adapters/evm/prepare-message-for-signing/index.html +31 -0
- package/docs/dist/signetjs/chain-adapters/evm/prepare-transaction-for-signing/index.html +34 -0
- package/docs/dist/signetjs/chain-adapters/evm/prepare-typed-data-for-signing/index.html +49 -0
- package/docs/dist/signetjs/chain-adapters/get-balance/index.html +30 -0
- package/docs/dist/signetjs/contracts/evm/constructor/index.html +45 -0
- package/docs/dist/signetjs/contracts/evm/get-current-signature-deposit/index.html +26 -0
- package/docs/dist/signetjs/contracts/evm/get-derived-public-key/index.html +31 -0
- package/docs/dist/signetjs/contracts/evm/get-latest-key-version/index.html +26 -0
- package/docs/dist/signetjs/contracts/evm/get-public-key/index.html +26 -0
- package/docs/dist/signetjs/contracts/evm/sign/index.html +32 -0
- package/docs/dist/signetjs/contracts/near/constructor/index.html +34 -0
- package/docs/dist/signetjs/contracts/near/get-current-signature-deposit/index.html +26 -0
- package/docs/dist/signetjs/contracts/near/get-derived-public-key/index.html +31 -0
- package/docs/dist/signetjs/contracts/near/get-public-key/index.html +26 -0
- package/docs/dist/signetjs/contracts/near/sign/index.html +32 -0
- package/docs/pages/examples/arbitrary-hash.mdx +73 -0
- package/docs/pages/examples/sponsor-foreign-chain-gas.mdx +1 -0
- package/docs/pages/index.mdx +36 -0
- package/docs/pages/introduction/signet-quick-start.mdx +88 -0
- package/docs/pages/primitives/chain-adapter-interface.mdx +45 -0
- package/docs/pages/primitives/chain-contract-interface.mdx +52 -0
- package/docs/pages/primitives/contract-addresses.mdx +27 -0
- package/docs/pages/signetjs/chain-adapters/bitcoin/btc-rpc-adapter.mdx +26 -0
- package/docs/pages/signetjs/chain-adapters/bitcoin/finalize-transaction-signing.mdx +47 -0
- package/docs/pages/signetjs/chain-adapters/bitcoin/index.mdx +119 -0
- package/docs/pages/signetjs/chain-adapters/bitcoin/prepare-transaction-for-signing.mdx +30 -0
- package/docs/pages/signetjs/chain-adapters/broadcast-tx.mdx +23 -0
- package/docs/pages/signetjs/chain-adapters/cosmos/finalize-transaction-signing.mdx +53 -0
- package/docs/pages/signetjs/chain-adapters/cosmos/index.mdx +108 -0
- package/docs/pages/signetjs/chain-adapters/cosmos/prepare-transaction-for-signing.mdx +39 -0
- package/docs/pages/signetjs/chain-adapters/derive-address-and-public-key.mdx +28 -0
- package/docs/pages/signetjs/chain-adapters/evm/finalize-message-signing.mdx +33 -0
- package/docs/pages/signetjs/chain-adapters/evm/finalize-transaction-signing.mdx +44 -0
- package/docs/pages/signetjs/chain-adapters/evm/finalize-typed-data-signing.mdx +34 -0
- package/docs/pages/signetjs/chain-adapters/evm/index.mdx +84 -0
- package/docs/pages/signetjs/chain-adapters/evm/prepare-message-for-signing.mdx +26 -0
- package/docs/pages/signetjs/chain-adapters/evm/prepare-transaction-for-signing.mdx +30 -0
- package/docs/pages/signetjs/chain-adapters/evm/prepare-typed-data-for-signing.mdx +44 -0
- package/docs/pages/signetjs/chain-adapters/get-balance.mdx +26 -0
- package/docs/pages/signetjs/contracts/evm/constructor.mdx +38 -0
- package/docs/pages/signetjs/contracts/evm/get-current-signature-deposit.mdx +17 -0
- package/docs/pages/signetjs/contracts/evm/get-derived-public-key.mdx +28 -0
- package/docs/pages/signetjs/contracts/evm/get-latest-key-version.mdx +17 -0
- package/docs/pages/signetjs/contracts/evm/get-public-key.mdx +17 -0
- package/docs/pages/signetjs/contracts/evm/sign.mdx +36 -0
- package/docs/pages/signetjs/contracts/near/constructor.mdx +29 -0
- package/docs/pages/signetjs/contracts/near/get-current-signature-deposit.mdx +17 -0
- package/docs/pages/signetjs/contracts/near/get-derived-public-key.mdx +28 -0
- package/docs/pages/signetjs/contracts/near/get-public-key.mdx +17 -0
- package/docs/pages/signetjs/contracts/near/sign.mdx +32 -0
- package/docs/public/signet-logo.png +0 -0
- package/docs/snippets/code/chains.ts +42 -0
- package/docs/snippets/code/contract.ts +44 -0
- package/docs/snippets/code/evm/contract.ts +24 -0
- package/docs/snippets/code/evm/env.ts +16 -0
- package/docs/snippets/code/near/env.ts +13 -0
- package/hardhat.config.mts +19 -0
- package/package.json +18 -19
- package/src/chain-adapters/Bitcoin/BTCRpcAdapter/BTCRpcAdapter.ts +15 -0
- package/src/chain-adapters/Bitcoin/BTCRpcAdapter/Mempool/Mempool.ts +101 -0
- package/src/chain-adapters/Bitcoin/BTCRpcAdapter/Mempool/index.ts +1 -0
- package/src/chain-adapters/Bitcoin/BTCRpcAdapter/Mempool/types.ts +72 -0
- package/src/chain-adapters/Bitcoin/BTCRpcAdapter/index.ts +6 -0
- package/src/chain-adapters/Bitcoin/Bitcoin.ts +287 -0
- package/src/chain-adapters/Bitcoin/index.ts +13 -0
- package/src/chain-adapters/Bitcoin/types.ts +48 -0
- package/src/chain-adapters/Bitcoin/utils.ts +14 -0
- package/src/chain-adapters/ChainAdapter.ts +92 -0
- package/src/chain-adapters/Cosmos/Cosmos.ts +258 -0
- package/src/chain-adapters/Cosmos/index.ts +8 -0
- package/src/chain-adapters/Cosmos/types.ts +35 -0
- package/src/chain-adapters/Cosmos/utils.ts +45 -0
- package/src/chain-adapters/EVM/EVM.test.ts +238 -0
- package/src/chain-adapters/EVM/EVM.ts +337 -0
- package/src/chain-adapters/EVM/index.ts +11 -0
- package/src/chain-adapters/EVM/types.ts +53 -0
- package/src/chain-adapters/EVM/utils.ts +27 -0
- package/src/chain-adapters/index.ts +5 -0
- package/src/constants.ts +62 -0
- package/src/contracts/ChainSignatureContract.ts +65 -0
- package/src/contracts/evm/ChainSignaturesContract.ts +323 -0
- package/src/contracts/evm/ChainSignaturesContractABI.ts +359 -0
- package/src/contracts/evm/errors.ts +52 -0
- package/src/contracts/evm/index.ts +10 -0
- package/src/contracts/evm/types.ts +39 -0
- package/src/contracts/evm/utils.ts +41 -0
- package/src/contracts/index.ts +4 -0
- package/src/contracts/near/ChainSignatureContract.ts +196 -0
- package/src/contracts/near/account.ts +42 -0
- package/src/contracts/near/constants.ts +4 -0
- package/src/contracts/near/index.ts +10 -0
- package/src/contracts/near/signAndSend/index.ts +1 -0
- package/src/contracts/near/signAndSend/keypair.ts +178 -0
- package/src/contracts/near/transaction.ts +202 -0
- package/src/contracts/near/types.ts +71 -0
- package/src/index.ts +5 -0
- package/src/types.ts +46 -0
- package/src/utils/cryptography.ts +141 -0
- package/src/utils/index.ts +1 -0
- package/src/utils/publicKey.ts +17 -0
- package/tsconfig.eslint.json +8 -0
- package/tsconfig.json +126 -0
- package/tsup.config.ts +58 -0
- package/vitest.config.ts +19 -0
- package/vocs.config.ts +213 -0
- package/browser/index.browser.cjs +0 -3
- package/browser/index.browser.cjs.map +0 -1
- package/browser/index.browser.js +0 -3
- package/browser/index.browser.js.map +0 -1
- package/node/index.node.cjs +0 -3
- package/node/index.node.cjs.map +0 -1
- package/node/index.node.js +0 -3
- package/node/index.node.js.map +0 -1
- package/types/index.d.cts +0 -1048
- package/types/index.d.ts +0 -1048
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
Address,
|
|
3
|
+
Hex,
|
|
4
|
+
TransactionRequest,
|
|
5
|
+
TypedDataDefinition,
|
|
6
|
+
SignableMessage,
|
|
7
|
+
} from 'viem'
|
|
8
|
+
|
|
9
|
+
export type EVMUnsignedTransaction = TransactionRequest & {
|
|
10
|
+
type: 'eip1559'
|
|
11
|
+
chainId: number
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface EVMTransactionRequest
|
|
15
|
+
extends Omit<EVMUnsignedTransaction, 'chainId' | 'type'> {
|
|
16
|
+
from: Address
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export type EVMMessage = SignableMessage
|
|
20
|
+
|
|
21
|
+
export type EVMTypedData = TypedDataDefinition
|
|
22
|
+
|
|
23
|
+
export interface UserOperationV7 {
|
|
24
|
+
sender: Hex
|
|
25
|
+
nonce: Hex
|
|
26
|
+
factory: Hex
|
|
27
|
+
factoryData: Hex
|
|
28
|
+
callData: Hex
|
|
29
|
+
callGasLimit: Hex
|
|
30
|
+
verificationGasLimit: Hex
|
|
31
|
+
preVerificationGas: Hex
|
|
32
|
+
maxFeePerGas: Hex
|
|
33
|
+
maxPriorityFeePerGas: Hex
|
|
34
|
+
paymaster: Hex
|
|
35
|
+
paymasterVerificationGasLimit: Hex
|
|
36
|
+
paymasterPostOpGasLimit: Hex
|
|
37
|
+
paymasterData: Hex
|
|
38
|
+
signature: Hex
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface UserOperationV6 {
|
|
42
|
+
sender: Hex
|
|
43
|
+
nonce: Hex
|
|
44
|
+
initCode: Hex
|
|
45
|
+
callData: Hex
|
|
46
|
+
callGasLimit: Hex
|
|
47
|
+
verificationGasLimit: Hex
|
|
48
|
+
preVerificationGas: Hex
|
|
49
|
+
maxFeePerGas: Hex
|
|
50
|
+
maxPriorityFeePerGas: Hex
|
|
51
|
+
paymasterAndData: Hex
|
|
52
|
+
signature: Hex
|
|
53
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { type PublicClient, type TransactionRequest } from 'viem'
|
|
2
|
+
|
|
3
|
+
export interface EVMFeeProperties {
|
|
4
|
+
gas: bigint
|
|
5
|
+
maxFeePerGas: bigint
|
|
6
|
+
maxPriorityFeePerGas: bigint
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export async function fetchEVMFeeProperties(
|
|
10
|
+
client: PublicClient,
|
|
11
|
+
transaction: TransactionRequest
|
|
12
|
+
): Promise<EVMFeeProperties> {
|
|
13
|
+
const [gas, feeData] = await Promise.all([
|
|
14
|
+
client.estimateGas(transaction),
|
|
15
|
+
client.estimateFeesPerGas(),
|
|
16
|
+
])
|
|
17
|
+
|
|
18
|
+
const maxFeePerGas = feeData.maxFeePerGas ?? BigInt(10_000_000_000) // 10 gwei
|
|
19
|
+
const maxPriorityFeePerGas =
|
|
20
|
+
feeData.maxPriorityFeePerGas ?? BigInt(10_000_000_000) // 10 gwei
|
|
21
|
+
|
|
22
|
+
return {
|
|
23
|
+
gas,
|
|
24
|
+
maxFeePerGas,
|
|
25
|
+
maxPriorityFeePerGas,
|
|
26
|
+
}
|
|
27
|
+
}
|
package/src/constants.ts
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { type NajPublicKey } from '@types'
|
|
2
|
+
|
|
3
|
+
export const ENVS = {
|
|
4
|
+
TESTNET_DEV: 'TESTNET_DEV',
|
|
5
|
+
TESTNET: 'TESTNET',
|
|
6
|
+
MAINNET: 'MAINNET',
|
|
7
|
+
} as const
|
|
8
|
+
|
|
9
|
+
export const CHAINS = {
|
|
10
|
+
ETHEREUM: 'ETHEREUM',
|
|
11
|
+
NEAR: 'NEAR',
|
|
12
|
+
} as const
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Root public keys for the Sig Network Smart Contracts across different environments.
|
|
16
|
+
*
|
|
17
|
+
* These keys should never change.
|
|
18
|
+
*/
|
|
19
|
+
export const ROOT_PUBLIC_KEYS: Record<keyof typeof ENVS, NajPublicKey> = {
|
|
20
|
+
[ENVS.TESTNET_DEV]:
|
|
21
|
+
'secp256k1:54hU5wcCmVUPFWLDALXMh1fFToZsVXrx9BbTbHzSfQq1Kd1rJZi52iPa4QQxo6s5TgjWqgpY8HamYuUDzG6fAaUq',
|
|
22
|
+
[ENVS.TESTNET]:
|
|
23
|
+
'secp256k1:3Ww8iFjqTHufye5aRGUvrQqETegR4gVUcW8FX5xzscaN9ENhpkffojsxJwi6N1RbbHMTxYa9UyKeqK3fsMuwxjR5',
|
|
24
|
+
[ENVS.MAINNET]:
|
|
25
|
+
'secp256k1:4tY4qMzusmgX5wYdG35663Y3Qar3CTbpApotwk9ZKLoF79XA4DjG8XoByaKdNHKQX9Lz5hd7iJqsWdTKyA7dKa6Z',
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Chain IDs used in the key derivation function (KDF) for deriving child public keys to
|
|
30
|
+
* distinguish between different chains.
|
|
31
|
+
*
|
|
32
|
+
* @see {@link deriveChildPublicKey} in cryptography.ts for usage details
|
|
33
|
+
*/
|
|
34
|
+
export const KDF_CHAIN_IDS = {
|
|
35
|
+
[CHAINS.ETHEREUM]: '0x1',
|
|
36
|
+
[CHAINS.NEAR]: '0x18d',
|
|
37
|
+
} as const
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Contract addresses for different chains and environments.
|
|
41
|
+
*
|
|
42
|
+
* - Testnet Dev: Used for internal development, very unstable
|
|
43
|
+
* - Testnet: Used for external development, stable
|
|
44
|
+
* - Mainnet: Production contract address
|
|
45
|
+
*
|
|
46
|
+
* @see ChainSignatureContract documentation for implementation details
|
|
47
|
+
*/
|
|
48
|
+
export const CONTRACT_ADDRESSES: Record<
|
|
49
|
+
keyof typeof CHAINS,
|
|
50
|
+
Record<keyof typeof ENVS, string>
|
|
51
|
+
> = {
|
|
52
|
+
[CHAINS.NEAR]: {
|
|
53
|
+
[ENVS.TESTNET_DEV]: 'dev.sig-net.testnet',
|
|
54
|
+
[ENVS.TESTNET]: 'v1.sig-net.testnet',
|
|
55
|
+
[ENVS.MAINNET]: 'v1.sig-net.near',
|
|
56
|
+
},
|
|
57
|
+
[CHAINS.ETHEREUM]: {
|
|
58
|
+
[ENVS.TESTNET_DEV]: '0x69C6b28Fdc74618817fa380De29a653060e14009',
|
|
59
|
+
[ENVS.TESTNET]: '0x83458E8Bf8206131Fe5c05127007FA164c0948A2',
|
|
60
|
+
[ENVS.MAINNET]: '0xf8bdC0612361a1E49a8E01423d4C0cFc5dF4791A',
|
|
61
|
+
},
|
|
62
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import type BN from 'bn.js'
|
|
2
|
+
|
|
3
|
+
import type { RSVSignature, UncompressedPubKeySEC1 } from '@types'
|
|
4
|
+
|
|
5
|
+
export interface SignArgs {
|
|
6
|
+
/** The payload to sign as an array of 32 bytes */
|
|
7
|
+
payload: number[]
|
|
8
|
+
/** The derivation path for key generation */
|
|
9
|
+
path: string
|
|
10
|
+
/** Version of the key to use */
|
|
11
|
+
key_version: number
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Base contract interface required for compatibility with ChainAdapter instances like EVM and Bitcoin.
|
|
16
|
+
*
|
|
17
|
+
* See {@link EVM} and {@link Bitcoin} for example implementations.
|
|
18
|
+
*/
|
|
19
|
+
export abstract class BaseChainSignatureContract {
|
|
20
|
+
/**
|
|
21
|
+
* Gets the current signature deposit required by the contract.
|
|
22
|
+
* This deposit amount helps manage network congestion.
|
|
23
|
+
*
|
|
24
|
+
* @returns Promise resolving to the required deposit amount as a BigNumber
|
|
25
|
+
*/
|
|
26
|
+
abstract getCurrentSignatureDeposit(): Promise<BN>
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Derives a child public key using a\ derivation path and predecessor.
|
|
30
|
+
*
|
|
31
|
+
* @param args - Arguments for key derivation
|
|
32
|
+
* @param args.path - The string path to use derive the key
|
|
33
|
+
* @param args.predecessor - The id/address of the account requesting signature
|
|
34
|
+
* @returns Promise resolving to the derived SEC1 uncompressed public key
|
|
35
|
+
*/
|
|
36
|
+
abstract getDerivedPublicKey(
|
|
37
|
+
args: {
|
|
38
|
+
path: string
|
|
39
|
+
predecessor: string
|
|
40
|
+
} & Record<string, unknown>
|
|
41
|
+
): Promise<UncompressedPubKeySEC1>
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Full contract interface that extends BaseChainSignatureContract to provide all Sig Network Smart Contract capabilities.
|
|
46
|
+
*/
|
|
47
|
+
export abstract class ChainSignatureContract extends BaseChainSignatureContract {
|
|
48
|
+
/**
|
|
49
|
+
* Signs a payload using Sig Network MPC.
|
|
50
|
+
*
|
|
51
|
+
* @param args - Arguments for the signing operation
|
|
52
|
+
* @param args.payload - The data to sign as an array of 32 bytes
|
|
53
|
+
* @param args.path - The string path to use derive the key
|
|
54
|
+
* @param args.key_version - Version of the key to use
|
|
55
|
+
* @returns Promise resolving to the RSV signature
|
|
56
|
+
*/
|
|
57
|
+
abstract sign(args: SignArgs & Record<string, unknown>): Promise<RSVSignature>
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Gets the public key associated with this contract instance.
|
|
61
|
+
*
|
|
62
|
+
* @returns Promise resolving to the SEC1 uncompressed public key
|
|
63
|
+
*/
|
|
64
|
+
abstract getPublicKey(): Promise<UncompressedPubKeySEC1>
|
|
65
|
+
}
|
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
import { najToUncompressedPubKeySEC1 } from '@utils/cryptography'
|
|
2
|
+
import { getRootPublicKey } from '@utils/publicKey'
|
|
3
|
+
import BN from 'bn.js'
|
|
4
|
+
import { withRetry, type PublicClient, type WalletClient, type Hex } from 'viem'
|
|
5
|
+
|
|
6
|
+
import { CHAINS, KDF_CHAIN_IDS } from '@constants'
|
|
7
|
+
import { ChainSignatureContract as AbstractChainSignatureContract } from '@contracts/ChainSignatureContract'
|
|
8
|
+
import type { SignArgs } from '@contracts/ChainSignatureContract'
|
|
9
|
+
import type {
|
|
10
|
+
NajPublicKey,
|
|
11
|
+
RSVSignature,
|
|
12
|
+
SigNetEvmMpcSignature,
|
|
13
|
+
UncompressedPubKeySEC1,
|
|
14
|
+
} from '@types'
|
|
15
|
+
import { cryptography } from '@utils'
|
|
16
|
+
|
|
17
|
+
import { abi } from './ChainSignaturesContractABI'
|
|
18
|
+
import {
|
|
19
|
+
SignatureNotFoundError,
|
|
20
|
+
SignatureContractError,
|
|
21
|
+
SigningError,
|
|
22
|
+
} from './errors'
|
|
23
|
+
import type {
|
|
24
|
+
RequestIdArgs,
|
|
25
|
+
SignOptions,
|
|
26
|
+
SignRequest,
|
|
27
|
+
SignatureErrorData,
|
|
28
|
+
} from './types'
|
|
29
|
+
import { getRequestId } from './utils'
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Implementation of the ChainSignatureContract for EVM chains.
|
|
33
|
+
*
|
|
34
|
+
* When signing data, the contract emits a SignatureRequested event with a requestId.
|
|
35
|
+
* This requestId is used to track the signature request and retrieve the signature
|
|
36
|
+
* once it's available. The sign method handles this process automatically by polling
|
|
37
|
+
* for the signature using the requestId.
|
|
38
|
+
*/
|
|
39
|
+
export class ChainSignatureContract extends AbstractChainSignatureContract {
|
|
40
|
+
private readonly publicClient: PublicClient
|
|
41
|
+
private readonly walletClient: WalletClient
|
|
42
|
+
private readonly contractAddress: Hex
|
|
43
|
+
private readonly rootPublicKey: NajPublicKey
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Creates a new instance of the ChainSignatureContract for EVM chains.
|
|
47
|
+
*
|
|
48
|
+
* @param args - Configuration options for the contract
|
|
49
|
+
* @param args.publicClient - A Viem PublicClient instance for reading from the blockchain
|
|
50
|
+
* @param args.walletClient - A Viem WalletClient instance for sending transactions
|
|
51
|
+
* @param args.contractAddress - The address of the deployed ChainSignatures contract (e.g. `0x857ED3A242B59cC24144814a0DF41C397a3811E6`)
|
|
52
|
+
* @param args.rootPublicKey - Optional root public key. If not provided, it will be derived from the contract address
|
|
53
|
+
*/
|
|
54
|
+
constructor(args: {
|
|
55
|
+
publicClient: PublicClient
|
|
56
|
+
walletClient: WalletClient
|
|
57
|
+
contractAddress: Hex
|
|
58
|
+
rootPublicKey?: NajPublicKey
|
|
59
|
+
}) {
|
|
60
|
+
super()
|
|
61
|
+
this.publicClient = args.publicClient
|
|
62
|
+
this.walletClient = args.walletClient
|
|
63
|
+
this.contractAddress = args.contractAddress
|
|
64
|
+
|
|
65
|
+
const rootPublicKey =
|
|
66
|
+
args.rootPublicKey ||
|
|
67
|
+
getRootPublicKey(this.contractAddress, CHAINS.ETHEREUM)
|
|
68
|
+
|
|
69
|
+
if (!rootPublicKey) {
|
|
70
|
+
throw new Error(
|
|
71
|
+
`Invalid public key, please provide a valid root public key or contract address`
|
|
72
|
+
)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
this.rootPublicKey = rootPublicKey
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
async getCurrentSignatureDeposit(): Promise<BN> {
|
|
79
|
+
const deposit = (await this.publicClient.readContract({
|
|
80
|
+
address: this.contractAddress,
|
|
81
|
+
abi,
|
|
82
|
+
functionName: 'getSignatureDeposit',
|
|
83
|
+
})) as bigint
|
|
84
|
+
|
|
85
|
+
return new BN(deposit.toString())
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
async getDerivedPublicKey(args: {
|
|
89
|
+
path: string
|
|
90
|
+
predecessor: string
|
|
91
|
+
}): Promise<UncompressedPubKeySEC1> {
|
|
92
|
+
const pubKey = cryptography.deriveChildPublicKey(
|
|
93
|
+
await this.getPublicKey(),
|
|
94
|
+
args.predecessor.toLowerCase(),
|
|
95
|
+
args.path,
|
|
96
|
+
KDF_CHAIN_IDS.ETHEREUM
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
return pubKey
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
async getPublicKey(): Promise<UncompressedPubKeySEC1> {
|
|
103
|
+
return najToUncompressedPubKeySEC1(this.rootPublicKey)
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
async getLatestKeyVersion(): Promise<number> {
|
|
107
|
+
const version = (await this.publicClient.readContract({
|
|
108
|
+
address: this.contractAddress,
|
|
109
|
+
abi,
|
|
110
|
+
functionName: 'latestKeyVersion',
|
|
111
|
+
})) as bigint
|
|
112
|
+
|
|
113
|
+
return Number(version)
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Sends a transaction to the contract to request a signature, then
|
|
118
|
+
* polls for the signature result. If the signature is not found within the retry
|
|
119
|
+
* parameters, it will throw an error.
|
|
120
|
+
*/
|
|
121
|
+
async sign(
|
|
122
|
+
args: SignArgs,
|
|
123
|
+
options: SignOptions = {
|
|
124
|
+
sign: {
|
|
125
|
+
algo: '',
|
|
126
|
+
dest: '',
|
|
127
|
+
params: '',
|
|
128
|
+
},
|
|
129
|
+
retry: {
|
|
130
|
+
delay: 5000,
|
|
131
|
+
retryCount: 12,
|
|
132
|
+
},
|
|
133
|
+
}
|
|
134
|
+
): Promise<RSVSignature> {
|
|
135
|
+
if (!this.walletClient?.account) {
|
|
136
|
+
throw new Error('Wallet client required for signing operations')
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const request: SignRequest = {
|
|
140
|
+
payload: `0x${Buffer.from(args.payload).toString('hex')}`,
|
|
141
|
+
path: args.path,
|
|
142
|
+
keyVersion: args.key_version,
|
|
143
|
+
algo: options.sign.algo ?? '',
|
|
144
|
+
dest: options.sign.dest ?? '',
|
|
145
|
+
params: options.sign.params ?? '',
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const requestId = this.getRequestId({
|
|
149
|
+
...request,
|
|
150
|
+
address: this.walletClient.account.address,
|
|
151
|
+
chainId: this.publicClient.chain?.id
|
|
152
|
+
? BigInt(this.publicClient.chain.id)
|
|
153
|
+
: 0n,
|
|
154
|
+
})
|
|
155
|
+
|
|
156
|
+
const hash = await this.walletClient.writeContract({
|
|
157
|
+
address: this.contractAddress,
|
|
158
|
+
abi,
|
|
159
|
+
chain: this.publicClient.chain,
|
|
160
|
+
account: this.walletClient.account,
|
|
161
|
+
functionName: 'sign',
|
|
162
|
+
args: [request],
|
|
163
|
+
value: BigInt((await this.getCurrentSignatureDeposit()).toString()),
|
|
164
|
+
})
|
|
165
|
+
|
|
166
|
+
const receipt = await this.publicClient.waitForTransactionReceipt({ hash })
|
|
167
|
+
|
|
168
|
+
try {
|
|
169
|
+
const result = await withRetry(
|
|
170
|
+
async () => {
|
|
171
|
+
const result = await this.getSignatureFromEvents(
|
|
172
|
+
requestId,
|
|
173
|
+
receipt.blockNumber
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
// TODO: Validate if this is the signature corresponding to the transaction as anybody can call respond on the contract
|
|
177
|
+
|
|
178
|
+
if (result) {
|
|
179
|
+
return result
|
|
180
|
+
} else {
|
|
181
|
+
throw new Error('Signature not found yet')
|
|
182
|
+
}
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
delay: options.retry.delay,
|
|
186
|
+
retryCount: options.retry.retryCount,
|
|
187
|
+
shouldRetry: ({ count, error }) => {
|
|
188
|
+
// TODO: Should be enabled only on debug mode
|
|
189
|
+
console.log(
|
|
190
|
+
`Retrying get signature: ${count}/${options.retry.retryCount}`
|
|
191
|
+
)
|
|
192
|
+
return error.message === 'Signature not found yet'
|
|
193
|
+
},
|
|
194
|
+
}
|
|
195
|
+
)
|
|
196
|
+
|
|
197
|
+
if (result) {
|
|
198
|
+
return result
|
|
199
|
+
} else {
|
|
200
|
+
const errorData = await this.getErrorFromEvents(
|
|
201
|
+
requestId,
|
|
202
|
+
receipt.blockNumber
|
|
203
|
+
)
|
|
204
|
+
if (errorData) {
|
|
205
|
+
throw new SignatureContractError(errorData.error, requestId, receipt)
|
|
206
|
+
} else {
|
|
207
|
+
throw new SignatureNotFoundError(requestId, receipt)
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
} catch (error) {
|
|
211
|
+
if (
|
|
212
|
+
error instanceof SignatureNotFoundError ||
|
|
213
|
+
error instanceof SignatureContractError
|
|
214
|
+
) {
|
|
215
|
+
throw error
|
|
216
|
+
} else {
|
|
217
|
+
throw new SigningError(
|
|
218
|
+
requestId,
|
|
219
|
+
receipt,
|
|
220
|
+
error instanceof Error ? error : undefined
|
|
221
|
+
)
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Generates the request ID for a signature request allowing to track the response.
|
|
228
|
+
*
|
|
229
|
+
* @param request - The signature request object containing:
|
|
230
|
+
* @param request.address - The contract/wallet address calling the signing contract
|
|
231
|
+
* @param request.payload - The data payload to be signed as a hex string
|
|
232
|
+
* @param request.path - The derivation path for the key
|
|
233
|
+
* @param request.keyVersion - The version of the key to use
|
|
234
|
+
* @param request.chainId - The chain ID as a bigint
|
|
235
|
+
* @param request.algo - The signing algorithm to use
|
|
236
|
+
* @param request.dest - The destination for the signature
|
|
237
|
+
* @param request.params - Additional parameters for the signing process
|
|
238
|
+
* @returns A hex string representing the unique request ID
|
|
239
|
+
*
|
|
240
|
+
* @example
|
|
241
|
+
* ```typescript
|
|
242
|
+
* const requestId = ChainSignatureContract.getRequestId({
|
|
243
|
+
* address: walletClient.account.address,
|
|
244
|
+
* payload: payload: `0x${Buffer.from(args.payload).toString('hex')}`,,
|
|
245
|
+
* path: '',
|
|
246
|
+
* keyVersion: 0,
|
|
247
|
+
* chainId: 1n,
|
|
248
|
+
* algo: '',
|
|
249
|
+
* dest: '',
|
|
250
|
+
* params: ''
|
|
251
|
+
* });
|
|
252
|
+
* console.log(requestId); // 0x...
|
|
253
|
+
* ```
|
|
254
|
+
*/
|
|
255
|
+
getRequestId(request: RequestIdArgs): Hex {
|
|
256
|
+
return getRequestId(request)
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
async getErrorFromEvents(
|
|
260
|
+
requestId: Hex,
|
|
261
|
+
fromBlock: bigint
|
|
262
|
+
): Promise<SignatureErrorData | undefined> {
|
|
263
|
+
const errorLogs = await this.publicClient.getContractEvents({
|
|
264
|
+
address: this.contractAddress,
|
|
265
|
+
abi,
|
|
266
|
+
eventName: 'SignatureError',
|
|
267
|
+
args: {
|
|
268
|
+
requestId,
|
|
269
|
+
},
|
|
270
|
+
fromBlock,
|
|
271
|
+
toBlock: 'latest',
|
|
272
|
+
})
|
|
273
|
+
|
|
274
|
+
if (errorLogs.length > 0) {
|
|
275
|
+
const { args: errorData } = errorLogs[
|
|
276
|
+
errorLogs.length - 1
|
|
277
|
+
] as unknown as {
|
|
278
|
+
args: SignatureErrorData
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
return errorData
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
return undefined
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* Searches for SignatureResponded events that match the given requestId.
|
|
289
|
+
* It works in conjunction with the getRequestId method which generates the unique
|
|
290
|
+
* identifier for a signature request.
|
|
291
|
+
*
|
|
292
|
+
* @param requestId - The identifier for the signature request
|
|
293
|
+
* @param fromBlock - The block number to start searching from
|
|
294
|
+
* @returns The RSV signature if found, undefined otherwise
|
|
295
|
+
*/
|
|
296
|
+
async getSignatureFromEvents(
|
|
297
|
+
requestId: Hex,
|
|
298
|
+
fromBlock: bigint
|
|
299
|
+
): Promise<RSVSignature | undefined> {
|
|
300
|
+
const logs = await this.publicClient.getContractEvents({
|
|
301
|
+
address: this.contractAddress,
|
|
302
|
+
abi,
|
|
303
|
+
eventName: 'SignatureResponded',
|
|
304
|
+
args: {
|
|
305
|
+
requestId,
|
|
306
|
+
},
|
|
307
|
+
fromBlock,
|
|
308
|
+
toBlock: 'latest',
|
|
309
|
+
})
|
|
310
|
+
|
|
311
|
+
if (logs.length > 0) {
|
|
312
|
+
const { args: signatureData } = logs[logs.length - 1] as unknown as {
|
|
313
|
+
args: {
|
|
314
|
+
signature: SigNetEvmMpcSignature
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
return cryptography.toRSV(signatureData.signature)
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
return undefined
|
|
322
|
+
}
|
|
323
|
+
}
|