@meshconnect/uwc-injected-connector 0.3.2 → 0.4.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/ethereum/ethereum-transaction-builder.d.ts +2 -1
- package/dist/services/ethereum/ethereum-transaction-builder.d.ts.map +1 -1
- package/dist/services/ethereum/ethereum-transaction-builder.js +14 -0
- package/dist/services/ethereum/ethereum-transaction-builder.js.map +1 -1
- package/dist/services/ethereum/ethereum-transaction-service.d.ts +4 -0
- package/dist/services/ethereum/ethereum-transaction-service.d.ts.map +1 -1
- package/dist/services/ethereum/ethereum-transaction-service.js +24 -0
- package/dist/services/ethereum/ethereum-transaction-service.js.map +1 -1
- package/package.json +3 -3
- package/src/services/ethereum/ethereum-transaction-builder.test.ts +252 -0
- package/src/services/ethereum/ethereum-transaction-builder.ts +19 -1
- package/src/services/ethereum/ethereum-transaction-service.test.ts +303 -0
- package/src/services/ethereum/ethereum-transaction-service.ts +34 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { EVMNativeTransferRequest, EVMContractCallRequest } from '@meshconnect/uwc-types';
|
|
1
|
+
import type { EVMNativeTransferRequest, EVMContractCallRequest, EVMDataTransferRequest } from '@meshconnect/uwc-types';
|
|
2
2
|
import type { TransactionRequest } from 'ethers';
|
|
3
3
|
/**
|
|
4
4
|
* Service for handling Ethereum/EVM transaction operations
|
|
@@ -6,6 +6,7 @@ import type { TransactionRequest } from 'ethers';
|
|
|
6
6
|
export declare class EthereumTransactionBuilder {
|
|
7
7
|
getContractTransaction(request: EVMContractCallRequest): Promise<TransactionRequest>;
|
|
8
8
|
getNativeTransaction(request: EVMNativeTransferRequest): Promise<TransactionRequest>;
|
|
9
|
+
getDataTransaction(request: EVMDataTransferRequest): Promise<TransactionRequest>;
|
|
9
10
|
/**
|
|
10
11
|
* Helper to format gas configuration for ethers
|
|
11
12
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ethereum-transaction-builder.d.ts","sourceRoot":"","sources":["../../../src/services/ethereum/ethereum-transaction-builder.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAEV,wBAAwB,EACxB,sBAAsB,EACvB,MAAM,wBAAwB,CAAA;AAE/B,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,QAAQ,CAAA;AAEhD;;GAEG;AACH,qBAAa,0BAA0B;IAC/B,sBAAsB,CAC1B,OAAO,EAAE,sBAAsB,GAC9B,OAAO,CAAC,kBAAkB,CAAC;IAgCxB,oBAAoB,CACxB,OAAO,EAAE,wBAAwB,GAChC,OAAO,CAAC,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"ethereum-transaction-builder.d.ts","sourceRoot":"","sources":["../../../src/services/ethereum/ethereum-transaction-builder.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAEV,wBAAwB,EACxB,sBAAsB,EACtB,sBAAsB,EACvB,MAAM,wBAAwB,CAAA;AAE/B,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,QAAQ,CAAA;AAEhD;;GAEG;AACH,qBAAa,0BAA0B;IAC/B,sBAAsB,CAC1B,OAAO,EAAE,sBAAsB,GAC9B,OAAO,CAAC,kBAAkB,CAAC;IAgCxB,oBAAoB,CACxB,OAAO,EAAE,wBAAwB,GAChC,OAAO,CAAC,kBAAkB,CAAC;IAYxB,kBAAkB,CACtB,OAAO,EAAE,sBAAsB,GAC9B,OAAO,CAAC,kBAAkB,CAAC;IAe9B;;OAEG;IACH,OAAO,CAAC,eAAe;CAiBxB"}
|
|
@@ -40,6 +40,20 @@ export class EthereumTransactionBuilder {
|
|
|
40
40
|
parseError(error);
|
|
41
41
|
}
|
|
42
42
|
}
|
|
43
|
+
async getDataTransaction(request) {
|
|
44
|
+
try {
|
|
45
|
+
const txRequest = {
|
|
46
|
+
to: request.to,
|
|
47
|
+
data: request.data,
|
|
48
|
+
chainId: BigInt(request.chainId),
|
|
49
|
+
...this.formatGasConfig(request.gasConfig)
|
|
50
|
+
};
|
|
51
|
+
return txRequest;
|
|
52
|
+
}
|
|
53
|
+
catch (error) {
|
|
54
|
+
parseError(error);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
43
57
|
/**
|
|
44
58
|
* Helper to format gas configuration for ethers
|
|
45
59
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ethereum-transaction-builder.js","sourceRoot":"","sources":["../../../src/services/ethereum/ethereum-transaction-builder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;
|
|
1
|
+
{"version":3,"file":"ethereum-transaction-builder.js","sourceRoot":"","sources":["../../../src/services/ethereum/ethereum-transaction-builder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAO/B,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAA;AAGpD;;GAEG;AACH,MAAM,OAAO,0BAA0B;IACrC,KAAK,CAAC,sBAAsB,CAC1B,OAA+B;QAE/B,IAAI,CAAC;YACH,4BAA4B;YAC5B,MAAM,SAAS,GAAqB;gBAClC,GAAG,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,SAAS,CAAC;aAC3C,CAAA;YAED,kCAAkC;YAClC,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;gBAClB,SAAS,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,CAAA;YACjC,CAAC;YAED,MAAM,KAAK,GAAG,IAAI,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;YAE/C,MAAM,IAAI,GAAG,KAAK,CAAC,kBAAkB,CACnC,OAAO,CAAC,YAAY,EACpB,OAAO,CAAC,IAAI,IAAI,EAAE,CACnB,CAAA;YAED,MAAM,SAAS,GAAuB;gBACpC,EAAE,EAAE,OAAO,CAAC,eAAe;gBAC3B,IAAI;gBACJ,KAAK,EAAE,OAAO,CAAC,KAAK,IAAI,EAAE;gBAC1B,GAAG,SAAS;aACb,CAAA;YAED,OAAO,SAAS,CAAA;QAClB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,UAAU,CAAC,KAAK,CAAC,CAAA;QACnB,CAAC;IACH,CAAC;IAED,KAAK,CAAC,oBAAoB,CACxB,OAAiC;QAEjC,IAAI,CAAC;YACH,OAAO;gBACL,EAAE,EAAE,OAAO,CAAC,EAAE;gBACd,KAAK,EAAE,OAAO,CAAC,MAAM;gBACrB,GAAG,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,SAAS,CAAC;aAC3C,CAAA;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,UAAU,CAAC,KAAK,CAAC,CAAA;QACnB,CAAC;IACH,CAAC;IAED,KAAK,CAAC,kBAAkB,CACtB,OAA+B;QAE/B,IAAI,CAAC;YACH,MAAM,SAAS,GAAuB;gBACpC,EAAE,EAAE,OAAO,CAAC,EAAE;gBACd,IAAI,EAAE,OAAO,CAAC,IAAI;gBAClB,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC;gBAChC,GAAG,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,SAAS,CAAC;aAC3C,CAAA;YAED,OAAO,SAAS,CAAA;QAClB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,UAAU,CAAC,KAAK,CAAC,CAAA;QACnB,CAAC;IACH,CAAC;IAED;;OAEG;IACK,eAAe,CAAC,SAAwB;QAC9C,MAAM,SAAS,GAAqB,EAAE,CAAA;QAEtC,IAAI,SAAS,EAAE,QAAQ,EAAE,CAAC;YACxB,SAAS,CAAC,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAA;QAC7D,CAAC;QACD,IAAI,SAAS,EAAE,YAAY,EAAE,CAAC;YAC5B,SAAS,CAAC,YAAY,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC,CAAA;QACrE,CAAC;QACD,IAAI,SAAS,EAAE,oBAAoB,EAAE,CAAC;YACpC,SAAS,CAAC,oBAAoB,GAAG,MAAM,CACrC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,oBAAoB,CAAC,CAC3C,CAAA;QACH,CAAC;QAED,OAAO,SAAS,CAAA;IAClB,CAAC;CACF"}
|
|
@@ -18,6 +18,10 @@ export declare class EthereumTransactionService {
|
|
|
18
18
|
* Send smart contract transaction (including ERC-20 transfers)
|
|
19
19
|
*/
|
|
20
20
|
private sendContractCall;
|
|
21
|
+
/**
|
|
22
|
+
* Send transaction with raw data
|
|
23
|
+
*/
|
|
24
|
+
private sendDataTransfer;
|
|
21
25
|
/**
|
|
22
26
|
* Send batch of transactions (EIP-5792)
|
|
23
27
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ethereum-transaction-service.d.ts","sourceRoot":"","sources":["../../../src/services/ethereum/ethereum-transaction-service.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAA;AAC/D,OAAO,KAAK,EAKV,0BAA0B,
|
|
1
|
+
{"version":3,"file":"ethereum-transaction-service.d.ts","sourceRoot":"","sources":["../../../src/services/ethereum/ethereum-transaction-service.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAA;AAC/D,OAAO,KAAK,EAKV,0BAA0B,EAE3B,MAAM,wBAAwB,CAAA;AAI/B;;GAEG;AACH,qBAAa,0BAA0B;IACrC,OAAO,CAAC,OAAO,CAA4B;;IAM3C;;OAEG;IACG,eAAe,CACnB,OAAO,EAAE,0BAA0B,EACnC,QAAQ,EAAE,gBAAgB,GACzB,OAAO,CAAC,MAAM,CAAC;IAmClB;;OAEG;YACW,qBAAqB;IAuBnC;;OAEG;YACW,gBAAgB;IAuB9B;;OAEG;YACW,gBAAgB;IAuB9B;;OAEG;YACW,SAAS;CA+ExB"}
|
|
@@ -23,6 +23,10 @@ export class EthereumTransactionService {
|
|
|
23
23
|
// Batch transaction
|
|
24
24
|
return await this.sendBatch(provider, request);
|
|
25
25
|
}
|
|
26
|
+
else if ('data' in request && 'chainId' in request) {
|
|
27
|
+
// Data transfer (raw transaction data)
|
|
28
|
+
return await this.sendDataTransfer(provider, request);
|
|
29
|
+
}
|
|
26
30
|
else if ('amount' in request && typeof request.amount === 'bigint') {
|
|
27
31
|
// Native transfer
|
|
28
32
|
return await this.sendNativeTransaction(provider, request);
|
|
@@ -75,6 +79,26 @@ export class EthereumTransactionService {
|
|
|
75
79
|
parseError(error);
|
|
76
80
|
}
|
|
77
81
|
}
|
|
82
|
+
/**
|
|
83
|
+
* Send transaction with raw data
|
|
84
|
+
*/
|
|
85
|
+
async sendDataTransfer(provider, request) {
|
|
86
|
+
try {
|
|
87
|
+
// Build transaction
|
|
88
|
+
const tx = await this.builder.getDataTransaction(request);
|
|
89
|
+
// Create ethers provider and signer
|
|
90
|
+
const ethersProvider = new ethers.BrowserProvider(provider);
|
|
91
|
+
const signer = await ethersProvider.getSigner(request.from);
|
|
92
|
+
// Send transaction
|
|
93
|
+
const response = await signer.sendTransaction(tx);
|
|
94
|
+
// Wait for confirmation
|
|
95
|
+
const receipt = await response.wait();
|
|
96
|
+
return receipt ? receipt.hash : '';
|
|
97
|
+
}
|
|
98
|
+
catch (error) {
|
|
99
|
+
parseError(error);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
78
102
|
/**
|
|
79
103
|
* Send batch of transactions (EIP-5792)
|
|
80
104
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ethereum-transaction-service.js","sourceRoot":"","sources":["../../../src/services/ethereum/ethereum-transaction-service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;
|
|
1
|
+
{"version":3,"file":"ethereum-transaction-service.js","sourceRoot":"","sources":["../../../src/services/ethereum/ethereum-transaction-service.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@meshconnect/uwc-injected-connector",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Injected connector for Universal Wallet Connector",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -27,8 +27,8 @@
|
|
|
27
27
|
"buffer": "^6.0.3",
|
|
28
28
|
"ethers": "^6.15.0",
|
|
29
29
|
"uuid": "^11.1.0",
|
|
30
|
-
"@meshconnect/uwc-types": "0.
|
|
31
|
-
"@meshconnect/uwc-constants": "0.2.
|
|
30
|
+
"@meshconnect/uwc-types": "0.4.0",
|
|
31
|
+
"@meshconnect/uwc-constants": "0.2.13"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
34
|
"typescript": "^5.9.2"
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach } from 'vitest'
|
|
2
|
+
import { EthereumTransactionBuilder } from './ethereum-transaction-builder'
|
|
3
|
+
import type {
|
|
4
|
+
EVMNativeTransferRequest,
|
|
5
|
+
EVMContractCallRequest,
|
|
6
|
+
EVMDataTransferRequest
|
|
7
|
+
} from '@meshconnect/uwc-types'
|
|
8
|
+
|
|
9
|
+
describe('EthereumTransactionBuilder', () => {
|
|
10
|
+
let builder: EthereumTransactionBuilder
|
|
11
|
+
|
|
12
|
+
beforeEach(() => {
|
|
13
|
+
builder = new EthereumTransactionBuilder()
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
describe('getNativeTransaction', () => {
|
|
17
|
+
it('should build a native transaction request', async () => {
|
|
18
|
+
const request: EVMNativeTransferRequest = {
|
|
19
|
+
from: '0x1234567890123456789012345678901234567890',
|
|
20
|
+
to: '0x0987654321098765432109876543210987654321',
|
|
21
|
+
amount: BigInt('1000000000000000000'), // 1 ETH
|
|
22
|
+
gasConfig: {
|
|
23
|
+
gasLimit: 21000,
|
|
24
|
+
maxFeePerGas: 50000000000,
|
|
25
|
+
maxPriorityFeePerGas: 2000000000
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const result = await builder.getNativeTransaction(request)
|
|
30
|
+
|
|
31
|
+
expect(result).toEqual({
|
|
32
|
+
to: request.to,
|
|
33
|
+
value: request.amount,
|
|
34
|
+
gasLimit: BigInt(21000),
|
|
35
|
+
maxFeePerGas: BigInt(50000000000),
|
|
36
|
+
maxPriorityFeePerGas: BigInt(2000000000)
|
|
37
|
+
})
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
it('should build a native transaction without gas config', async () => {
|
|
41
|
+
const request: EVMNativeTransferRequest = {
|
|
42
|
+
from: '0x1234567890123456789012345678901234567890',
|
|
43
|
+
to: '0x0987654321098765432109876543210987654321',
|
|
44
|
+
amount: BigInt('500000000000000000') // 0.5 ETH
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const result = await builder.getNativeTransaction(request)
|
|
48
|
+
|
|
49
|
+
expect(result).toEqual({
|
|
50
|
+
to: request.to,
|
|
51
|
+
value: request.amount
|
|
52
|
+
})
|
|
53
|
+
})
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
describe('getContractTransaction', () => {
|
|
57
|
+
it('should build a contract transaction request', async () => {
|
|
58
|
+
const erc20ABI = [
|
|
59
|
+
{
|
|
60
|
+
inputs: [
|
|
61
|
+
{ name: 'recipient', type: 'address' },
|
|
62
|
+
{ name: 'amount', type: 'uint256' }
|
|
63
|
+
],
|
|
64
|
+
name: 'transfer',
|
|
65
|
+
outputs: [{ name: '', type: 'bool' }],
|
|
66
|
+
stateMutability: 'nonpayable',
|
|
67
|
+
type: 'function'
|
|
68
|
+
}
|
|
69
|
+
]
|
|
70
|
+
|
|
71
|
+
const request: EVMContractCallRequest = {
|
|
72
|
+
from: '0x1234567890123456789012345678901234567890',
|
|
73
|
+
contractAddress: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
|
|
74
|
+
abi: erc20ABI,
|
|
75
|
+
functionName: 'transfer',
|
|
76
|
+
args: ['0x0987654321098765432109876543210987654321', BigInt(1000000)],
|
|
77
|
+
gasConfig: {
|
|
78
|
+
gasLimit: 100000
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const result = await builder.getContractTransaction(request)
|
|
83
|
+
|
|
84
|
+
expect(result.to).toBe(request.contractAddress)
|
|
85
|
+
expect(result.data).toBeDefined()
|
|
86
|
+
expect(result.data).toContain('0xa9059cbb') // transfer function selector
|
|
87
|
+
expect(result.value).toBe(0n)
|
|
88
|
+
expect(result.gasLimit).toBe(BigInt(100000))
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
it('should build a payable contract transaction', async () => {
|
|
92
|
+
const payableABI = [
|
|
93
|
+
{
|
|
94
|
+
inputs: [],
|
|
95
|
+
name: 'deposit',
|
|
96
|
+
outputs: [],
|
|
97
|
+
stateMutability: 'payable',
|
|
98
|
+
type: 'function'
|
|
99
|
+
}
|
|
100
|
+
]
|
|
101
|
+
|
|
102
|
+
const request: EVMContractCallRequest = {
|
|
103
|
+
from: '0x1234567890123456789012345678901234567890',
|
|
104
|
+
contractAddress: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
|
|
105
|
+
abi: payableABI,
|
|
106
|
+
functionName: 'deposit',
|
|
107
|
+
args: [],
|
|
108
|
+
value: BigInt('1000000000000000000') // 1 ETH
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const result = await builder.getContractTransaction(request)
|
|
112
|
+
|
|
113
|
+
expect(result.to).toBe(request.contractAddress)
|
|
114
|
+
expect(result.data).toBeDefined()
|
|
115
|
+
expect(result.value).toBe(request.value)
|
|
116
|
+
})
|
|
117
|
+
})
|
|
118
|
+
|
|
119
|
+
describe('getDataTransaction', () => {
|
|
120
|
+
it('should build a data transaction request with all fields', async () => {
|
|
121
|
+
const request: EVMDataTransferRequest = {
|
|
122
|
+
from: '0x1234567890123456789012345678901234567890',
|
|
123
|
+
to: '0x0987654321098765432109876543210987654321',
|
|
124
|
+
data: '0xa9059cbb000000000000000000000000123456789012345678901234567890123456789000000000000000000000000000000000000000000000000000000000000f4240',
|
|
125
|
+
chainId: '1',
|
|
126
|
+
value: BigInt('500000000000000000'), // 0.5 ETH
|
|
127
|
+
gasConfig: {
|
|
128
|
+
gasLimit: 100000,
|
|
129
|
+
maxFeePerGas: 50000000000,
|
|
130
|
+
maxPriorityFeePerGas: 2000000000
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const result = await builder.getDataTransaction(request)
|
|
135
|
+
|
|
136
|
+
expect(result).toEqual({
|
|
137
|
+
to: request.to,
|
|
138
|
+
data: request.data,
|
|
139
|
+
chainId: BigInt(1),
|
|
140
|
+
gasLimit: BigInt(100000),
|
|
141
|
+
maxFeePerGas: BigInt(50000000000),
|
|
142
|
+
maxPriorityFeePerGas: BigInt(2000000000)
|
|
143
|
+
})
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
it('should build a data transaction without value', async () => {
|
|
147
|
+
const request: EVMDataTransferRequest = {
|
|
148
|
+
from: '0x1234567890123456789012345678901234567890',
|
|
149
|
+
to: '0x0987654321098765432109876543210987654321',
|
|
150
|
+
data: '0xa9059cbb',
|
|
151
|
+
chainId: '137' // Polygon
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const result = await builder.getDataTransaction(request)
|
|
155
|
+
|
|
156
|
+
expect(result).toEqual({
|
|
157
|
+
to: request.to,
|
|
158
|
+
data: request.data,
|
|
159
|
+
chainId: BigInt(137)
|
|
160
|
+
})
|
|
161
|
+
})
|
|
162
|
+
|
|
163
|
+
it('should build a data transaction with minimal gas config', async () => {
|
|
164
|
+
const request: EVMDataTransferRequest = {
|
|
165
|
+
from: '0x1234567890123456789012345678901234567890',
|
|
166
|
+
to: '0x0987654321098765432109876543210987654321',
|
|
167
|
+
data: '0x00',
|
|
168
|
+
chainId: '8453', // Base
|
|
169
|
+
gasConfig: {
|
|
170
|
+
gasLimit: 50000
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const result = await builder.getDataTransaction(request)
|
|
175
|
+
|
|
176
|
+
expect(result.gasLimit).toBe(BigInt(50000))
|
|
177
|
+
expect(result.maxFeePerGas).toBeUndefined()
|
|
178
|
+
expect(result.maxPriorityFeePerGas).toBeUndefined()
|
|
179
|
+
})
|
|
180
|
+
|
|
181
|
+
it('should handle empty data field', async () => {
|
|
182
|
+
const request: EVMDataTransferRequest = {
|
|
183
|
+
from: '0x1234567890123456789012345678901234567890',
|
|
184
|
+
to: '0x0987654321098765432109876543210987654321',
|
|
185
|
+
data: '0x',
|
|
186
|
+
chainId: '1'
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const result = await builder.getDataTransaction(request)
|
|
190
|
+
|
|
191
|
+
expect(result.data).toBe('0x')
|
|
192
|
+
expect(result.to).toBe(request.to)
|
|
193
|
+
expect(result.chainId).toBe(BigInt(1))
|
|
194
|
+
})
|
|
195
|
+
|
|
196
|
+
it('should handle complex encoded data', async () => {
|
|
197
|
+
const complexData = '0x' + 'a'.repeat(1000) // Long hex string
|
|
198
|
+
|
|
199
|
+
const request: EVMDataTransferRequest = {
|
|
200
|
+
from: '0x1234567890123456789012345678901234567890',
|
|
201
|
+
to: '0x0987654321098765432109876543210987654321',
|
|
202
|
+
data: complexData,
|
|
203
|
+
chainId: '42161' // Arbitrum
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const result = await builder.getDataTransaction(request)
|
|
207
|
+
|
|
208
|
+
expect(result.data).toBe(complexData)
|
|
209
|
+
expect(result.chainId).toBe(BigInt(42161))
|
|
210
|
+
})
|
|
211
|
+
})
|
|
212
|
+
|
|
213
|
+
describe('formatGasConfig', () => {
|
|
214
|
+
it('should handle null gas config values', async () => {
|
|
215
|
+
const request: EVMNativeTransferRequest = {
|
|
216
|
+
from: '0x1234567890123456789012345678901234567890',
|
|
217
|
+
to: '0x0987654321098765432109876543210987654321',
|
|
218
|
+
amount: BigInt('1000000000000000000'),
|
|
219
|
+
gasConfig: {
|
|
220
|
+
gasLimit: null,
|
|
221
|
+
maxFeePerGas: null,
|
|
222
|
+
maxPriorityFeePerGas: null
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
const result = await builder.getNativeTransaction(request)
|
|
227
|
+
|
|
228
|
+
expect(result.gasLimit).toBeUndefined()
|
|
229
|
+
expect(result.maxFeePerGas).toBeUndefined()
|
|
230
|
+
expect(result.maxPriorityFeePerGas).toBeUndefined()
|
|
231
|
+
})
|
|
232
|
+
|
|
233
|
+
it('should floor decimal gas values', async () => {
|
|
234
|
+
const request: EVMNativeTransferRequest = {
|
|
235
|
+
from: '0x1234567890123456789012345678901234567890',
|
|
236
|
+
to: '0x0987654321098765432109876543210987654321',
|
|
237
|
+
amount: BigInt('1000000000000000000'),
|
|
238
|
+
gasConfig: {
|
|
239
|
+
gasLimit: 21000.7,
|
|
240
|
+
maxFeePerGas: 50000000000.9,
|
|
241
|
+
maxPriorityFeePerGas: 2000000000.1
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
const result = await builder.getNativeTransaction(request)
|
|
246
|
+
|
|
247
|
+
expect(result.gasLimit).toBe(BigInt(21000))
|
|
248
|
+
expect(result.maxFeePerGas).toBe(BigInt(50000000000))
|
|
249
|
+
expect(result.maxPriorityFeePerGas).toBe(BigInt(2000000000))
|
|
250
|
+
})
|
|
251
|
+
})
|
|
252
|
+
})
|
|
@@ -2,7 +2,8 @@ import { ethers } from 'ethers'
|
|
|
2
2
|
import type {
|
|
3
3
|
EVMGasConfig,
|
|
4
4
|
EVMNativeTransferRequest,
|
|
5
|
-
EVMContractCallRequest
|
|
5
|
+
EVMContractCallRequest,
|
|
6
|
+
EVMDataTransferRequest
|
|
6
7
|
} from '@meshconnect/uwc-types'
|
|
7
8
|
import { parseError } from '../../utils/error-utils'
|
|
8
9
|
import type { TransactionRequest } from 'ethers'
|
|
@@ -59,6 +60,23 @@ export class EthereumTransactionBuilder {
|
|
|
59
60
|
}
|
|
60
61
|
}
|
|
61
62
|
|
|
63
|
+
async getDataTransaction(
|
|
64
|
+
request: EVMDataTransferRequest
|
|
65
|
+
): Promise<TransactionRequest> {
|
|
66
|
+
try {
|
|
67
|
+
const txRequest: TransactionRequest = {
|
|
68
|
+
to: request.to,
|
|
69
|
+
data: request.data,
|
|
70
|
+
chainId: BigInt(request.chainId),
|
|
71
|
+
...this.formatGasConfig(request.gasConfig)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return txRequest
|
|
75
|
+
} catch (error) {
|
|
76
|
+
parseError(error)
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
62
80
|
/**
|
|
63
81
|
* Helper to format gas configuration for ethers
|
|
64
82
|
*/
|
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, vi } from 'vitest'
|
|
2
|
+
import { EthereumTransactionService } from './ethereum-transaction-service'
|
|
3
|
+
import type {
|
|
4
|
+
EVMNativeTransferRequest,
|
|
5
|
+
EVMContractCallRequest,
|
|
6
|
+
EVMDataTransferRequest
|
|
7
|
+
} from '@meshconnect/uwc-types'
|
|
8
|
+
import type { EthereumProvider } from '../../eip6963-discovery'
|
|
9
|
+
|
|
10
|
+
// Mock ethers
|
|
11
|
+
vi.mock('ethers', () => {
|
|
12
|
+
const mockReceipt = { hash: '0xtxhash' }
|
|
13
|
+
const mockResponse = {
|
|
14
|
+
wait: vi.fn().mockResolvedValue(mockReceipt)
|
|
15
|
+
}
|
|
16
|
+
const mockSigner = {
|
|
17
|
+
sendTransaction: vi.fn().mockResolvedValue(mockResponse)
|
|
18
|
+
}
|
|
19
|
+
const mockProvider = {
|
|
20
|
+
getSigner: vi.fn().mockResolvedValue(mockSigner),
|
|
21
|
+
send: vi.fn()
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return {
|
|
25
|
+
ethers: {
|
|
26
|
+
BrowserProvider: vi.fn().mockImplementation(() => mockProvider),
|
|
27
|
+
Interface: vi.fn().mockImplementation(() => ({
|
|
28
|
+
encodeFunctionData: vi.fn().mockReturnValue('0xencodeddata')
|
|
29
|
+
}))
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
describe('EthereumTransactionService', () => {
|
|
35
|
+
let service: EthereumTransactionService
|
|
36
|
+
let mockProvider: EthereumProvider
|
|
37
|
+
|
|
38
|
+
beforeEach(() => {
|
|
39
|
+
vi.clearAllMocks()
|
|
40
|
+
service = new EthereumTransactionService()
|
|
41
|
+
mockProvider = {
|
|
42
|
+
request: vi.fn()
|
|
43
|
+
} as any
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
describe('sendTransaction routing', () => {
|
|
47
|
+
it('should route native transfer to sendNativeTransaction', async () => {
|
|
48
|
+
const request: EVMNativeTransferRequest = {
|
|
49
|
+
from: '0x1234567890123456789012345678901234567890',
|
|
50
|
+
to: '0x0987654321098765432109876543210987654321',
|
|
51
|
+
amount: BigInt('1000000000000000000'),
|
|
52
|
+
gasConfig: { gasLimit: 21000 }
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const result = await service.sendTransaction(request, mockProvider)
|
|
56
|
+
|
|
57
|
+
expect(result).toBe('0xtxhash')
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
it('should route contract call to sendContractCall', async () => {
|
|
61
|
+
const request: EVMContractCallRequest = {
|
|
62
|
+
from: '0x1234567890123456789012345678901234567890',
|
|
63
|
+
contractAddress: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
|
|
64
|
+
abi: [
|
|
65
|
+
{
|
|
66
|
+
inputs: [
|
|
67
|
+
{ name: 'recipient', type: 'address' },
|
|
68
|
+
{ name: 'amount', type: 'uint256' }
|
|
69
|
+
],
|
|
70
|
+
name: 'transfer',
|
|
71
|
+
outputs: [{ name: '', type: 'bool' }],
|
|
72
|
+
stateMutability: 'nonpayable',
|
|
73
|
+
type: 'function'
|
|
74
|
+
}
|
|
75
|
+
],
|
|
76
|
+
functionName: 'transfer',
|
|
77
|
+
args: ['0x0987654321098765432109876543210987654321', BigInt(1000000)]
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const result = await service.sendTransaction(request, mockProvider)
|
|
81
|
+
|
|
82
|
+
expect(result).toBe('0xtxhash')
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
it('should route data transfer to sendDataTransfer', async () => {
|
|
86
|
+
const request: EVMDataTransferRequest = {
|
|
87
|
+
from: '0x1234567890123456789012345678901234567890',
|
|
88
|
+
to: '0x0987654321098765432109876543210987654321',
|
|
89
|
+
data: '0xa9059cbb',
|
|
90
|
+
chainId: '1'
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const result = await service.sendTransaction(request, mockProvider)
|
|
94
|
+
|
|
95
|
+
expect(result).toBe('0xtxhash')
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
it('should throw error for invalid request type', async () => {
|
|
99
|
+
const invalidRequest = {
|
|
100
|
+
from: '0x1234567890123456789012345678901234567890'
|
|
101
|
+
} as any
|
|
102
|
+
|
|
103
|
+
await expect(
|
|
104
|
+
service.sendTransaction(invalidRequest, mockProvider)
|
|
105
|
+
).rejects.toThrow('Invalid transaction request type')
|
|
106
|
+
})
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
describe('sendNativeTransaction', () => {
|
|
110
|
+
it('should send native transaction successfully', async () => {
|
|
111
|
+
const request: EVMNativeTransferRequest = {
|
|
112
|
+
from: '0x1234567890123456789012345678901234567890',
|
|
113
|
+
to: '0x0987654321098765432109876543210987654321',
|
|
114
|
+
amount: BigInt('1000000000000000000')
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const result = await service.sendTransaction(request, mockProvider)
|
|
118
|
+
|
|
119
|
+
expect(result).toBe('0xtxhash')
|
|
120
|
+
})
|
|
121
|
+
|
|
122
|
+
it('should handle transaction with gas config', async () => {
|
|
123
|
+
const request: EVMNativeTransferRequest = {
|
|
124
|
+
from: '0x1234567890123456789012345678901234567890',
|
|
125
|
+
to: '0x0987654321098765432109876543210987654321',
|
|
126
|
+
amount: BigInt('500000000000000000'),
|
|
127
|
+
gasConfig: {
|
|
128
|
+
gasLimit: 21000,
|
|
129
|
+
maxFeePerGas: 50000000000,
|
|
130
|
+
maxPriorityFeePerGas: 2000000000
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const result = await service.sendTransaction(request, mockProvider)
|
|
135
|
+
|
|
136
|
+
expect(result).toBe('0xtxhash')
|
|
137
|
+
})
|
|
138
|
+
})
|
|
139
|
+
|
|
140
|
+
describe('sendContractCall', () => {
|
|
141
|
+
it('should send contract call successfully', async () => {
|
|
142
|
+
const request: EVMContractCallRequest = {
|
|
143
|
+
from: '0x1234567890123456789012345678901234567890',
|
|
144
|
+
contractAddress: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
|
|
145
|
+
abi: [
|
|
146
|
+
{
|
|
147
|
+
inputs: [
|
|
148
|
+
{ name: 'recipient', type: 'address' },
|
|
149
|
+
{ name: 'amount', type: 'uint256' }
|
|
150
|
+
],
|
|
151
|
+
name: 'transfer',
|
|
152
|
+
outputs: [{ name: '', type: 'bool' }],
|
|
153
|
+
stateMutability: 'nonpayable',
|
|
154
|
+
type: 'function'
|
|
155
|
+
}
|
|
156
|
+
],
|
|
157
|
+
functionName: 'transfer',
|
|
158
|
+
args: ['0x0987654321098765432109876543210987654321', BigInt(1000000)]
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const result = await service.sendTransaction(request, mockProvider)
|
|
162
|
+
|
|
163
|
+
expect(result).toBe('0xtxhash')
|
|
164
|
+
})
|
|
165
|
+
|
|
166
|
+
it('should send payable contract call with value', async () => {
|
|
167
|
+
const request: EVMContractCallRequest = {
|
|
168
|
+
from: '0x1234567890123456789012345678901234567890',
|
|
169
|
+
contractAddress: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
|
|
170
|
+
abi: [
|
|
171
|
+
{
|
|
172
|
+
inputs: [],
|
|
173
|
+
name: 'deposit',
|
|
174
|
+
outputs: [],
|
|
175
|
+
stateMutability: 'payable',
|
|
176
|
+
type: 'function'
|
|
177
|
+
}
|
|
178
|
+
],
|
|
179
|
+
functionName: 'deposit',
|
|
180
|
+
args: [],
|
|
181
|
+
value: BigInt('1000000000000000000')
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const result = await service.sendTransaction(request, mockProvider)
|
|
185
|
+
|
|
186
|
+
expect(result).toBe('0xtxhash')
|
|
187
|
+
})
|
|
188
|
+
})
|
|
189
|
+
|
|
190
|
+
describe('sendDataTransfer', () => {
|
|
191
|
+
it('should send data transfer successfully', async () => {
|
|
192
|
+
const request: EVMDataTransferRequest = {
|
|
193
|
+
from: '0x1234567890123456789012345678901234567890',
|
|
194
|
+
to: '0x0987654321098765432109876543210987654321',
|
|
195
|
+
data: '0xa9059cbb000000000000000000000000123456789012345678901234567890123456789000000000000000000000000000000000000000000000000000000000000f4240',
|
|
196
|
+
chainId: '1'
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const result = await service.sendTransaction(request, mockProvider)
|
|
200
|
+
|
|
201
|
+
expect(result).toBe('0xtxhash')
|
|
202
|
+
})
|
|
203
|
+
|
|
204
|
+
it('should send data transfer with value', async () => {
|
|
205
|
+
const request: EVMDataTransferRequest = {
|
|
206
|
+
from: '0x1234567890123456789012345678901234567890',
|
|
207
|
+
to: '0x0987654321098765432109876543210987654321',
|
|
208
|
+
data: '0xa9059cbb',
|
|
209
|
+
chainId: '1',
|
|
210
|
+
value: BigInt('500000000000000000')
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
const result = await service.sendTransaction(request, mockProvider)
|
|
214
|
+
|
|
215
|
+
expect(result).toBe('0xtxhash')
|
|
216
|
+
})
|
|
217
|
+
|
|
218
|
+
it('should send data transfer with gas config', async () => {
|
|
219
|
+
const request: EVMDataTransferRequest = {
|
|
220
|
+
from: '0x1234567890123456789012345678901234567890',
|
|
221
|
+
to: '0x0987654321098765432109876543210987654321',
|
|
222
|
+
data: '0x00',
|
|
223
|
+
chainId: '137',
|
|
224
|
+
gasConfig: {
|
|
225
|
+
gasLimit: 100000,
|
|
226
|
+
maxFeePerGas: 50000000000,
|
|
227
|
+
maxPriorityFeePerGas: 2000000000
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
const result = await service.sendTransaction(request, mockProvider)
|
|
232
|
+
|
|
233
|
+
expect(result).toBe('0xtxhash')
|
|
234
|
+
})
|
|
235
|
+
|
|
236
|
+
it('should send data transfer on different chains', async () => {
|
|
237
|
+
const chains = ['1', '137', '8453', '42161', '10'] // Ethereum, Polygon, Base, Arbitrum, Optimism
|
|
238
|
+
|
|
239
|
+
for (const chainId of chains) {
|
|
240
|
+
const request: EVMDataTransferRequest = {
|
|
241
|
+
from: '0x1234567890123456789012345678901234567890',
|
|
242
|
+
to: '0x0987654321098765432109876543210987654321',
|
|
243
|
+
data: '0xa9059cbb',
|
|
244
|
+
chainId
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
const result = await service.sendTransaction(request, mockProvider)
|
|
248
|
+
expect(result).toBe('0xtxhash')
|
|
249
|
+
}
|
|
250
|
+
})
|
|
251
|
+
|
|
252
|
+
it('should handle empty data field', async () => {
|
|
253
|
+
const request: EVMDataTransferRequest = {
|
|
254
|
+
from: '0x1234567890123456789012345678901234567890',
|
|
255
|
+
to: '0x0987654321098765432109876543210987654321',
|
|
256
|
+
data: '0x',
|
|
257
|
+
chainId: '1'
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
const result = await service.sendTransaction(request, mockProvider)
|
|
261
|
+
|
|
262
|
+
expect(result).toBe('0xtxhash')
|
|
263
|
+
})
|
|
264
|
+
|
|
265
|
+
it('should handle complex encoded data', async () => {
|
|
266
|
+
const complexData = '0x' + 'a'.repeat(1000)
|
|
267
|
+
|
|
268
|
+
const request: EVMDataTransferRequest = {
|
|
269
|
+
from: '0x1234567890123456789012345678901234567890',
|
|
270
|
+
to: '0x0987654321098765432109876543210987654321',
|
|
271
|
+
data: complexData,
|
|
272
|
+
chainId: '1'
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
const result = await service.sendTransaction(request, mockProvider)
|
|
276
|
+
|
|
277
|
+
expect(result).toBe('0xtxhash')
|
|
278
|
+
})
|
|
279
|
+
})
|
|
280
|
+
|
|
281
|
+
describe('error handling', () => {
|
|
282
|
+
it('should handle transaction errors', async () => {
|
|
283
|
+
const { ethers } = await import('ethers')
|
|
284
|
+
const mockError = new Error('Transaction failed')
|
|
285
|
+
vi.mocked(ethers.BrowserProvider).mockImplementationOnce(
|
|
286
|
+
(_provider: any) => {
|
|
287
|
+
throw mockError
|
|
288
|
+
}
|
|
289
|
+
)
|
|
290
|
+
|
|
291
|
+
const request: EVMDataTransferRequest = {
|
|
292
|
+
from: '0x1234567890123456789012345678901234567890',
|
|
293
|
+
to: '0x0987654321098765432109876543210987654321',
|
|
294
|
+
data: '0xa9059cbb',
|
|
295
|
+
chainId: '1'
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
await expect(
|
|
299
|
+
service.sendTransaction(request, mockProvider)
|
|
300
|
+
).rejects.toThrow()
|
|
301
|
+
})
|
|
302
|
+
})
|
|
303
|
+
})
|
|
@@ -5,7 +5,8 @@ import type {
|
|
|
5
5
|
EVMContractCallRequest,
|
|
6
6
|
EVMBatchTransactionRequest,
|
|
7
7
|
BatchTransactionResult,
|
|
8
|
-
EthereumTransactionRequest
|
|
8
|
+
EthereumTransactionRequest,
|
|
9
|
+
EVMDataTransferRequest
|
|
9
10
|
} from '@meshconnect/uwc-types'
|
|
10
11
|
import { parseError } from '../../utils/error-utils'
|
|
11
12
|
import { EthereumTransactionBuilder } from './ethereum-transaction-builder'
|
|
@@ -41,6 +42,12 @@ export class EthereumTransactionService {
|
|
|
41
42
|
provider,
|
|
42
43
|
request as EVMBatchTransactionRequest
|
|
43
44
|
)
|
|
45
|
+
} else if ('data' in request && 'chainId' in request) {
|
|
46
|
+
// Data transfer (raw transaction data)
|
|
47
|
+
return await this.sendDataTransfer(
|
|
48
|
+
provider,
|
|
49
|
+
request as EVMDataTransferRequest
|
|
50
|
+
)
|
|
44
51
|
} else if ('amount' in request && typeof request.amount === 'bigint') {
|
|
45
52
|
// Native transfer
|
|
46
53
|
return await this.sendNativeTransaction(
|
|
@@ -107,6 +114,32 @@ export class EthereumTransactionService {
|
|
|
107
114
|
}
|
|
108
115
|
}
|
|
109
116
|
|
|
117
|
+
/**
|
|
118
|
+
* Send transaction with raw data
|
|
119
|
+
*/
|
|
120
|
+
private async sendDataTransfer(
|
|
121
|
+
provider: EthereumProvider,
|
|
122
|
+
request: EVMDataTransferRequest
|
|
123
|
+
): Promise<string> {
|
|
124
|
+
try {
|
|
125
|
+
// Build transaction
|
|
126
|
+
const tx = await this.builder.getDataTransaction(request)
|
|
127
|
+
|
|
128
|
+
// Create ethers provider and signer
|
|
129
|
+
const ethersProvider = new ethers.BrowserProvider(provider)
|
|
130
|
+
const signer = await ethersProvider.getSigner(request.from)
|
|
131
|
+
|
|
132
|
+
// Send transaction
|
|
133
|
+
const response = await signer.sendTransaction(tx)
|
|
134
|
+
|
|
135
|
+
// Wait for confirmation
|
|
136
|
+
const receipt = await response.wait()
|
|
137
|
+
return receipt ? receipt.hash : ''
|
|
138
|
+
} catch (error) {
|
|
139
|
+
parseError(error)
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
110
143
|
/**
|
|
111
144
|
* Send batch of transactions (EIP-5792)
|
|
112
145
|
*/
|