@meshconnect/uwc-types 0.14.0-snapshot.6b75329 → 0.15.0
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/dist/connector.d.ts +8 -1
- package/dist/connector.d.ts.map +1 -1
- package/dist/react-hooks.d.ts +27 -1
- package/dist/react-hooks.d.ts.map +1 -1
- package/dist/signature.d.ts +35 -0
- package/dist/signature.d.ts.map +1 -1
- package/dist/signature.js +39 -1
- package/dist/signature.js.map +1 -1
- package/package.json +1 -1
- package/src/connector.ts +15 -1
- package/src/react-hooks.ts +30 -0
- package/src/signature.test.ts +197 -0
- package/src/signature.ts +59 -0
package/dist/connector.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type { Network, NetworkId, Namespace } from './networks';
|
|
|
2
2
|
import type { AvailableAddress } from './session';
|
|
3
3
|
import type { DetectedEIP6963WalletInfo, DetectedSolanaWalletInfo, DetectedTronWalletInfo, DetectedTonWalletInfo, ExtensionInjectedProvider, IntegratedBrowserInjectedProvider, WalletConnectProvider, TonConnectWalletProvider, WalletMetadata } from './UWC-state';
|
|
4
4
|
import type { EVMCapabilities, TransactionRequest, TransactionResult } from './transactions';
|
|
5
|
-
import type { SignatureType } from './signature';
|
|
5
|
+
import type { SignatureType, EIP712TypedData } from './signature';
|
|
6
6
|
/**
|
|
7
7
|
* Result interface for connect operations
|
|
8
8
|
*/
|
|
@@ -68,6 +68,13 @@ export interface Connector {
|
|
|
68
68
|
* @returns A promise that resolves to the signature
|
|
69
69
|
*/
|
|
70
70
|
signMessage?(message: string, provider?: ExtensionInjectedProvider | IntegratedBrowserInjectedProvider | WalletConnectProvider | TonConnectWalletProvider): Promise<SignatureType>;
|
|
71
|
+
/**
|
|
72
|
+
* Sign EIP-712 typed structured data (eth_signTypedData_v4).
|
|
73
|
+
* Required for ERC-3009 (Transfer With Authorization) and EIP-2612 (Permit) relay flows.
|
|
74
|
+
* EVM-only (eip155); connectors that don't support it leave this undefined.
|
|
75
|
+
* @returns A promise that resolves to the 65-byte hex signature (0x-prefixed)
|
|
76
|
+
*/
|
|
77
|
+
signTypedData?(typedData: EIP712TypedData, provider?: ExtensionInjectedProvider | IntegratedBrowserInjectedProvider | WalletConnectProvider): Promise<string>;
|
|
71
78
|
/**
|
|
72
79
|
* Send a transaction with the connected wallet
|
|
73
80
|
* @param request The transaction request parameters
|
package/dist/connector.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"connector.d.ts","sourceRoot":"","sources":["../src/connector.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AAC/D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAA;AACjD,OAAO,KAAK,EACV,yBAAyB,EACzB,wBAAwB,EACxB,sBAAsB,EACtB,qBAAqB,EACrB,yBAAyB,EACzB,iCAAiC,EACjC,qBAAqB,EACrB,wBAAwB,EACxB,cAAc,EACf,MAAM,aAAa,CAAA;AACpB,OAAO,KAAK,EACV,eAAe,EACf,kBAAkB,EAClB,iBAAiB,EAClB,MAAM,gBAAgB,CAAA;AACvB,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"connector.d.ts","sourceRoot":"","sources":["../src/connector.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AAC/D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAA;AACjD,OAAO,KAAK,EACV,yBAAyB,EACzB,wBAAwB,EACxB,sBAAsB,EACtB,qBAAqB,EACrB,yBAAyB,EACzB,iCAAiC,EACjC,qBAAqB,EACrB,wBAAwB,EACxB,cAAc,EACf,MAAM,aAAa,CAAA;AACpB,OAAO,KAAK,EACV,eAAe,EACf,kBAAkB,EAClB,iBAAiB,EAClB,MAAM,gBAAgB,CAAA;AACvB,OAAO,KAAK,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAEjE;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,SAAS,CAAA;IACpB,OAAO,EAAE,MAAM,CAAA;IACf,kBAAkB,EAAE,gBAAgB,EAAE,CAAA;IACtC,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,SAAS,CAAA;IACpB,OAAO,EAAE,MAAM,CAAA;IACf,kBAAkB,CAAC,EAAE,gBAAgB,EAAE,CAAA;CACxC;AAED;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB;;;;;OAKG;IAEH,OAAO,CACL,OAAO,EAAE,OAAO,EAChB,QAAQ,CAAC,EACL,yBAAyB,GACzB,iCAAiC,GACjC,qBAAqB,GACrB,wBAAwB,GAC3B,OAAO,CAAC,eAAe,CAAC,CAAA;IAE3B;;;;;;;OAOG;IACH,gBAAgB,CAAC,IAAI,MAAM,CAAA;IAE3B;;;;OAIG;IACH,UAAU,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;IAE5B;;;;;OAKG;IAEH,aAAa,CACX,OAAO,EAAE,OAAO,EAChB,QAAQ,CAAC,EACL,yBAAyB,GACzB,iCAAiC,GACjC,qBAAqB,GACrB,wBAAwB,GAC3B,OAAO,CAAC,mBAAmB,CAAC,CAAA;IAE/B;;;;;;OAMG;IACH,mBAAmB,CAAC,CAClB,SAAS,EAAE,SAAS,EACpB,eAAe,CAAC,EAAE,cAAc,EAAE,GACjC,OAAO,CACN,yBAAyB,EAAE,GAC3B,wBAAwB,EAAE,GAC1B,sBAAsB,EAAE,GACxB,qBAAqB,EAAE,CAC1B,CAAA;IAED;;;;;OAKG;IACH,WAAW,CAAC,CACV,OAAO,EAAE,MAAM,EACf,QAAQ,CAAC,EACL,yBAAyB,GACzB,iCAAiC,GACjC,qBAAqB,GACrB,wBAAwB,GAC3B,OAAO,CAAC,aAAa,CAAC,CAAA;IAEzB;;;;;OAKG;IACH,aAAa,CAAC,CACZ,SAAS,EAAE,eAAe,EAC1B,QAAQ,CAAC,EACL,yBAAyB,GACzB,iCAAiC,GACjC,qBAAqB,GACxB,OAAO,CAAC,MAAM,CAAC,CAAA;IAElB;;;;;OAKG;IACH,eAAe,CAAC,CACd,OAAO,EAAE,kBAAkB,EAC3B,QAAQ,CAAC,EACL,yBAAyB,GACzB,iCAAiC,GACjC,qBAAqB,GACrB,wBAAwB,GAC3B,OAAO,CAAC,iBAAiB,CAAC,CAAA;IAE7B,qBAAqB,CAAC,CACpB,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,OAAO,EAAE,GAClB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC,CAAA;IAE3C;;;;OAIG;IACH,0BAA0B,CAAC,CAAC,YAAY,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,CAAA;CAC3E"}
|
package/dist/react-hooks.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { NetworkId, Network, ConnectionMode, Session, AvailableAddress, TransactionRequest, TransactionResult, WalletError, EVMCapabilities, SignatureType, WalletMetadata } from './index';
|
|
1
|
+
import type { NetworkId, Network, ConnectionMode, Session, AvailableAddress, TransactionRequest, TransactionResult, WalletError, EVMCapabilities, SignatureType, EIP712TypedData, WalletMetadata } from './index';
|
|
2
2
|
/**
|
|
3
3
|
* WalletConnect connection interface for the useConnection hook
|
|
4
4
|
*/
|
|
@@ -230,6 +230,32 @@ export interface UseSignMessageReturn {
|
|
|
230
230
|
*/
|
|
231
231
|
error: WalletError | undefined;
|
|
232
232
|
}
|
|
233
|
+
/**
|
|
234
|
+
* Return type for the useSignTypedData hook.
|
|
235
|
+
* Provides EIP-712 typed data signing (eth_signTypedData_v4) for EVM wallets.
|
|
236
|
+
* Used by ERC-3009 (Transfer With Authorization) and EIP-2612 (Permit) relay flows.
|
|
237
|
+
*/
|
|
238
|
+
export interface UseSignTypedDataReturn {
|
|
239
|
+
/**
|
|
240
|
+
* Signs EIP-712 typed data with the connected EVM wallet
|
|
241
|
+
* @param typedData - The EIP-712 typed data to sign
|
|
242
|
+
* @returns Promise that resolves to the 65-byte hex signature (0x-prefixed)
|
|
243
|
+
* @throws Error if no wallet is connected, the wallet is non-EVM, or signing fails
|
|
244
|
+
*/
|
|
245
|
+
signTypedData: (typedData: EIP712TypedData) => Promise<string>;
|
|
246
|
+
/**
|
|
247
|
+
* Indicates if a typed-data signing operation is currently in progress
|
|
248
|
+
*/
|
|
249
|
+
isLoading: boolean;
|
|
250
|
+
/**
|
|
251
|
+
* The raw hex signature from the last successful sign, undefined if not yet signed
|
|
252
|
+
*/
|
|
253
|
+
signature: string | undefined;
|
|
254
|
+
/**
|
|
255
|
+
* Error from the last signing attempt, undefined if no error occurred
|
|
256
|
+
*/
|
|
257
|
+
error: WalletError | undefined;
|
|
258
|
+
}
|
|
233
259
|
/**
|
|
234
260
|
* Return type for useSignSolanaTransaction — sign-only Solana signing (bytes in,
|
|
235
261
|
* bytes out) for fee-payer relay flows where the relay, not the wallet, broadcasts.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"react-hooks.d.ts","sourceRoot":"","sources":["../src/react-hooks.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"react-hooks.d.ts","sourceRoot":"","sources":["../src/react-hooks.ts"],"names":[],"mappings":"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"}
|
package/dist/signature.d.ts
CHANGED
|
@@ -1,4 +1,39 @@
|
|
|
1
1
|
import type { ExtensionInjectedProvider, IntegratedBrowserInjectedProvider } from './UWC-state';
|
|
2
|
+
/**
|
|
3
|
+
* EIP-712 typed structured data for eth_signTypedData_v4.
|
|
4
|
+
* Used by ERC-3009 (Transfer With Authorization), EIP-2612 (Permit), and similar standards.
|
|
5
|
+
*/
|
|
6
|
+
export interface EIP712TypedData {
|
|
7
|
+
domain: {
|
|
8
|
+
name?: string;
|
|
9
|
+
version?: string;
|
|
10
|
+
chainId?: number;
|
|
11
|
+
verifyingContract?: string;
|
|
12
|
+
salt?: string;
|
|
13
|
+
};
|
|
14
|
+
types: Record<string, Array<{
|
|
15
|
+
name: string;
|
|
16
|
+
type: string;
|
|
17
|
+
}>>;
|
|
18
|
+
primaryType: string;
|
|
19
|
+
message: Record<string, unknown>;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Ensures the EIP712Domain type entry is present in `types`, derived from the
|
|
23
|
+
* fields actually set on `domain`, in EIP-712's canonical order.
|
|
24
|
+
*
|
|
25
|
+
* Why: some wallets (notably Trust Wallet and several mobile wallets over
|
|
26
|
+
* WalletConnect) parse the `types` object strictly and reject an
|
|
27
|
+
* eth_signTypedData_v4 request that omits EIP712Domain. Desktop MetaMask derives
|
|
28
|
+
* it implicitly, so callers tend to leave it out — this normalizes both.
|
|
29
|
+
*
|
|
30
|
+
* If the caller already supplied EIP712Domain, theirs is authoritative and the
|
|
31
|
+
* input is returned untouched. Otherwise a new object is returned (input is not
|
|
32
|
+
* mutated) with EIP712Domain inserted first.
|
|
33
|
+
*
|
|
34
|
+
* @see https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator
|
|
35
|
+
*/
|
|
36
|
+
export declare function withEIP712Domain(typedData: EIP712TypedData): EIP712TypedData;
|
|
2
37
|
/**
|
|
3
38
|
* Standard signature format for most blockchains (EVM, Solana, etc.)
|
|
4
39
|
*/
|
package/dist/signature.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"signature.d.ts","sourceRoot":"","sources":["../src/signature.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,yBAAyB,EACzB,iCAAiC,EAClC,MAAM,aAAa,CAAA;AAEpB;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,UAAU,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,EAAE,MAAM,EAAE,CAAA;IACnB,IAAI,EAAE,MAAM,CAAA;CACb;AAED;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAC1B;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC9B;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC9C;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAA;AAErC;;;;;GAKG;AACH,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,KAAK,CAAA;IACX,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;IACjB,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,kBAAkB,CAAA;CAC5B;AAED;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG,iBAAiB,GAAG,aAAa,GAAG,YAAY,CAAA;AAE5E;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,aAAa,CAAA;IACxB,OAAO,EAAE,MAAM,CAAA;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;;;;OAKG;IACH,WAAW,CACT,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,yBAAyB,GAAG,iCAAiC,GACtE,OAAO,CAAC,eAAe,CAAC,CAAA;CAC5B"}
|
|
1
|
+
{"version":3,"file":"signature.d.ts","sourceRoot":"","sources":["../src/signature.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,yBAAyB,EACzB,iCAAiC,EAClC,MAAM,aAAa,CAAA;AAEpB;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE;QACN,IAAI,CAAC,EAAE,MAAM,CAAA;QACb,OAAO,CAAC,EAAE,MAAM,CAAA;QAChB,OAAO,CAAC,EAAE,MAAM,CAAA;QAChB,iBAAiB,CAAC,EAAE,MAAM,CAAA;QAC1B,IAAI,CAAC,EAAE,MAAM,CAAA;KACd,CAAA;IACD,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC,CAAA;IAC5D,WAAW,EAAE,MAAM,CAAA;IACnB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CACjC;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,eAAe,GAAG,eAAe,CAyB5E;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,UAAU,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,EAAE,MAAM,EAAE,CAAA;IACnB,IAAI,EAAE,MAAM,CAAA;CACb;AAED;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAC1B;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC9B;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC9C;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAA;AAErC;;;;;GAKG;AACH,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,KAAK,CAAA;IACX,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;IACjB,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,kBAAkB,CAAA;CAC5B;AAED;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG,iBAAiB,GAAG,aAAa,GAAG,YAAY,CAAA;AAE5E;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,aAAa,CAAA;IACxB,OAAO,EAAE,MAAM,CAAA;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;;;;OAKG;IACH,WAAW,CACT,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,yBAAyB,GAAG,iCAAiC,GACtE,OAAO,CAAC,eAAe,CAAC,CAAA;CAC5B"}
|
package/dist/signature.js
CHANGED
|
@@ -1,2 +1,40 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Ensures the EIP712Domain type entry is present in `types`, derived from the
|
|
3
|
+
* fields actually set on `domain`, in EIP-712's canonical order.
|
|
4
|
+
*
|
|
5
|
+
* Why: some wallets (notably Trust Wallet and several mobile wallets over
|
|
6
|
+
* WalletConnect) parse the `types` object strictly and reject an
|
|
7
|
+
* eth_signTypedData_v4 request that omits EIP712Domain. Desktop MetaMask derives
|
|
8
|
+
* it implicitly, so callers tend to leave it out — this normalizes both.
|
|
9
|
+
*
|
|
10
|
+
* If the caller already supplied EIP712Domain, theirs is authoritative and the
|
|
11
|
+
* input is returned untouched. Otherwise a new object is returned (input is not
|
|
12
|
+
* mutated) with EIP712Domain inserted first.
|
|
13
|
+
*
|
|
14
|
+
* @see https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator
|
|
15
|
+
*/
|
|
16
|
+
export function withEIP712Domain(typedData) {
|
|
17
|
+
if (Object.hasOwn(typedData.types, 'EIP712Domain'))
|
|
18
|
+
return typedData;
|
|
19
|
+
const { domain } = typedData;
|
|
20
|
+
const domainFields = [];
|
|
21
|
+
// Canonical field order — the on-chain domainSeparator hash depends on it.
|
|
22
|
+
if (domain.name !== undefined)
|
|
23
|
+
domainFields.push({ name: 'name', type: 'string' });
|
|
24
|
+
if (domain.version !== undefined)
|
|
25
|
+
domainFields.push({ name: 'version', type: 'string' });
|
|
26
|
+
if (domain.chainId !== undefined)
|
|
27
|
+
domainFields.push({ name: 'chainId', type: 'uint256' });
|
|
28
|
+
if (domain.verifyingContract !== undefined)
|
|
29
|
+
domainFields.push({ name: 'verifyingContract', type: 'address' });
|
|
30
|
+
if (domain.salt !== undefined)
|
|
31
|
+
domainFields.push({ name: 'salt', type: 'bytes32' });
|
|
32
|
+
return {
|
|
33
|
+
...typedData,
|
|
34
|
+
types: {
|
|
35
|
+
EIP712Domain: domainFields,
|
|
36
|
+
...typedData.types
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
}
|
|
2
40
|
//# sourceMappingURL=signature.js.map
|
package/dist/signature.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"signature.js","sourceRoot":"","sources":["../src/signature.ts"],"names":[],"mappings":""}
|
|
1
|
+
{"version":3,"file":"signature.js","sourceRoot":"","sources":["../src/signature.ts"],"names":[],"mappings":"AAsBA;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,gBAAgB,CAAC,SAA0B;IACzD,IAAI,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,EAAE,cAAc,CAAC;QAAE,OAAO,SAAS,CAAA;IAEpE,MAAM,EAAE,MAAM,EAAE,GAAG,SAAS,CAAA;IAC5B,MAAM,YAAY,GAA0C,EAAE,CAAA;IAE9D,2EAA2E;IAC3E,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS;QAC3B,YAAY,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAA;IACrD,IAAI,MAAM,CAAC,OAAO,KAAK,SAAS;QAC9B,YAAY,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAA;IACxD,IAAI,MAAM,CAAC,OAAO,KAAK,SAAS;QAC9B,YAAY,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAA;IACzD,IAAI,MAAM,CAAC,iBAAiB,KAAK,SAAS;QACxC,YAAY,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,mBAAmB,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAA;IACnE,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS;QAC3B,YAAY,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAA;IAEtD,OAAO;QACL,GAAG,SAAS;QACZ,KAAK,EAAE;YACL,YAAY,EAAE,YAAY;YAC1B,GAAG,SAAS,CAAC,KAAK;SACnB;KACF,CAAA;AACH,CAAC"}
|
package/package.json
CHANGED
package/src/connector.ts
CHANGED
|
@@ -16,7 +16,7 @@ import type {
|
|
|
16
16
|
TransactionRequest,
|
|
17
17
|
TransactionResult
|
|
18
18
|
} from './transactions'
|
|
19
|
-
import type { SignatureType } from './signature'
|
|
19
|
+
import type { SignatureType, EIP712TypedData } from './signature'
|
|
20
20
|
|
|
21
21
|
/**
|
|
22
22
|
* Result interface for connect operations
|
|
@@ -122,6 +122,20 @@ export interface Connector {
|
|
|
122
122
|
| TonConnectWalletProvider
|
|
123
123
|
): Promise<SignatureType>
|
|
124
124
|
|
|
125
|
+
/**
|
|
126
|
+
* Sign EIP-712 typed structured data (eth_signTypedData_v4).
|
|
127
|
+
* Required for ERC-3009 (Transfer With Authorization) and EIP-2612 (Permit) relay flows.
|
|
128
|
+
* EVM-only (eip155); connectors that don't support it leave this undefined.
|
|
129
|
+
* @returns A promise that resolves to the 65-byte hex signature (0x-prefixed)
|
|
130
|
+
*/
|
|
131
|
+
signTypedData?(
|
|
132
|
+
typedData: EIP712TypedData,
|
|
133
|
+
provider?:
|
|
134
|
+
| ExtensionInjectedProvider
|
|
135
|
+
| IntegratedBrowserInjectedProvider
|
|
136
|
+
| WalletConnectProvider
|
|
137
|
+
): Promise<string>
|
|
138
|
+
|
|
125
139
|
/**
|
|
126
140
|
* Send a transaction with the connected wallet
|
|
127
141
|
* @param request The transaction request parameters
|
package/src/react-hooks.ts
CHANGED
|
@@ -9,6 +9,7 @@ import type {
|
|
|
9
9
|
WalletError,
|
|
10
10
|
EVMCapabilities,
|
|
11
11
|
SignatureType,
|
|
12
|
+
EIP712TypedData,
|
|
12
13
|
WalletMetadata
|
|
13
14
|
} from './index'
|
|
14
15
|
|
|
@@ -258,6 +259,35 @@ export interface UseSignMessageReturn {
|
|
|
258
259
|
error: WalletError | undefined
|
|
259
260
|
}
|
|
260
261
|
|
|
262
|
+
// useSignTypedData hook types
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Return type for the useSignTypedData hook.
|
|
266
|
+
* Provides EIP-712 typed data signing (eth_signTypedData_v4) for EVM wallets.
|
|
267
|
+
* Used by ERC-3009 (Transfer With Authorization) and EIP-2612 (Permit) relay flows.
|
|
268
|
+
*/
|
|
269
|
+
export interface UseSignTypedDataReturn {
|
|
270
|
+
/**
|
|
271
|
+
* Signs EIP-712 typed data with the connected EVM wallet
|
|
272
|
+
* @param typedData - The EIP-712 typed data to sign
|
|
273
|
+
* @returns Promise that resolves to the 65-byte hex signature (0x-prefixed)
|
|
274
|
+
* @throws Error if no wallet is connected, the wallet is non-EVM, or signing fails
|
|
275
|
+
*/
|
|
276
|
+
signTypedData: (typedData: EIP712TypedData) => Promise<string>
|
|
277
|
+
/**
|
|
278
|
+
* Indicates if a typed-data signing operation is currently in progress
|
|
279
|
+
*/
|
|
280
|
+
isLoading: boolean
|
|
281
|
+
/**
|
|
282
|
+
* The raw hex signature from the last successful sign, undefined if not yet signed
|
|
283
|
+
*/
|
|
284
|
+
signature: string | undefined
|
|
285
|
+
/**
|
|
286
|
+
* Error from the last signing attempt, undefined if no error occurred
|
|
287
|
+
*/
|
|
288
|
+
error: WalletError | undefined
|
|
289
|
+
}
|
|
290
|
+
|
|
261
291
|
// useSignSolanaTransaction hook types
|
|
262
292
|
|
|
263
293
|
/**
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest'
|
|
2
|
+
import { withEIP712Domain } from './signature'
|
|
3
|
+
import type { EIP712TypedData } from './signature'
|
|
4
|
+
|
|
5
|
+
const baseTypes = {
|
|
6
|
+
TransferWithAuthorization: [
|
|
7
|
+
{ name: 'from', type: 'address' },
|
|
8
|
+
{ name: 'to', type: 'address' },
|
|
9
|
+
{ name: 'value', type: 'uint256' },
|
|
10
|
+
{ name: 'validAfter', type: 'uint256' },
|
|
11
|
+
{ name: 'validBefore', type: 'uint256' },
|
|
12
|
+
{ name: 'nonce', type: 'bytes32' }
|
|
13
|
+
]
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const baseMessage = {
|
|
17
|
+
from: '0xabc',
|
|
18
|
+
to: '0xdef',
|
|
19
|
+
value: '1000000',
|
|
20
|
+
validAfter: 0,
|
|
21
|
+
validBefore: 9999999999,
|
|
22
|
+
nonce: '0xdeadbeef'
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
describe('withEIP712Domain', () => {
|
|
26
|
+
it('injects EIP712Domain with all four standard fields when all are present in domain', () => {
|
|
27
|
+
const input: EIP712TypedData = {
|
|
28
|
+
domain: {
|
|
29
|
+
name: 'USD Coin',
|
|
30
|
+
version: '2',
|
|
31
|
+
chainId: 1,
|
|
32
|
+
verifyingContract: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48'
|
|
33
|
+
},
|
|
34
|
+
types: baseTypes,
|
|
35
|
+
primaryType: 'TransferWithAuthorization',
|
|
36
|
+
message: baseMessage
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const result = withEIP712Domain(input)
|
|
40
|
+
|
|
41
|
+
expect(result.types.EIP712Domain).toEqual([
|
|
42
|
+
{ name: 'name', type: 'string' },
|
|
43
|
+
{ name: 'version', type: 'string' },
|
|
44
|
+
{ name: 'chainId', type: 'uint256' },
|
|
45
|
+
{ name: 'verifyingContract', type: 'address' }
|
|
46
|
+
])
|
|
47
|
+
// Existing types are preserved
|
|
48
|
+
expect(result.types.TransferWithAuthorization).toEqual(
|
|
49
|
+
baseTypes.TransferWithAuthorization
|
|
50
|
+
)
|
|
51
|
+
// Other fields are unchanged
|
|
52
|
+
expect(result.domain).toBe(input.domain)
|
|
53
|
+
expect(result.primaryType).toBe(input.primaryType)
|
|
54
|
+
expect(result.message).toBe(input.message)
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
it('omits version from EIP712Domain when domain has no version (UNI-style)', () => {
|
|
58
|
+
const input: EIP712TypedData = {
|
|
59
|
+
domain: { name: 'Uniswap V2', chainId: 1, verifyingContract: '0x...' },
|
|
60
|
+
types: { Permit: [{ name: 'owner', type: 'address' }] },
|
|
61
|
+
primaryType: 'Permit',
|
|
62
|
+
message: {}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const result = withEIP712Domain(input)
|
|
66
|
+
|
|
67
|
+
expect(result.types.EIP712Domain).toEqual([
|
|
68
|
+
{ name: 'name', type: 'string' },
|
|
69
|
+
{ name: 'chainId', type: 'uint256' },
|
|
70
|
+
{ name: 'verifyingContract', type: 'address' }
|
|
71
|
+
])
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
it('includes salt when present in domain', () => {
|
|
75
|
+
const input: EIP712TypedData = {
|
|
76
|
+
domain: {
|
|
77
|
+
name: 'MyToken',
|
|
78
|
+
chainId: 137,
|
|
79
|
+
salt: '0xdeadbeef00000000000000000000000000000000000000000000000000000000'
|
|
80
|
+
},
|
|
81
|
+
types: baseTypes,
|
|
82
|
+
primaryType: 'TransferWithAuthorization',
|
|
83
|
+
message: baseMessage
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const result = withEIP712Domain(input)
|
|
87
|
+
|
|
88
|
+
expect(result.types.EIP712Domain).toEqual([
|
|
89
|
+
{ name: 'name', type: 'string' },
|
|
90
|
+
{ name: 'chainId', type: 'uint256' },
|
|
91
|
+
{ name: 'salt', type: 'bytes32' }
|
|
92
|
+
])
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
it('preserves canonical field order: name, version, chainId, verifyingContract, salt', () => {
|
|
96
|
+
const input: EIP712TypedData = {
|
|
97
|
+
domain: {
|
|
98
|
+
salt: '0x00000000000000000000000000000000000000000000000000000000000000ab',
|
|
99
|
+
verifyingContract: '0x123',
|
|
100
|
+
name: 'Token',
|
|
101
|
+
chainId: 1,
|
|
102
|
+
version: '1'
|
|
103
|
+
},
|
|
104
|
+
types: baseTypes,
|
|
105
|
+
primaryType: 'TransferWithAuthorization',
|
|
106
|
+
message: baseMessage
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const result = withEIP712Domain(input)
|
|
110
|
+
const names = result.types.EIP712Domain.map(f => f.name)
|
|
111
|
+
|
|
112
|
+
expect(names).toEqual([
|
|
113
|
+
'name',
|
|
114
|
+
'version',
|
|
115
|
+
'chainId',
|
|
116
|
+
'verifyingContract',
|
|
117
|
+
'salt'
|
|
118
|
+
])
|
|
119
|
+
})
|
|
120
|
+
|
|
121
|
+
it('does not modify input when EIP712Domain is already present', () => {
|
|
122
|
+
const existingEIP712Domain = [
|
|
123
|
+
{ name: 'name', type: 'string' },
|
|
124
|
+
{ name: 'chainId', type: 'uint256' }
|
|
125
|
+
]
|
|
126
|
+
const input: EIP712TypedData = {
|
|
127
|
+
domain: {
|
|
128
|
+
name: 'USD Coin',
|
|
129
|
+
version: '2',
|
|
130
|
+
chainId: 1,
|
|
131
|
+
verifyingContract: '0xabc'
|
|
132
|
+
},
|
|
133
|
+
types: { EIP712Domain: existingEIP712Domain, ...baseTypes },
|
|
134
|
+
primaryType: 'TransferWithAuthorization',
|
|
135
|
+
message: baseMessage
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const result = withEIP712Domain(input)
|
|
139
|
+
|
|
140
|
+
// Returns input unchanged — caller's EIP712Domain is authoritative
|
|
141
|
+
expect(result).toBe(input)
|
|
142
|
+
expect(result.types.EIP712Domain).toBe(existingEIP712Domain)
|
|
143
|
+
})
|
|
144
|
+
|
|
145
|
+
it('returns a new object (does not mutate input) when injecting EIP712Domain', () => {
|
|
146
|
+
const input: EIP712TypedData = {
|
|
147
|
+
domain: {
|
|
148
|
+
name: 'USD Coin',
|
|
149
|
+
version: '2',
|
|
150
|
+
chainId: 1,
|
|
151
|
+
verifyingContract: '0xabc'
|
|
152
|
+
},
|
|
153
|
+
types: { ...baseTypes },
|
|
154
|
+
primaryType: 'TransferWithAuthorization',
|
|
155
|
+
message: baseMessage
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const result = withEIP712Domain(input)
|
|
159
|
+
|
|
160
|
+
expect(result).not.toBe(input)
|
|
161
|
+
expect(result.types).not.toBe(input.types)
|
|
162
|
+
// Original is untouched
|
|
163
|
+
expect(input.types.EIP712Domain).toBeUndefined()
|
|
164
|
+
})
|
|
165
|
+
|
|
166
|
+
it('handles a domain with only chainId (minimal domain)', () => {
|
|
167
|
+
const input: EIP712TypedData = {
|
|
168
|
+
domain: { chainId: 8453 },
|
|
169
|
+
types: baseTypes,
|
|
170
|
+
primaryType: 'TransferWithAuthorization',
|
|
171
|
+
message: baseMessage
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const result = withEIP712Domain(input)
|
|
175
|
+
|
|
176
|
+
expect(result.types.EIP712Domain).toEqual([
|
|
177
|
+
{ name: 'chainId', type: 'uint256' }
|
|
178
|
+
])
|
|
179
|
+
})
|
|
180
|
+
|
|
181
|
+
it('places EIP712Domain before other types in the types object', () => {
|
|
182
|
+
const input: EIP712TypedData = {
|
|
183
|
+
domain: {
|
|
184
|
+
name: 'USD Coin',
|
|
185
|
+
version: '2',
|
|
186
|
+
chainId: 1,
|
|
187
|
+
verifyingContract: '0xabc'
|
|
188
|
+
},
|
|
189
|
+
types: baseTypes,
|
|
190
|
+
primaryType: 'TransferWithAuthorization',
|
|
191
|
+
message: baseMessage
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const keys = Object.keys(withEIP712Domain(input).types)
|
|
195
|
+
expect(keys[0]).toBe('EIP712Domain')
|
|
196
|
+
})
|
|
197
|
+
})
|
package/src/signature.ts
CHANGED
|
@@ -3,6 +3,65 @@ import type {
|
|
|
3
3
|
IntegratedBrowserInjectedProvider
|
|
4
4
|
} from './UWC-state'
|
|
5
5
|
|
|
6
|
+
/**
|
|
7
|
+
* EIP-712 typed structured data for eth_signTypedData_v4.
|
|
8
|
+
* Used by ERC-3009 (Transfer With Authorization), EIP-2612 (Permit), and similar standards.
|
|
9
|
+
*/
|
|
10
|
+
export interface EIP712TypedData {
|
|
11
|
+
domain: {
|
|
12
|
+
name?: string
|
|
13
|
+
version?: string
|
|
14
|
+
chainId?: number
|
|
15
|
+
verifyingContract?: string
|
|
16
|
+
salt?: string
|
|
17
|
+
}
|
|
18
|
+
types: Record<string, Array<{ name: string; type: string }>>
|
|
19
|
+
primaryType: string
|
|
20
|
+
message: Record<string, unknown>
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Ensures the EIP712Domain type entry is present in `types`, derived from the
|
|
25
|
+
* fields actually set on `domain`, in EIP-712's canonical order.
|
|
26
|
+
*
|
|
27
|
+
* Why: some wallets (notably Trust Wallet and several mobile wallets over
|
|
28
|
+
* WalletConnect) parse the `types` object strictly and reject an
|
|
29
|
+
* eth_signTypedData_v4 request that omits EIP712Domain. Desktop MetaMask derives
|
|
30
|
+
* it implicitly, so callers tend to leave it out — this normalizes both.
|
|
31
|
+
*
|
|
32
|
+
* If the caller already supplied EIP712Domain, theirs is authoritative and the
|
|
33
|
+
* input is returned untouched. Otherwise a new object is returned (input is not
|
|
34
|
+
* mutated) with EIP712Domain inserted first.
|
|
35
|
+
*
|
|
36
|
+
* @see https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator
|
|
37
|
+
*/
|
|
38
|
+
export function withEIP712Domain(typedData: EIP712TypedData): EIP712TypedData {
|
|
39
|
+
if (Object.hasOwn(typedData.types, 'EIP712Domain')) return typedData
|
|
40
|
+
|
|
41
|
+
const { domain } = typedData
|
|
42
|
+
const domainFields: Array<{ name: string; type: string }> = []
|
|
43
|
+
|
|
44
|
+
// Canonical field order — the on-chain domainSeparator hash depends on it.
|
|
45
|
+
if (domain.name !== undefined)
|
|
46
|
+
domainFields.push({ name: 'name', type: 'string' })
|
|
47
|
+
if (domain.version !== undefined)
|
|
48
|
+
domainFields.push({ name: 'version', type: 'string' })
|
|
49
|
+
if (domain.chainId !== undefined)
|
|
50
|
+
domainFields.push({ name: 'chainId', type: 'uint256' })
|
|
51
|
+
if (domain.verifyingContract !== undefined)
|
|
52
|
+
domainFields.push({ name: 'verifyingContract', type: 'address' })
|
|
53
|
+
if (domain.salt !== undefined)
|
|
54
|
+
domainFields.push({ name: 'salt', type: 'bytes32' })
|
|
55
|
+
|
|
56
|
+
return {
|
|
57
|
+
...typedData,
|
|
58
|
+
types: {
|
|
59
|
+
EIP712Domain: domainFields,
|
|
60
|
+
...typedData.types
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
6
65
|
/**
|
|
7
66
|
* Standard signature format for most blockchains (EVM, Solana, etc.)
|
|
8
67
|
*/
|