4
4
Log ,
5
5
TransactionController ,
6
6
TransactionControllerGetStateAction ,
7
+ TransactionMeta ,
7
8
TransactionReceipt ,
8
9
TransactionStatus ,
9
10
} from '@metamask/transaction-controller' ;
@@ -22,6 +23,9 @@ type Actions =
22
23
23
24
export type EIP5792Messenger = Messenger < Actions , never > ;
24
25
26
+ const VERSION_SEND_CALLS = '1.0' ;
27
+ const VERSION_GET_CALLS_STATUS = '1.0' ;
28
+
25
29
export async function processSendCalls (
26
30
hooks : {
27
31
addTransactionBatch : TransactionController [ 'addTransactionBatch' ] ;
@@ -32,7 +36,7 @@ export async function processSendCalls(
32
36
req : JsonRpcRequest & { networkClientId : string ; origin ?: string } ,
33
37
) : Promise < SendCallsResult > {
34
38
const { addTransactionBatch, getDisabledAccountUpgradeChains } = hooks ;
35
- const { calls, capabilities , chainId : requestChainId , from } = params ;
39
+ const { calls, from } = params ;
36
40
const { networkClientId, origin } = req ;
37
41
const transactions = calls . map ( ( call ) => ( { params : call } ) ) ;
38
42
@@ -41,46 +45,9 @@ export async function processSendCalls(
41
45
networkClientId ,
42
46
) . configuration . chainId ;
43
47
44
- if (
45
- requestChainId &&
46
- requestChainId . toLowerCase ( ) !== dappChainId . toLowerCase ( )
47
- ) {
48
- throw rpcErrors . invalidInput (
49
- `Chain ID must match the dApp selected network: Got ${ requestChainId } , expected ${ dappChainId } ` ,
50
- ) ;
51
- }
52
-
53
- const requiredTopLevelCapabilities = Object . keys ( capabilities ?? { } ) . filter (
54
- ( name ) => capabilities ?. [ name ] . optional !== true ,
55
- ) ;
56
-
57
- const requiredCallCapabilities = calls . flatMap ( ( call ) =>
58
- Object . keys ( call . capabilities ?? { } ) . filter (
59
- ( name ) => call . capabilities ?. [ name ] . optional !== true ,
60
- ) ,
61
- ) ;
62
-
63
- const requiredCapabilities = [
64
- ...requiredTopLevelCapabilities ,
65
- ...requiredCallCapabilities ,
66
- ] ;
67
-
68
- if ( requiredCapabilities ?. length ) {
69
- throw rpcErrors . invalidInput (
70
- `Unsupported non-optional capabilities: ${ requiredCapabilities . join (
71
- ', ' ,
72
- ) } `,
73
- ) ;
74
- }
75
-
76
48
const disabledChains = getDisabledAccountUpgradeChains ( ) ;
77
- const isDisabled = disabledChains . includes ( dappChainId ) ;
78
49
79
- if ( isDisabled ) {
80
- throw rpcErrors . methodNotSupported (
81
- `EIP-5792 is not supported for this chain and account - Chain ID: ${ dappChainId } , Account: ${ from } ` ,
82
- ) ;
83
- }
50
+ validateSendCalls ( params , dappChainId , disabledChains ) ;
84
51
85
52
const { batchId : id } = await addTransactionBatch ( {
86
53
from,
@@ -104,35 +71,13 @@ export function getCallsStatus(
104
71
throw rpcErrors . invalidInput ( `No matching calls found` ) ;
105
72
}
106
73
107
- const {
108
- chainId,
109
- hash,
110
- txReceipt : rawTxReceipt ,
111
- status : transactionStatus ,
112
- } = transactions [ 0 ] ;
113
-
114
- let status = GetCallsStatusCode . PENDING ;
115
-
116
- if ( transactionStatus === TransactionStatus . confirmed ) {
117
- status = GetCallsStatusCode . CONFIRMED ;
118
- } else if ( transactionStatus === TransactionStatus . failed ) {
119
- status = hash
120
- ? GetCallsStatusCode . REVERTED
121
- : GetCallsStatusCode . FAILED_OFFCHAIN ;
122
- } else if ( transactionStatus === TransactionStatus . dropped ) {
123
- status = GetCallsStatusCode . REVERTED ;
124
- }
125
-
126
- const txReceipt = rawTxReceipt as unknown as Required < TransactionReceipt > & {
127
- transactionHash : Hex ;
128
- } ;
129
-
130
- const logs =
131
- ( txReceipt . logs as ( Required < Log > & {
132
- data : Hex ;
133
- } ) [ ] ) ?? [ ] ;
74
+ const transaction = transactions [ 0 ] ;
75
+ const { chainId, txReceipt : rawTxReceipt } = transaction ;
76
+ const status = getStatusCode ( transaction ) ;
77
+ const txReceipt = rawTxReceipt as Required < TransactionReceipt > | undefined ;
78
+ const logs = ( txReceipt ?. logs ?? [ ] ) as Required < Log > [ ] ;
134
79
135
- const receipts : GetCallsStatusResult [ 'receipts' ] = [
80
+ const receipts : GetCallsStatusResult [ 'receipts' ] = txReceipt && [
136
81
{
137
82
blockHash : txReceipt . blockHash as Hex ,
138
83
blockNumber : txReceipt . blockNumber as Hex ,
@@ -142,13 +87,13 @@ export function getCallsStatus(
142
87
data : log . data ,
143
88
topics : log . topics as unknown as Hex [ ] ,
144
89
} ) ) ,
145
- status : txReceipt . status as Hex ,
90
+ status : txReceipt . status as '0x0' | '0x1' ,
146
91
transactionHash : txReceipt . transactionHash ,
147
92
} ,
148
93
] ;
149
94
150
95
return {
151
- version : '1.0' ,
96
+ version : VERSION_GET_CALLS_STATUS ,
152
97
id,
153
98
chainId,
154
99
status,
@@ -160,3 +105,99 @@ export async function getCapabilities(_address: Hex, _chainIds?: Hex[]) {
160
105
// No capabilities currently supported
161
106
return { } ;
162
107
}
108
+
109
+ function validateSendCalls (
110
+ sendCalls : SendCalls ,
111
+ dappChainId : Hex ,
112
+ disabledChains : Hex [ ] ,
113
+ ) {
114
+ validateSendCallsVersion ( sendCalls ) ;
115
+ validateSendCallsChainId ( sendCalls , dappChainId ) ;
116
+ validateCapabilities ( sendCalls ) ;
117
+ validateUserDisabled ( sendCalls , disabledChains , dappChainId ) ;
118
+ }
119
+
120
+ function validateSendCallsVersion ( sendCalls : SendCalls ) {
121
+ const { version } = sendCalls ;
122
+
123
+ if ( version !== VERSION_SEND_CALLS ) {
124
+ throw rpcErrors . invalidInput (
125
+ `Version not supported: Got ${ version } , expected ${ VERSION_SEND_CALLS } ` ,
126
+ ) ;
127
+ }
128
+ }
129
+
130
+ function validateSendCallsChainId ( sendCalls : SendCalls , dappChainId : Hex ) {
131
+ const { chainId : requestChainId } = sendCalls ;
132
+
133
+ if (
134
+ requestChainId &&
135
+ requestChainId . toLowerCase ( ) !== dappChainId . toLowerCase ( )
136
+ ) {
137
+ throw rpcErrors . invalidInput (
138
+ `Chain ID must match the dApp selected network: Got ${ requestChainId } , expected ${ dappChainId } ` ,
139
+ ) ;
140
+ }
141
+ }
142
+
143
+ function validateCapabilities ( sendCalls : SendCalls ) {
144
+ const { calls, capabilities } = sendCalls ;
145
+
146
+ const requiredTopLevelCapabilities = Object . keys ( capabilities ?? { } ) . filter (
147
+ ( name ) => capabilities ?. [ name ] . optional !== true ,
148
+ ) ;
149
+
150
+ const requiredCallCapabilities = calls . flatMap ( ( call ) =>
151
+ Object . keys ( call . capabilities ?? { } ) . filter (
152
+ ( name ) => call . capabilities ?. [ name ] . optional !== true ,
153
+ ) ,
154
+ ) ;
155
+
156
+ const requiredCapabilities = [
157
+ ...requiredTopLevelCapabilities ,
158
+ ...requiredCallCapabilities ,
159
+ ] ;
160
+
161
+ if ( requiredCapabilities ?. length ) {
162
+ throw rpcErrors . invalidInput (
163
+ `Unsupported non-optional capabilities: ${ requiredCapabilities . join (
164
+ ', ' ,
165
+ ) } `,
166
+ ) ;
167
+ }
168
+ }
169
+
170
+ function validateUserDisabled (
171
+ sendCalls : SendCalls ,
172
+ disabledChains : Hex [ ] ,
173
+ dappChainId : Hex ,
174
+ ) {
175
+ const { from } = sendCalls ;
176
+ const isDisabled = disabledChains . includes ( dappChainId ) ;
177
+
178
+ if ( isDisabled ) {
179
+ throw rpcErrors . methodNotSupported (
180
+ `EIP-5792 is not supported for this chain and account - Chain ID: ${ dappChainId } , Account: ${ from } ` ,
181
+ ) ;
182
+ }
183
+ }
184
+
185
+ function getStatusCode ( transactionMeta : TransactionMeta ) {
186
+ const { hash, status } = transactionMeta ;
187
+
188
+ if ( status === TransactionStatus . confirmed ) {
189
+ return GetCallsStatusCode . CONFIRMED ;
190
+ }
191
+
192
+ if ( status === TransactionStatus . failed ) {
193
+ return hash
194
+ ? GetCallsStatusCode . REVERTED
195
+ : GetCallsStatusCode . FAILED_OFFCHAIN ;
196
+ }
197
+
198
+ if ( status === TransactionStatus . dropped ) {
199
+ return GetCallsStatusCode . REVERTED ;
200
+ }
201
+
202
+ return GetCallsStatusCode . PENDING ;
203
+ }
0 commit comments