@meshconnect/uwc-wallet-connect-connector 0.5.0 → 0.6.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/services/signature-service.d.ts +8 -1
- package/dist/services/signature-service.d.ts.map +1 -1
- package/dist/services/signature-service.js +44 -0
- package/dist/services/signature-service.js.map +1 -1
- package/dist/wallet-connect-connector.d.ts +2 -1
- package/dist/wallet-connect-connector.d.ts.map +1 -1
- package/dist/wallet-connect-connector.js +3 -0
- package/dist/wallet-connect-connector.js.map +1 -1
- package/package.json +2 -2
- package/src/services/signature-service.test.ts +194 -0
- package/src/services/signature-service.ts +52 -1
- package/src/wallet-connect-connector.ts +6 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { WalletConnectClient } from './walletconnect-client';
|
|
2
2
|
import { ConnectionService } from './connection-service';
|
|
3
|
-
import type { SignatureType } from '@meshconnect/uwc-types';
|
|
3
|
+
import type { SignatureType, EIP712TypedData } from '@meshconnect/uwc-types';
|
|
4
4
|
/**
|
|
5
5
|
* Service for handling message signing in WalletConnect
|
|
6
6
|
*/
|
|
@@ -12,5 +12,12 @@ export declare class SignatureService {
|
|
|
12
12
|
* Sign a message with the connected wallet
|
|
13
13
|
*/
|
|
14
14
|
signMessage(message: string): Promise<SignatureType>;
|
|
15
|
+
/**
|
|
16
|
+
* Sign EIP-712 typed structured data (eth_signTypedData_v4) over WalletConnect.
|
|
17
|
+
* EVM-only (eip155); used by ERC-3009 and EIP-2612 relay flows. The WC session
|
|
18
|
+
* already negotiates `eth_signTypedData_v4` in its namespace methods
|
|
19
|
+
* (connection-service.ts), so no session renegotiation is needed.
|
|
20
|
+
*/
|
|
21
|
+
signTypedData(typedData: EIP712TypedData): Promise<string>;
|
|
15
22
|
}
|
|
16
23
|
//# sourceMappingURL=signature-service.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"signature-service.d.ts","sourceRoot":"","sources":["../../src/services/signature-service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAA;AAC5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAA;AAKxD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAA;
|
|
1
|
+
{"version":3,"file":"signature-service.d.ts","sourceRoot":"","sources":["../../src/services/signature-service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAA;AAC5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAA;AAKxD,OAAO,KAAK,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAA;AAG5E;;GAEG;AACH,qBAAa,gBAAgB;IAEzB,OAAO,CAAC,mBAAmB;IAC3B,OAAO,CAAC,iBAAiB;gBADjB,mBAAmB,EAAE,mBAAmB,EACxC,iBAAiB,EAAE,iBAAiB;IAG9C;;OAEG;IACG,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAyI1D;;;;;OAKG;IACG,aAAa,CAAC,SAAS,EAAE,eAAe,GAAG,OAAO,CAAC,MAAM,CAAC;CA2CjE"}
|
|
@@ -4,6 +4,7 @@ import { findAccountInNamespaces, parseAccount } from '../utils/account-utils';
|
|
|
4
4
|
import { base58Encode } from '../utils/encoding-utils';
|
|
5
5
|
import { parseError } from '../utils/error-utils';
|
|
6
6
|
import { triggerSmartContract, stringToHex } from '../utils/tron-utils';
|
|
7
|
+
import { withEIP712Domain } from '@meshconnect/uwc-types';
|
|
7
8
|
/**
|
|
8
9
|
* Service for handling message signing in WalletConnect
|
|
9
10
|
*/
|
|
@@ -122,5 +123,48 @@ export class SignatureService {
|
|
|
122
123
|
throw parseError(error);
|
|
123
124
|
}
|
|
124
125
|
}
|
|
126
|
+
/**
|
|
127
|
+
* Sign EIP-712 typed structured data (eth_signTypedData_v4) over WalletConnect.
|
|
128
|
+
* EVM-only (eip155); used by ERC-3009 and EIP-2612 relay flows. The WC session
|
|
129
|
+
* already negotiates `eth_signTypedData_v4` in its namespace methods
|
|
130
|
+
* (connection-service.ts), so no session renegotiation is needed.
|
|
131
|
+
*/
|
|
132
|
+
async signTypedData(typedData) {
|
|
133
|
+
try {
|
|
134
|
+
const session = this.connectionService.getSession();
|
|
135
|
+
if (!session) {
|
|
136
|
+
throw new Error('No active session. Please connect first.');
|
|
137
|
+
}
|
|
138
|
+
const activeNetwork = this.connectionService.getActiveNetwork();
|
|
139
|
+
const activeAddress = this.connectionService.getActiveAddress();
|
|
140
|
+
if (!activeNetwork) {
|
|
141
|
+
throw new Error('No active network. Please connect first.');
|
|
142
|
+
}
|
|
143
|
+
if (!activeAddress) {
|
|
144
|
+
throw new Error('No active address. Please connect first.');
|
|
145
|
+
}
|
|
146
|
+
const namespace = activeNetwork.id.split(':')[0];
|
|
147
|
+
if (namespace !== 'eip155') {
|
|
148
|
+
throw new Error(`signTypedData is only supported for EVM wallets, got: ${namespace}`);
|
|
149
|
+
}
|
|
150
|
+
const client = await this.walletConnectClient.getClient();
|
|
151
|
+
const chainId = activeNetwork.id.split(':')[1];
|
|
152
|
+
// Inject EIP712Domain into the types before signing — mobile wallets
|
|
153
|
+
// (Trust Wallet, OKX mobile, etc.) require it explicitly in the payload.
|
|
154
|
+
const wireData = withEIP712Domain(typedData);
|
|
155
|
+
const result = await client.request({
|
|
156
|
+
topic: session.topic,
|
|
157
|
+
chainId: `eip155:${chainId}`,
|
|
158
|
+
request: {
|
|
159
|
+
method: 'eth_signTypedData_v4',
|
|
160
|
+
params: [activeAddress, JSON.stringify(wireData)]
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
return result;
|
|
164
|
+
}
|
|
165
|
+
catch (error) {
|
|
166
|
+
throw parseError(error);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
125
169
|
}
|
|
126
170
|
//# sourceMappingURL=signature-service.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"signature-service.js","sourceRoot":"","sources":["../../src/services/signature-service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAA;AAC5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAA;AACxD,OAAO,EAAE,uBAAuB,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAA;AAC9E,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAA;AACtD,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAA;AACjD,OAAO,EAAE,oBAAoB,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;
|
|
1
|
+
{"version":3,"file":"signature-service.js","sourceRoot":"","sources":["../../src/services/signature-service.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Network, Connector, ConnectorResult, SwitchNetworkResult, WalletConnectConfig, WalletConnectProvider, TransactionRequest, TransactionResult, NetworkRpcMap, SignatureType } from '@meshconnect/uwc-types';
|
|
1
|
+
import type { Network, Connector, ConnectorResult, SwitchNetworkResult, WalletConnectConfig, WalletConnectProvider, TransactionRequest, TransactionResult, NetworkRpcMap, SignatureType, EIP712TypedData } from '@meshconnect/uwc-types';
|
|
2
2
|
export declare class WalletConnectConnector implements Connector {
|
|
3
3
|
private walletConnectClient;
|
|
4
4
|
private connectionService;
|
|
@@ -12,6 +12,7 @@ export declare class WalletConnectConnector implements Connector {
|
|
|
12
12
|
disconnect(): Promise<void>;
|
|
13
13
|
switchNetwork(network: Network): Promise<SwitchNetworkResult>;
|
|
14
14
|
signMessage(message: string): Promise<SignatureType>;
|
|
15
|
+
signTypedData(typedData: EIP712TypedData): Promise<string>;
|
|
15
16
|
sendTransaction(request: TransactionRequest): Promise<TransactionResult>;
|
|
16
17
|
/**
|
|
17
18
|
* Sign a Solana transaction over WalletConnect without broadcasting.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wallet-connect-connector.d.ts","sourceRoot":"","sources":["../src/wallet-connect-connector.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,OAAO,EACP,SAAS,EACT,eAAe,EACf,mBAAmB,EACnB,mBAAmB,EACnB,qBAAqB,EACrB,kBAAkB,EAClB,iBAAiB,EACjB,aAAa,EACb,aAAa,
|
|
1
|
+
{"version":3,"file":"wallet-connect-connector.d.ts","sourceRoot":"","sources":["../src/wallet-connect-connector.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,OAAO,EACP,SAAS,EACT,eAAe,EACf,mBAAmB,EACnB,mBAAmB,EACnB,qBAAqB,EACrB,kBAAkB,EAClB,iBAAiB,EACjB,aAAa,EACb,aAAa,EACb,eAAe,EAChB,MAAM,wBAAwB,CAAA;AAO/B,qBAAa,sBAAuB,YAAW,SAAS;IACtD,OAAO,CAAC,mBAAmB,CAAqB;IAChD,OAAO,CAAC,iBAAiB,CAAmB;IAC5C,OAAO,CAAC,oBAAoB,CAAsB;IAClD,OAAO,CAAC,gBAAgB,CAAkB;IAC1C,OAAO,CAAC,kBAAkB,CAAoB;IAC9C,OAAO,CAAC,aAAa,CAAe;gBAExB,MAAM,EAAE,mBAAmB,EAAE,aAAa,GAAE,aAAkB;IAmBpE,OAAO,CACX,OAAO,EAAE,OAAO,EAChB,QAAQ,CAAC,EAAE,qBAAqB,GAC/B,OAAO,CAAC,eAAe,CAAC;IAU3B,gBAAgB,IAAI,MAAM;IAQpB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAI3B,aAAa,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAI7D,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAIpD,aAAa,CAAC,SAAS,EAAE,eAAe,GAAG,OAAO,CAAC,MAAM,CAAC;IAI1D,eAAe,CACnB,OAAO,EAAE,kBAAkB,GAC1B,OAAO,CAAC,iBAAiB,CAAC;IAI7B;;;;;;OAMG;IACG,0BAA0B,CAC9B,YAAY,EAAE,UAAU,GACvB,OAAO,CAAC,UAAU,CAAC;CAGvB"}
|
|
@@ -40,6 +40,9 @@ export class WalletConnectConnector {
|
|
|
40
40
|
async signMessage(message) {
|
|
41
41
|
return this.signatureService.signMessage(message);
|
|
42
42
|
}
|
|
43
|
+
async signTypedData(typedData) {
|
|
44
|
+
return this.signatureService.signTypedData(typedData);
|
|
45
|
+
}
|
|
43
46
|
async sendTransaction(request) {
|
|
44
47
|
return this.transactionService.sendTransaction(request);
|
|
45
48
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wallet-connect-connector.js","sourceRoot":"","sources":["../src/wallet-connect-connector.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"wallet-connect-connector.js","sourceRoot":"","sources":["../src/wallet-connect-connector.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAA;AACrE,OAAO,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAA;AACjE,OAAO,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAA;AACxE,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAA;AAC/D,OAAO,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAA;AAEnE,MAAM,OAAO,sBAAsB;IACzB,mBAAmB,CAAqB;IACxC,iBAAiB,CAAmB;IACpC,oBAAoB,CAAsB;IAC1C,gBAAgB,CAAkB;IAClC,kBAAkB,CAAoB;IACtC,aAAa,CAAe;IAEpC,YAAY,MAA2B,EAAE,gBAA+B,EAAE;QACxE,IAAI,CAAC,mBAAmB,GAAG,IAAI,mBAAmB,CAAC,MAAM,CAAC,CAAA;QAC1D,IAAI,CAAC,aAAa,GAAG,aAAa,CAAA;QAClC,IAAI,CAAC,iBAAiB,GAAG,IAAI,iBAAiB,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAA;QACxE,IAAI,CAAC,oBAAoB,GAAG,IAAI,oBAAoB,CAClD,IAAI,CAAC,mBAAmB,EACxB,IAAI,CAAC,iBAAiB,CACvB,CAAA;QACD,IAAI,CAAC,gBAAgB,GAAG,IAAI,gBAAgB,CAC1C,IAAI,CAAC,mBAAmB,EACxB,IAAI,CAAC,iBAAiB,CACvB,CAAA;QACD,IAAI,CAAC,kBAAkB,GAAG,IAAI,kBAAkB,CAC9C,IAAI,CAAC,mBAAmB,EACxB,IAAI,CAAC,iBAAiB,EACtB,IAAI,CAAC,aAAa,CACnB,CAAA;IACH,CAAC;IAED,KAAK,CAAC,OAAO,CACX,OAAgB,EAChB,QAAgC;QAEhC,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,MAAM,IAAI,KAAK,CACb,gEAAgE,CACjE,CAAA;QACH,CAAC;QAED,OAAO,IAAI,CAAC,iBAAiB,CAAC,OAAO,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAA;IAC1D,CAAC;IAED,gBAAgB;QACd,MAAM,GAAG,GAAG,IAAI,CAAC,iBAAiB,CAAC,gBAAgB,EAAE,CAAA;QACrD,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC,CAAA;QACvE,CAAC;QACD,OAAO,GAAG,CAAA;IACZ,CAAC;IAED,KAAK,CAAC,UAAU;QACd,OAAO,IAAI,CAAC,iBAAiB,CAAC,UAAU,EAAE,CAAA;IAC5C,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,OAAgB;QAClC,OAAO,IAAI,CAAC,oBAAoB,CAAC,aAAa,CAAC,OAAO,CAAC,CAAA;IACzD,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,OAAe;QAC/B,OAAO,IAAI,CAAC,gBAAgB,CAAC,WAAW,CAAC,OAAO,CAAC,CAAA;IACnD,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,SAA0B;QAC5C,OAAO,IAAI,CAAC,gBAAgB,CAAC,aAAa,CAAC,SAAS,CAAC,CAAA;IACvD,CAAC;IAED,KAAK,CAAC,eAAe,CACnB,OAA2B;QAE3B,OAAO,IAAI,CAAC,kBAAkB,CAAC,eAAe,CAAC,OAAO,CAAC,CAAA;IACzD,CAAC;IAED;;;;;;OAMG;IACH,KAAK,CAAC,0BAA0B,CAC9B,YAAwB;QAExB,OAAO,IAAI,CAAC,kBAAkB,CAAC,0BAA0B,CAAC,YAAY,CAAC,CAAA;IACzE,CAAC;CACF"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@meshconnect/uwc-wallet-connect-connector",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "WalletConnect connector for Universal Wallet Connector",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"bs58": "6.0.0",
|
|
25
25
|
"buffer": "^6.0.3",
|
|
26
26
|
"viem": "^2.44.4",
|
|
27
|
-
"@meshconnect/uwc-types": "0.
|
|
27
|
+
"@meshconnect/uwc-types": "0.15.0"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
30
|
"typescript": "^5.9.3"
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
|
2
|
+
import { SignatureService } from './signature-service'
|
|
3
|
+
import type { WalletConnectClient } from './walletconnect-client'
|
|
4
|
+
import type { ConnectionService } from './connection-service'
|
|
5
|
+
import type { Network } from '@meshconnect/uwc-types'
|
|
6
|
+
|
|
7
|
+
// Partial Network mocks — the signing path only reads `network.id`, so the
|
|
8
|
+
// other required Network fields are intentionally omitted via a cast.
|
|
9
|
+
const EVM_NETWORK = {
|
|
10
|
+
id: 'eip155:1',
|
|
11
|
+
name: 'Ethereum Mainnet'
|
|
12
|
+
} as unknown as Network
|
|
13
|
+
const SOLANA_NETWORK = {
|
|
14
|
+
id: 'solana:mainnet',
|
|
15
|
+
name: 'Solana'
|
|
16
|
+
} as unknown as Network
|
|
17
|
+
|
|
18
|
+
const ACTIVE_ADDRESS = '0xUserAddress'
|
|
19
|
+
const MOCK_TOPIC = 'mock-session-topic'
|
|
20
|
+
|
|
21
|
+
function makeMockConnectionService(overrides?: {
|
|
22
|
+
session?: object | null
|
|
23
|
+
network?: Network | null
|
|
24
|
+
address?: string | null
|
|
25
|
+
}): ConnectionService {
|
|
26
|
+
return {
|
|
27
|
+
getSession: vi
|
|
28
|
+
.fn()
|
|
29
|
+
.mockReturnValue(
|
|
30
|
+
overrides?.session !== undefined
|
|
31
|
+
? overrides.session
|
|
32
|
+
: { topic: MOCK_TOPIC, namespaces: {} }
|
|
33
|
+
),
|
|
34
|
+
getActiveNetwork: vi
|
|
35
|
+
.fn()
|
|
36
|
+
.mockReturnValue(
|
|
37
|
+
overrides?.network !== undefined ? overrides.network : EVM_NETWORK
|
|
38
|
+
),
|
|
39
|
+
getActiveAddress: vi
|
|
40
|
+
.fn()
|
|
41
|
+
.mockReturnValue(
|
|
42
|
+
overrides?.address !== undefined ? overrides.address : ACTIVE_ADDRESS
|
|
43
|
+
)
|
|
44
|
+
} as unknown as ConnectionService
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const USDC_TYPED_DATA = {
|
|
48
|
+
domain: {
|
|
49
|
+
name: 'USD Coin',
|
|
50
|
+
version: '2',
|
|
51
|
+
chainId: 1,
|
|
52
|
+
verifyingContract: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48'
|
|
53
|
+
},
|
|
54
|
+
types: {
|
|
55
|
+
TransferWithAuthorization: [
|
|
56
|
+
{ name: 'from', type: 'address' },
|
|
57
|
+
{ name: 'to', type: 'address' },
|
|
58
|
+
{ name: 'value', type: 'uint256' },
|
|
59
|
+
{ name: 'validAfter', type: 'uint256' },
|
|
60
|
+
{ name: 'validBefore', type: 'uint256' },
|
|
61
|
+
{ name: 'nonce', type: 'bytes32' }
|
|
62
|
+
]
|
|
63
|
+
},
|
|
64
|
+
primaryType: 'TransferWithAuthorization',
|
|
65
|
+
message: {
|
|
66
|
+
from: '0xabc',
|
|
67
|
+
to: '0xdef',
|
|
68
|
+
value: '1000000',
|
|
69
|
+
validAfter: 0,
|
|
70
|
+
validBefore: 9999999999,
|
|
71
|
+
nonce: '0xdeadbeef'
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
describe('SignatureService (wallet-connect-connector) — signTypedData', () => {
|
|
76
|
+
let mockWCClient: WalletConnectClient
|
|
77
|
+
let mockConnectionService: ConnectionService
|
|
78
|
+
let service: SignatureService
|
|
79
|
+
let mockSignClient: { request: ReturnType<typeof vi.fn> }
|
|
80
|
+
|
|
81
|
+
beforeEach(() => {
|
|
82
|
+
mockSignClient = { request: vi.fn().mockResolvedValue('0xwcsig') }
|
|
83
|
+
mockWCClient = {
|
|
84
|
+
getClient: vi.fn().mockResolvedValue(mockSignClient)
|
|
85
|
+
} as unknown as WalletConnectClient
|
|
86
|
+
mockConnectionService = makeMockConnectionService()
|
|
87
|
+
service = new SignatureService(mockWCClient, mockConnectionService)
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
it('sends eth_signTypedData_v4 via WalletConnect', async () => {
|
|
91
|
+
await service.signTypedData(USDC_TYPED_DATA)
|
|
92
|
+
|
|
93
|
+
expect(mockSignClient.request).toHaveBeenCalledWith({
|
|
94
|
+
topic: MOCK_TOPIC,
|
|
95
|
+
chainId: 'eip155:1',
|
|
96
|
+
request: {
|
|
97
|
+
method: 'eth_signTypedData_v4',
|
|
98
|
+
params: [ACTIVE_ADDRESS, expect.any(String)]
|
|
99
|
+
}
|
|
100
|
+
})
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
it('injects EIP712Domain into wire payload for mobile wallet compat', async () => {
|
|
104
|
+
await service.signTypedData(USDC_TYPED_DATA)
|
|
105
|
+
|
|
106
|
+
const [, jsonArg] = mockSignClient.request.mock.calls[0][0].request.params
|
|
107
|
+
const sent = JSON.parse(jsonArg)
|
|
108
|
+
|
|
109
|
+
expect(sent.types.EIP712Domain).toEqual([
|
|
110
|
+
{ name: 'name', type: 'string' },
|
|
111
|
+
{ name: 'version', type: 'string' },
|
|
112
|
+
{ name: 'chainId', type: 'uint256' },
|
|
113
|
+
{ name: 'verifyingContract', type: 'address' }
|
|
114
|
+
])
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
it('does not duplicate EIP712Domain when caller already includes it', async () => {
|
|
118
|
+
const dataWithDomain = {
|
|
119
|
+
...USDC_TYPED_DATA,
|
|
120
|
+
types: {
|
|
121
|
+
EIP712Domain: [
|
|
122
|
+
{ name: 'name', type: 'string' },
|
|
123
|
+
{ name: 'chainId', type: 'uint256' }
|
|
124
|
+
],
|
|
125
|
+
...USDC_TYPED_DATA.types
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
await service.signTypedData(dataWithDomain)
|
|
130
|
+
|
|
131
|
+
const [, jsonArg] = mockSignClient.request.mock.calls[0][0].request.params
|
|
132
|
+
const sent = JSON.parse(jsonArg)
|
|
133
|
+
|
|
134
|
+
expect(sent.types.EIP712Domain).toEqual([
|
|
135
|
+
{ name: 'name', type: 'string' },
|
|
136
|
+
{ name: 'chainId', type: 'uint256' }
|
|
137
|
+
])
|
|
138
|
+
})
|
|
139
|
+
|
|
140
|
+
it('omits version from EIP712Domain when domain has no version (UNI-style)', async () => {
|
|
141
|
+
const uniData = {
|
|
142
|
+
...USDC_TYPED_DATA,
|
|
143
|
+
domain: { name: 'Uniswap V2', chainId: 1, verifyingContract: '0x...' }
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
await service.signTypedData(uniData)
|
|
147
|
+
|
|
148
|
+
const [, jsonArg] = mockSignClient.request.mock.calls[0][0].request.params
|
|
149
|
+
const sent = JSON.parse(jsonArg)
|
|
150
|
+
|
|
151
|
+
expect(sent.types.EIP712Domain).toEqual([
|
|
152
|
+
{ name: 'name', type: 'string' },
|
|
153
|
+
{ name: 'chainId', type: 'uint256' },
|
|
154
|
+
{ name: 'verifyingContract', type: 'address' }
|
|
155
|
+
])
|
|
156
|
+
})
|
|
157
|
+
|
|
158
|
+
it('does not mutate the original typedData object', async () => {
|
|
159
|
+
const original = JSON.parse(JSON.stringify(USDC_TYPED_DATA))
|
|
160
|
+
|
|
161
|
+
await service.signTypedData(USDC_TYPED_DATA)
|
|
162
|
+
|
|
163
|
+
expect(USDC_TYPED_DATA.types).toEqual(original.types)
|
|
164
|
+
expect(
|
|
165
|
+
(USDC_TYPED_DATA.types as Record<string, unknown>).EIP712Domain
|
|
166
|
+
).toBeUndefined()
|
|
167
|
+
})
|
|
168
|
+
|
|
169
|
+
it('returns the signature from WalletConnect', async () => {
|
|
170
|
+
mockSignClient.request.mockResolvedValue('0xexpectedsig')
|
|
171
|
+
const result = await service.signTypedData(USDC_TYPED_DATA)
|
|
172
|
+
expect(result).toBe('0xexpectedsig')
|
|
173
|
+
})
|
|
174
|
+
|
|
175
|
+
it('throws when there is no active session', async () => {
|
|
176
|
+
service = new SignatureService(
|
|
177
|
+
mockWCClient,
|
|
178
|
+
makeMockConnectionService({ session: null })
|
|
179
|
+
)
|
|
180
|
+
await expect(service.signTypedData(USDC_TYPED_DATA)).rejects.toThrow(
|
|
181
|
+
'No active session'
|
|
182
|
+
)
|
|
183
|
+
})
|
|
184
|
+
|
|
185
|
+
it('throws when the active network is not eip155', async () => {
|
|
186
|
+
service = new SignatureService(
|
|
187
|
+
mockWCClient,
|
|
188
|
+
makeMockConnectionService({ network: SOLANA_NETWORK })
|
|
189
|
+
)
|
|
190
|
+
await expect(service.signTypedData(USDC_TYPED_DATA)).rejects.toThrow(
|
|
191
|
+
'signTypedData is only supported for EVM wallets'
|
|
192
|
+
)
|
|
193
|
+
})
|
|
194
|
+
})
|
|
@@ -4,7 +4,8 @@ import { findAccountInNamespaces, parseAccount } from '../utils/account-utils'
|
|
|
4
4
|
import { base58Encode } from '../utils/encoding-utils'
|
|
5
5
|
import { parseError } from '../utils/error-utils'
|
|
6
6
|
import { triggerSmartContract, stringToHex } from '../utils/tron-utils'
|
|
7
|
-
import type { SignatureType } from '@meshconnect/uwc-types'
|
|
7
|
+
import type { SignatureType, EIP712TypedData } from '@meshconnect/uwc-types'
|
|
8
|
+
import { withEIP712Domain } from '@meshconnect/uwc-types'
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* Service for handling message signing in WalletConnect
|
|
@@ -154,4 +155,54 @@ export class SignatureService {
|
|
|
154
155
|
throw parseError(error)
|
|
155
156
|
}
|
|
156
157
|
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Sign EIP-712 typed structured data (eth_signTypedData_v4) over WalletConnect.
|
|
161
|
+
* EVM-only (eip155); used by ERC-3009 and EIP-2612 relay flows. The WC session
|
|
162
|
+
* already negotiates `eth_signTypedData_v4` in its namespace methods
|
|
163
|
+
* (connection-service.ts), so no session renegotiation is needed.
|
|
164
|
+
*/
|
|
165
|
+
async signTypedData(typedData: EIP712TypedData): Promise<string> {
|
|
166
|
+
try {
|
|
167
|
+
const session = this.connectionService.getSession()
|
|
168
|
+
if (!session) {
|
|
169
|
+
throw new Error('No active session. Please connect first.')
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
const activeNetwork = this.connectionService.getActiveNetwork()
|
|
173
|
+
const activeAddress = this.connectionService.getActiveAddress()
|
|
174
|
+
if (!activeNetwork) {
|
|
175
|
+
throw new Error('No active network. Please connect first.')
|
|
176
|
+
}
|
|
177
|
+
if (!activeAddress) {
|
|
178
|
+
throw new Error('No active address. Please connect first.')
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const namespace = activeNetwork.id.split(':')[0]
|
|
182
|
+
if (namespace !== 'eip155') {
|
|
183
|
+
throw new Error(
|
|
184
|
+
`signTypedData is only supported for EVM wallets, got: ${namespace}`
|
|
185
|
+
)
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const client = await this.walletConnectClient.getClient()
|
|
189
|
+
const chainId = activeNetwork.id.split(':')[1]
|
|
190
|
+
|
|
191
|
+
// Inject EIP712Domain into the types before signing — mobile wallets
|
|
192
|
+
// (Trust Wallet, OKX mobile, etc.) require it explicitly in the payload.
|
|
193
|
+
const wireData = withEIP712Domain(typedData)
|
|
194
|
+
const result = await client.request({
|
|
195
|
+
topic: session.topic,
|
|
196
|
+
chainId: `eip155:${chainId}`,
|
|
197
|
+
request: {
|
|
198
|
+
method: 'eth_signTypedData_v4',
|
|
199
|
+
params: [activeAddress, JSON.stringify(wireData)]
|
|
200
|
+
}
|
|
201
|
+
})
|
|
202
|
+
|
|
203
|
+
return result as string
|
|
204
|
+
} catch (error) {
|
|
205
|
+
throw parseError(error)
|
|
206
|
+
}
|
|
207
|
+
}
|
|
157
208
|
}
|
|
@@ -8,7 +8,8 @@ import type {
|
|
|
8
8
|
TransactionRequest,
|
|
9
9
|
TransactionResult,
|
|
10
10
|
NetworkRpcMap,
|
|
11
|
-
SignatureType
|
|
11
|
+
SignatureType,
|
|
12
|
+
EIP712TypedData
|
|
12
13
|
} from '@meshconnect/uwc-types'
|
|
13
14
|
import { WalletConnectClient } from './services/walletconnect-client'
|
|
14
15
|
import { ConnectionService } from './services/connection-service'
|
|
@@ -76,6 +77,10 @@ export class WalletConnectConnector implements Connector {
|
|
|
76
77
|
return this.signatureService.signMessage(message)
|
|
77
78
|
}
|
|
78
79
|
|
|
80
|
+
async signTypedData(typedData: EIP712TypedData): Promise<string> {
|
|
81
|
+
return this.signatureService.signTypedData(typedData)
|
|
82
|
+
}
|
|
83
|
+
|
|
79
84
|
async sendTransaction(
|
|
80
85
|
request: TransactionRequest
|
|
81
86
|
): Promise<TransactionResult> {
|