@metamask/transaction-controller 54.2.0 → 54.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.
Files changed (46) hide show
  1. package/CHANGELOG.md +20 -1
  2. package/dist/TransactionController.cjs +0 -2
  3. package/dist/TransactionController.cjs.map +1 -1
  4. package/dist/TransactionController.d.cts.map +1 -1
  5. package/dist/TransactionController.d.mts.map +1 -1
  6. package/dist/TransactionController.mjs +0 -2
  7. package/dist/TransactionController.mjs.map +1 -1
  8. package/dist/api/simulation-api.cjs.map +1 -0
  9. package/dist/{utils → api}/simulation-api.d.cts +2 -0
  10. package/dist/api/simulation-api.d.cts.map +1 -0
  11. package/dist/{utils → api}/simulation-api.d.mts +2 -0
  12. package/dist/api/simulation-api.d.mts.map +1 -0
  13. package/dist/api/simulation-api.mjs.map +1 -0
  14. package/dist/types.cjs.map +1 -1
  15. package/dist/types.d.cts +3 -1
  16. package/dist/types.d.cts.map +1 -1
  17. package/dist/types.d.mts +3 -1
  18. package/dist/types.d.mts.map +1 -1
  19. package/dist/types.mjs.map +1 -1
  20. package/dist/utils/gas.cjs +1 -1
  21. package/dist/utils/gas.cjs.map +1 -1
  22. package/dist/utils/gas.mjs +1 -1
  23. package/dist/utils/gas.mjs.map +1 -1
  24. package/dist/utils/simulation.cjs +2 -1
  25. package/dist/utils/simulation.cjs.map +1 -1
  26. package/dist/utils/simulation.d.cts +1 -1
  27. package/dist/utils/simulation.d.cts.map +1 -1
  28. package/dist/utils/simulation.d.mts +1 -1
  29. package/dist/utils/simulation.d.mts.map +1 -1
  30. package/dist/utils/simulation.mjs +2 -1
  31. package/dist/utils/simulation.mjs.map +1 -1
  32. package/dist/utils/validation.cjs +8 -18
  33. package/dist/utils/validation.cjs.map +1 -1
  34. package/dist/utils/validation.d.cts +1 -1
  35. package/dist/utils/validation.d.cts.map +1 -1
  36. package/dist/utils/validation.d.mts +1 -1
  37. package/dist/utils/validation.d.mts.map +1 -1
  38. package/dist/utils/validation.mjs +8 -18
  39. package/dist/utils/validation.mjs.map +1 -1
  40. package/package.json +3 -3
  41. package/dist/utils/simulation-api.cjs.map +0 -1
  42. package/dist/utils/simulation-api.d.cts.map +0 -1
  43. package/dist/utils/simulation-api.d.mts.map +0 -1
  44. package/dist/utils/simulation-api.mjs.map +0 -1
  45. /package/dist/{utils → api}/simulation-api.cjs +0 -0
  46. /package/dist/{utils → api}/simulation-api.mjs +0 -0
@@ -28,33 +28,23 @@ const TRANSACTION_ENVELOPE_TYPES_FEE_MARKET = [
28
28
  * @param options.type - The transaction type.
29
29
  * @throws Throws an error if the transaction is not permitted.
30
30
  */
31
- export async function validateTransactionOrigin({ data, from, internalAccounts, origin, permittedAddresses, selectedAddress, txParams, type, }) {
32
- const isInternal = origin === ORIGIN_METAMASK;
33
- const isExternal = origin && origin !== ORIGIN_METAMASK;
34
- const { authorizationList, to, type: envelopeType } = txParams;
35
- if (isInternal && from !== selectedAddress) {
36
- throw rpcErrors.internal({
37
- message: `Internally initiated transaction is using invalid account.`,
38
- data: {
39
- origin,
40
- fromAddress: from,
41
- selectedAddress,
42
- },
43
- });
31
+ export async function validateTransactionOrigin({ data, from, internalAccounts, origin, permittedAddresses, txParams, type, }) {
32
+ const isInternal = !origin || origin === ORIGIN_METAMASK;
33
+ if (isInternal) {
34
+ return;
44
35
  }
45
- if (isExternal && permittedAddresses && !permittedAddresses.includes(from)) {
36
+ const { authorizationList, to, type: envelopeType } = txParams;
37
+ if (permittedAddresses && !permittedAddresses.includes(from)) {
46
38
  throw providerErrors.unauthorized({ data: { origin } });
47
39
  }
48
40
  if (type === TransactionType.batch) {
49
41
  return;
50
42
  }
51
- if (isExternal &&
52
- (authorizationList || envelopeType === TransactionEnvelopeType.setCode)) {
43
+ if (authorizationList || envelopeType === TransactionEnvelopeType.setCode) {
53
44
  throw rpcErrors.invalidParams('External EIP-7702 transactions are not supported');
54
45
  }
55
46
  const hasData = Boolean(data && data !== '0x');
56
- if (isExternal &&
57
- hasData &&
47
+ if (hasData &&
58
48
  internalAccounts?.some((account) => account.toLowerCase() === to?.toLowerCase())) {
59
49
  throw rpcErrors.invalidParams('External transactions to internal accounts cannot include data');
60
50
  }
@@ -1 +1 @@
1
- {"version":3,"file":"validation.mjs","sourceRoot":"","sources":["../../src/utils/validation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,2BAA2B;AAC/C,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,mCAAmC;AAChF,OAAO,EAAE,QAAQ,EAAE,oCAAoC;AACvD,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,SAAS,EAAE,6BAA6B;AAE/E,OAAO,EAAE,iBAAiB,EAAE,QAAQ,EAAE,wBAAwB;AAE9D,OAAO,EAAE,oBAAoB,EAAE,oBAAgB;AAE/C,OAAO,EACL,uBAAuB,EACvB,eAAe,EAEhB,qBAAiB;AAElB,MAAM,CAAN,IAAY,SAGX;AAHD,WAAY,SAAS;IACnB,sEAAwB,CAAA;IACxB,gEAAqB,CAAA;AACvB,CAAC,EAHW,SAAS,KAAT,SAAS,QAGpB;AAED,MAAM,qCAAqC,GAAG;IAC5C,uBAAuB,CAAC,SAAS;IACjC,uBAAuB,CAAC,OAAO;CAChC,CAAC;AASF;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAAC,EAC9C,IAAI,EACJ,IAAI,EACJ,gBAAgB,EAChB,MAAM,EACN,kBAAkB,EAClB,eAAe,EACf,QAAQ,EACR,IAAI,GAUL;IACC,MAAM,UAAU,GAAG,MAAM,KAAK,eAAe,CAAC;IAC9C,MAAM,UAAU,GAAG,MAAM,IAAI,MAAM,KAAK,eAAe,CAAC;IACxD,MAAM,EAAE,iBAAiB,EAAE,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,GAAG,QAAQ,CAAC;IAE/D,IAAI,UAAU,IAAI,IAAI,KAAK,eAAe,EAAE;QAC1C,MAAM,SAAS,CAAC,QAAQ,CAAC;YACvB,OAAO,EAAE,4DAA4D;YACrE,IAAI,EAAE;gBACJ,MAAM;gBACN,WAAW,EAAE,IAAI;gBACjB,eAAe;aAChB;SACF,CAAC,CAAC;KACJ;IAED,IAAI,UAAU,IAAI,kBAAkB,IAAI,CAAC,kBAAkB,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE;QAC1E,MAAM,cAAc,CAAC,YAAY,CAAC,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC;KACzD;IAED,IAAI,IAAI,KAAK,eAAe,CAAC,KAAK,EAAE;QAClC,OAAO;KACR;IAED,IACE,UAAU;QACV,CAAC,iBAAiB,IAAI,YAAY,KAAK,uBAAuB,CAAC,OAAO,CAAC,EACvE;QACA,MAAM,SAAS,CAAC,aAAa,CAC3B,kDAAkD,CACnD,CAAC;KACH;IAED,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,IAAI,IAAI,KAAK,IAAI,CAAC,CAAC;IAE/C,IACE,UAAU;QACV,OAAO;QACP,gBAAgB,EAAE,IAAI,CACpB,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,WAAW,EAAE,KAAK,EAAE,EAAE,WAAW,EAAE,CACzD,EACD;QACA,MAAM,SAAS,CAAC,aAAa,CAC3B,gEAAgE,CACjE,CAAC;KACH;AACH,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,gBAAgB,CAC9B,QAA2B,EAC3B,mBAAmB,GAAG,IAAI,EAC1B,OAAa;IAEb,oBAAoB,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACpC,4BAA4B,CAAC,QAAQ,EAAE,mBAAmB,CAAC,CAAC;IAC5D,iBAAiB,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACjC,sBAAsB,CAAC,QAAQ,CAAC,CAAC;IACjC,kBAAkB,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IACnC,iBAAiB,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACjC,oBAAoB,CAAC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAChD,oBAAoB,CAAC,QAAQ,CAAC,CAAC;IAC/B,yBAAyB,CAAC,QAAQ,CAAC,CAAC;AACtC,CAAC;AAED;;;;;GAKG;AACH,SAAS,oBAAoB,CAAC,IAAwB;IACpD,IACE,IAAI;QACJ,CAAC,MAAM,CAAC,MAAM,CAAC,uBAAuB,CAAC,CAAC,QAAQ,CAC9C,IAA+B,CAChC,EACD;QACA,MAAM,SAAS,CAAC,aAAa,CAC3B,uCAAuC,IAAI,sBAAsB,MAAM,CAAC,MAAM,CAC5E,uBAAuB,CACxB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CACf,CAAC;KACH;AACH,CAAC;AAED;;;;;;GAMG;AACH,SAAS,4BAA4B,CACnC,QAA2B,EAC3B,mBAA4B;IAE5B,IAAI,oBAAoB,CAAC,QAAQ,CAAC,IAAI,CAAC,mBAAmB,EAAE;QAC1D,MAAM,SAAS,CAAC,aAAa,CAC3B,sHAAsH,CACvH,CAAC;KACH;AACH,CAAC;AAED;;;;;;;;;;GAUG;AACH,SAAS,kBAAkB,CAAC,KAAc;IACxC,IAAI,KAAK,KAAK,SAAS,EAAE;QACvB,IAAI,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE;YACvB,MAAM,SAAS,CAAC,aAAa,CAC3B,8BAA8B,KAAK,2BAA2B,CAC/D,CAAC;SACH;QAED,IAAI,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE;YACvB,MAAM,SAAS,CAAC,aAAa,CAC3B,8BAA8B,KAAK,2BAA2B,CAC/D,CAAC;SACH;QACD,MAAM,QAAQ,GAAG,QAAQ,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QACrC,MAAM,OAAO,GACX,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC;YACzB,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC;YACvB,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACrB,MAAM,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;QACjC,IAAI,CAAC,OAAO,EAAE;YACZ,MAAM,SAAS,CAAC,aAAa,CAC3B,6BAA6B,KAAK,kCAAkC,CACrE,CAAC;SACH;KACF;AACH,CAAC;AAED;;;;;;;;GAQG;AACH,SAAS,sBAAsB,CAAC,QAA2B;IACzD,IAAI,QAAQ,CAAC,EAAE,KAAK,IAAI,IAAI,QAAQ,CAAC,EAAE,KAAK,SAAS,EAAE;QACrD,IAAI,QAAQ,CAAC,IAAI,EAAE;YACjB,OAAO,QAAQ,CAAC,EAAE,CAAC;SACpB;aAAM;YACL,MAAM,SAAS,CAAC,aAAa,CAAC,uBAAuB,CAAC,CAAC;SACxD;KACF;SAAM,IAAI,QAAQ,CAAC,EAAE,KAAK,SAAS,IAAI,CAAC,iBAAiB,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE;QACvE,MAAM,SAAS,CAAC,aAAa,CAAC,uBAAuB,CAAC,CAAC;KACxD;AACH,CAAC;AAED;;;;;;;;GAQG;AACH,SAAS,iBAAiB,CAAC,IAAY;IACrC,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE;QACrC,MAAM,SAAS,CAAC,aAAa,CAC3B,0BAA0B,IAAI,iBAAiB,CAChD,CAAC;KACH;IACD,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,EAAE;QAC5B,MAAM,SAAS,CAAC,aAAa,CAAC,yBAAyB,CAAC,CAAC;KAC1D;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAAC,EAAW;IACzC,IAAI,CAAC,EAAE,IAAI,OAAO,EAAE,KAAK,QAAQ,EAAE;QACjC,MAAM,SAAS,CAAC,aAAa,CAAC,sBAAsB,CAAC,CAAC;KACvD;AACH,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,oBAAoB,CAAC,EACnC,gBAAgB,EAChB,OAAO,EACP,SAAS,GAKV;IACC,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;IAC3B,MAAM,UAAU,GAAG,MAAM,IAAI,MAAM,KAAK,eAAe,CAAC;IAExD,MAAM,0BAA0B,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAClE,OAAO,CAAC,WAAW,EAAE,CACtB,CAAC;IAEF,IACE,UAAU;QACV,OAAO,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,iBAAiB,EAAE,EAAE;YAC9C,MAAM,gBAAgB,GACpB,iBAAiB,CAAC,MAAM,CAAC,EAAE,EAAE,WAAW,EAAY,CAAC;YAEvD,MAAM,QAAQ,GAAG,iBAAiB,CAAC,MAAM,CAAC,IAAI,CAAC;YAE/C,MAAM,iBAAiB,GACrB,0BAA0B,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAC;YAExD,MAAM,OAAO,GAAG,OAAO,CAAC,QAAQ,IAAI,QAAQ,KAAK,IAAI,CAAC,CAAC;YAEvD,OAAO,iBAAiB,IAAI,OAAO,CAAC;QACtC,CAAC,CAAC,EACF;QACA,MAAM,SAAS,CAAC,aAAa,CAC3B,yDAAyD,CAC1D,CAAC;KACH;IAED,IAAI,UAAU,IAAI,OAAO,CAAC,YAAY,CAAC,MAAM,GAAG,SAAS,EAAE;QACzD,MAAM,IAAI,YAAY,CACpB,SAAS,CAAC,cAAc,EACxB,4BAA4B,SAAS,UAAU,OAAO,CAAC,YAAY,CAAC,MAAM,EAAE,CAC7E,CAAC;KACH;AACH,CAAC;AAED;;;;;GAKG;AACH,SAAS,iBAAiB,CAAC,KAAc;IACvC,IAAI,KAAK,EAAE;QACT,MAAM,cAAc,GAAG,IAAI,SAAS,CAAC,QAAQ,CAAC,CAAC;QAC/C,IAAI;YACF,cAAc,CAAC,gBAAgB,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;YACjD,gCAAgC;YAChC,8DAA8D;SAC/D;QAAC,OAAO,KAAU,EAAE;YACnB,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,iBAAiB,CAAC,EAAE;gBAC1C,MAAM,SAAS,CAAC,aAAa,CAC3B,iEAAiE,CAClE,CAAC;aACH;SACF;KACF;AACH,CAAC;AAED;;;;;GAKG;AACH,SAAS,oBAAoB,CAAC,aAAmB,EAAE,oBAA0B;IAC3E,IACE,aAAa;QACb,oBAAoB;QACpB,aAAa,CAAC,WAAW,EAAE,EAAE,KAAK,oBAAoB,CAAC,WAAW,EAAE,EACpE;QACA,MAAM,SAAS,CAAC,aAAa,CAC3B,2EAA2E,aAAa,eAAe,oBAAoB,EAAE,CAC9H,CAAC;KACH;AACH,CAAC;AAED;;;;GAIG;AACH,SAAS,oBAAoB,CAAC,QAA2B;IACvD,IAAI,QAAQ,CAAC,QAAQ,EAAE;QACrB,2CAA2C,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;QAClE,wCAAwC,CACtC,QAAQ,EACR,UAAU,EACV,cAAc,CACf,CAAC;QACF,wCAAwC,CACtC,QAAQ,EACR,UAAU,EACV,sBAAsB,CACvB,CAAC;QACF,qBAAqB,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;KAC7C;IAED,IAAI,QAAQ,CAAC,YAAY,EAAE;QACzB,2CAA2C,CAAC,QAAQ,EAAE,cAAc,CAAC,CAAC;QACtE,wCAAwC,CACtC,QAAQ,EACR,cAAc,EACd,UAAU,CACX,CAAC;QACF,qBAAqB,CAAC,QAAQ,EAAE,cAAc,CAAC,CAAC;KACjD;IAED,IAAI,QAAQ,CAAC,oBAAoB,EAAE;QACjC,2CAA2C,CACzC,QAAQ,EACR,sBAAsB,CACvB,CAAC;QACF,wCAAwC,CACtC,QAAQ,EACR,sBAAsB,EACtB,UAAU,CACX,CAAC;QACF,qBAAqB,CAAC,QAAQ,EAAE,sBAAsB,CAAC,CAAC;KACzD;IAED,IAAI,QAAQ,CAAC,QAAQ,EAAE;QACrB,qBAAqB,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;KAC7C;IAED,IAAI,QAAQ,CAAC,GAAG,EAAE;QAChB,qBAAqB,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;KACxC;AACH,CAAC;AAED;;;;;;;;;GASG;AACH,SAAS,2CAA2C,CAClD,QAA2B,EAC3B,KAA8B;IAE9B,MAAM,IAAI,GAAG,QAAQ,CAAC,IAA2C,CAAC;IAElE,QAAQ,KAAK,EAAE;QACb,KAAK,mBAAmB;YACtB,IAAI,IAAI,IAAI,IAAI,KAAK,uBAAuB,CAAC,OAAO,EAAE;gBACpD,MAAM,SAAS,CAAC,aAAa,CAC3B,sDAAsD,IAAI,qDAAqD,uBAAuB,CAAC,OAAO,GAAG,CAClJ,CAAC;aACH;YACD,MAAM;QACR,KAAK,cAAc,CAAC;QACpB,KAAK,sBAAsB;YACzB,IACE,IAAI;gBACJ,CAAC,qCAAqC,CAAC,QAAQ,CAC7C,IAA+B,CAChC,EACD;gBACA,MAAM,SAAS,CAAC,aAAa,CAC3B,sDAAsD,IAAI,yEAAyE,qCAAqC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CACvL,CAAC;aACH;YACD,MAAM;QACR,KAAK,UAAU,CAAC;QAChB;YACE,IACE,IAAI;gBACJ,qCAAqC,CAAC,QAAQ,CAC5C,IAA+B,CAChC,EACD;gBACA,MAAM,SAAS,CAAC,aAAa,CAC3B,sDAAsD,IAAI,4EAA4E,CACvI,CAAC;aACH;KACJ;AACH,CAAC;AAED;;;;;;;;;GASG;AACH,SAAS,wCAAwC,CAC/C,QAA2B,EAC3B,mBAAwC,EACxC,sBAA2C;IAE3C,IAAI,OAAO,QAAQ,CAAC,sBAAsB,CAAC,KAAK,WAAW,EAAE;QAC3D,MAAM,SAAS,CAAC,aAAa,CAC3B,yCAAyC,mBAAmB,sBAAsB,sBAAsB,yBAAyB,CAClI,CAAC;KACH;AACH,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,qBAAqB,CAAI,IAAO,EAAE,KAAc;IACvD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC;IAC1B,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,iBAAiB,CAAC,KAAK,CAAC,EAAE;QAC1D,MAAM,SAAS,CAAC,aAAa,CAC3B,+BAA+B,MAAM,CAAC,KAAK,CAAC,6CAA6C,MAAM,CAC7F,KAAK,CACN,GAAG,CACL,CAAC;KACH;AACH,CAAC;AAED;;;;GAIG;AACH,SAAS,yBAAyB,CAAC,QAA2B;IAC5D,MAAM,EAAE,iBAAiB,EAAE,GAAG,QAAQ,CAAC;IAEvC,IAAI,CAAC,iBAAiB,EAAE;QACtB,OAAO;KACR;IAED,2CAA2C,CAAC,QAAQ,EAAE,mBAAmB,CAAC,CAAC;IAE3E,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,iBAAiB,CAAC,EAAE;QACrC,MAAM,SAAS,CAAC,aAAa,CAC3B,gEAAgE,CACjE,CAAC;KACH;IAED,KAAK,MAAM,aAAa,IAAI,iBAAiB,EAAE;QAC7C,qBAAqB,CAAC,aAAa,CAAC,CAAC;KACtC;AACH,CAAC;AAED;;;;GAIG;AACH,SAAS,qBAAqB,CAAC,aAA4B;IACzD,qBAAqB,CAAC,aAAa,EAAE,SAAS,CAAC,CAAC;IAChD,iBAAiB,CAAC,aAAa,CAAC,OAAO,EAAE,EAAE,EAAE,SAAS,CAAC,CAAC;IAExD,KAAK,MAAM,KAAK,IAAI,CAAC,SAAS,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,CAAU,EAAE;QAC3D,IAAI,aAAa,CAAC,KAAK,CAAC,EAAE;YACxB,qBAAqB,CAAC,aAAa,EAAE,KAAK,CAAC,CAAC;SAC7C;KACF;IAED,MAAM,EAAE,OAAO,EAAE,GAAG,aAAa,CAAC;IAElC,IAAI,OAAO,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE;QAC/C,MAAM,SAAS,CAAC,aAAa,CAC3B,mEAAmE,OAAO,EAAE,CAC7E,CAAC;KACH;AACH,CAAC;AAED;;;;;;GAMG;AACH,SAAS,iBAAiB,CACxB,KAAa,EACb,WAAmB,EACnB,SAAiB;IAEjB,MAAM,iBAAiB,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;IAErD,IAAI,iBAAiB,KAAK,WAAW,EAAE;QACrC,MAAM,SAAS,CAAC,aAAa,CAC3B,+BAA+B,SAAS,YAAY,WAAW,gBAAgB,iBAAiB,QAAQ,CACzG,CAAC;KACH;AACH,CAAC","sourcesContent":["import { Interface } from '@ethersproject/abi';\nimport { ORIGIN_METAMASK, isValidHexAddress } from '@metamask/controller-utils';\nimport { abiERC20 } from '@metamask/metamask-eth-abis';\nimport { JsonRpcError, providerErrors, rpcErrors } from '@metamask/rpc-errors';\nimport type { Hex } from '@metamask/utils';\nimport { isStrictHexString, remove0x } from '@metamask/utils';\n\nimport { isEIP1559Transaction } from './utils';\nimport type { Authorization, TransactionBatchRequest } from '../types';\nimport {\n TransactionEnvelopeType,\n TransactionType,\n type TransactionParams,\n} from '../types';\n\nexport enum ErrorCode {\n DuplicateBundleId = 5720,\n BundleTooLarge = 5740,\n}\n\nconst TRANSACTION_ENVELOPE_TYPES_FEE_MARKET = [\n TransactionEnvelopeType.feeMarket,\n TransactionEnvelopeType.setCode,\n];\n\ntype GasFieldsToValidate =\n | 'gasPrice'\n | 'maxFeePerGas'\n | 'maxPriorityFeePerGas'\n | 'gas'\n | 'gasLimit';\n\n/**\n * Validates whether a transaction initiated by a specific 'from' address is permitted by the origin.\n *\n * @param options - Options bag.\n * @param options.data - The data included in the transaction.\n * @param options.from - The address from which the transaction is initiated.\n * @param options.internalAccounts - The internal accounts added to the wallet.\n * @param options.origin - The origin or source of the transaction.\n * @param options.permittedAddresses - The permitted accounts for the given origin.\n * @param options.selectedAddress - The currently selected Ethereum address in the wallet.\n * @param options.txParams - The transaction parameters.\n * @param options.type - The transaction type.\n * @throws Throws an error if the transaction is not permitted.\n */\nexport async function validateTransactionOrigin({\n data,\n from,\n internalAccounts,\n origin,\n permittedAddresses,\n selectedAddress,\n txParams,\n type,\n}: {\n data?: string;\n from: string;\n internalAccounts?: string[];\n origin?: string;\n permittedAddresses?: string[];\n selectedAddress?: string;\n txParams: TransactionParams;\n type?: TransactionType;\n}) {\n const isInternal = origin === ORIGIN_METAMASK;\n const isExternal = origin && origin !== ORIGIN_METAMASK;\n const { authorizationList, to, type: envelopeType } = txParams;\n\n if (isInternal && from !== selectedAddress) {\n throw rpcErrors.internal({\n message: `Internally initiated transaction is using invalid account.`,\n data: {\n origin,\n fromAddress: from,\n selectedAddress,\n },\n });\n }\n\n if (isExternal && permittedAddresses && !permittedAddresses.includes(from)) {\n throw providerErrors.unauthorized({ data: { origin } });\n }\n\n if (type === TransactionType.batch) {\n return;\n }\n\n if (\n isExternal &&\n (authorizationList || envelopeType === TransactionEnvelopeType.setCode)\n ) {\n throw rpcErrors.invalidParams(\n 'External EIP-7702 transactions are not supported',\n );\n }\n\n const hasData = Boolean(data && data !== '0x');\n\n if (\n isExternal &&\n hasData &&\n internalAccounts?.some(\n (account) => account.toLowerCase() === to?.toLowerCase(),\n )\n ) {\n throw rpcErrors.invalidParams(\n 'External transactions to internal accounts cannot include data',\n );\n }\n}\n\n/**\n * Validates the transaction params for required properties and throws in\n * the event of any validation error.\n *\n * @param txParams - Transaction params object to validate.\n * @param isEIP1559Compatible - whether or not the current network supports EIP-1559 transactions.\n * @param chainId - The chain ID of the transaction.\n */\nexport function validateTxParams(\n txParams: TransactionParams,\n isEIP1559Compatible = true,\n chainId?: Hex,\n) {\n validateEnvelopeType(txParams.type);\n validateEIP1559Compatibility(txParams, isEIP1559Compatible);\n validateParamFrom(txParams.from);\n validateParamRecipient(txParams);\n validateParamValue(txParams.value);\n validateParamData(txParams.data);\n validateParamChainId(txParams.chainId, chainId);\n validateGasFeeParams(txParams);\n validateAuthorizationList(txParams);\n}\n\n/**\n * Validates the `type` property, ensuring that if it is specified, it is a valid transaction envelope type.\n *\n * @param type - The transaction envelope type to validate.\n * @throws Throws invalid params if the type is not a valid transaction envelope type.\n */\nfunction validateEnvelopeType(type: string | undefined) {\n if (\n type &&\n !Object.values(TransactionEnvelopeType).includes(\n type as TransactionEnvelopeType,\n )\n ) {\n throw rpcErrors.invalidParams(\n `Invalid transaction envelope type: \"${type}\". Must be one of: ${Object.values(\n TransactionEnvelopeType,\n ).join(', ')}`,\n );\n }\n}\n\n/**\n * Validates EIP-1559 compatibility for transaction creation.\n *\n * @param txParams - The transaction parameters to validate.\n * @param isEIP1559Compatible - Indicates if the current network supports EIP-1559.\n * @throws Throws invalid params if the transaction specifies EIP-1559 but the network does not support it.\n */\nfunction validateEIP1559Compatibility(\n txParams: TransactionParams,\n isEIP1559Compatible: boolean,\n) {\n if (isEIP1559Transaction(txParams) && !isEIP1559Compatible) {\n throw rpcErrors.invalidParams(\n 'Invalid transaction params: params specify an EIP-1559 transaction but the current network does not support EIP-1559',\n );\n }\n}\n\n/**\n * Validates value property, ensuring it is a valid positive integer number\n * denominated in wei.\n *\n * @param value - The value to validate, expressed as a string.\n * @throws Throws an error if the value is not a valid positive integer\n * number denominated in wei.\n * - If the value contains a hyphen (-), it is considered invalid.\n * - If the value contains a decimal point (.), it is considered invalid.\n * - If the value is not a finite number, is NaN, or is not a safe integer, it is considered invalid.\n */\nfunction validateParamValue(value?: string) {\n if (value !== undefined) {\n if (value.includes('-')) {\n throw rpcErrors.invalidParams(\n `Invalid transaction value \"${value}\": not a positive number.`,\n );\n }\n\n if (value.includes('.')) {\n throw rpcErrors.invalidParams(\n `Invalid transaction value \"${value}\": number must be in wei.`,\n );\n }\n const intValue = parseInt(value, 10);\n const isValid =\n Number.isFinite(intValue) &&\n !Number.isNaN(intValue) &&\n !isNaN(Number(value)) &&\n Number.isSafeInteger(intValue);\n if (!isValid) {\n throw rpcErrors.invalidParams(\n `Invalid transaction value ${value}: number must be a valid number.`,\n );\n }\n }\n}\n\n/**\n * Validates the recipient address in a transaction's parameters.\n *\n * @param txParams - The transaction parameters object to validate.\n * @throws Throws an error if the recipient address is invalid:\n * - If the recipient address is an empty string ('0x') or undefined and the transaction contains data,\n * the \"to\" field is removed from the transaction parameters.\n * - If the recipient address is not a valid hexadecimal Ethereum address, an error is thrown.\n */\nfunction validateParamRecipient(txParams: TransactionParams) {\n if (txParams.to === '0x' || txParams.to === undefined) {\n if (txParams.data) {\n delete txParams.to;\n } else {\n throw rpcErrors.invalidParams(`Invalid \"to\" address.`);\n }\n } else if (txParams.to !== undefined && !isValidHexAddress(txParams.to)) {\n throw rpcErrors.invalidParams(`Invalid \"to\" address.`);\n }\n}\n\n/**\n * Validates the recipient address in a transaction's parameters.\n *\n * @param from - The from property to validate.\n * @throws Throws an error if the recipient address is invalid:\n * - If the recipient address is an empty string ('0x') or undefined and the transaction contains data,\n * the \"to\" field is removed from the transaction parameters.\n * - If the recipient address is not a valid hexadecimal Ethereum address, an error is thrown.\n */\nfunction validateParamFrom(from: string) {\n if (!from || typeof from !== 'string') {\n throw rpcErrors.invalidParams(\n `Invalid \"from\" address ${from}: not a string.`,\n );\n }\n if (!isValidHexAddress(from)) {\n throw rpcErrors.invalidParams('Invalid \"from\" address.');\n }\n}\n\n/**\n * Validates the recipient address in a transaction's parameters.\n *\n * @param to - The to property to validate.\n * @throws Throws an error if the recipient address is invalid.\n */\nexport function validateParamTo(to?: string) {\n if (!to || typeof to !== 'string') {\n throw rpcErrors.invalidParams(`Invalid \"to\" address`);\n }\n}\n\n/**\n * Validates a transaction batch request.\n *\n * @param options - Options bag.\n * @param options.internalAccounts - The internal accounts added to the wallet.\n * @param options.request - The batch request object.\n * @param options.sizeLimit - The maximum number of calls allowed in a batch request.\n */\nexport function validateBatchRequest({\n internalAccounts,\n request,\n sizeLimit,\n}: {\n internalAccounts: string[];\n request: TransactionBatchRequest;\n sizeLimit: number;\n}) {\n const { origin } = request;\n const isExternal = origin && origin !== ORIGIN_METAMASK;\n\n const internalAccountsNormalized = internalAccounts.map((account) =>\n account.toLowerCase(),\n );\n\n if (\n isExternal &&\n request.transactions.some((nestedTransaction) => {\n const normalizedCallTo =\n nestedTransaction.params.to?.toLowerCase() as string;\n\n const callData = nestedTransaction.params.data;\n\n const isInternalAccount =\n internalAccountsNormalized.includes(normalizedCallTo);\n\n const hasData = Boolean(callData && callData !== '0x');\n\n return isInternalAccount && hasData;\n })\n ) {\n throw rpcErrors.invalidParams(\n 'External calls to internal accounts cannot include data',\n );\n }\n\n if (isExternal && request.transactions.length > sizeLimit) {\n throw new JsonRpcError(\n ErrorCode.BundleTooLarge,\n `Batch size cannot exceed ${sizeLimit}. got: ${request.transactions.length}`,\n );\n }\n}\n\n/**\n * Validates input data for transactions.\n *\n * @param value - The input data to validate.\n * @throws Throws invalid params if the input data is invalid.\n */\nfunction validateParamData(value?: string) {\n if (value) {\n const ERC20Interface = new Interface(abiERC20);\n try {\n ERC20Interface.parseTransaction({ data: value });\n // TODO: Replace `any` with type\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n } catch (error: any) {\n if (error.message.match(/BUFFER_OVERRUN/u)) {\n throw rpcErrors.invalidParams(\n 'Invalid transaction params: data out-of-bounds, BUFFER_OVERRUN.',\n );\n }\n }\n }\n}\n\n/**\n * Validates chainId type.\n *\n * @param chainIdParams - The chain ID to validate.\n * @param chainIdNetworkClient - The chain ID of the network client.\n */\nfunction validateParamChainId(chainIdParams?: Hex, chainIdNetworkClient?: Hex) {\n if (\n chainIdParams &&\n chainIdNetworkClient &&\n chainIdParams.toLowerCase?.() !== chainIdNetworkClient.toLowerCase()\n ) {\n throw rpcErrors.invalidParams(\n `Invalid transaction params: chainId must match the network client, got: ${chainIdParams}, expected: ${chainIdNetworkClient}`,\n );\n }\n}\n\n/**\n * Validates gas values.\n *\n * @param txParams - The transaction parameters to validate.\n */\nfunction validateGasFeeParams(txParams: TransactionParams) {\n if (txParams.gasPrice) {\n ensureProperTransactionEnvelopeTypeProvided(txParams, 'gasPrice');\n ensureMutuallyExclusiveFieldsNotProvided(\n txParams,\n 'gasPrice',\n 'maxFeePerGas',\n );\n ensureMutuallyExclusiveFieldsNotProvided(\n txParams,\n 'gasPrice',\n 'maxPriorityFeePerGas',\n );\n ensureFieldIsValidHex(txParams, 'gasPrice');\n }\n\n if (txParams.maxFeePerGas) {\n ensureProperTransactionEnvelopeTypeProvided(txParams, 'maxFeePerGas');\n ensureMutuallyExclusiveFieldsNotProvided(\n txParams,\n 'maxFeePerGas',\n 'gasPrice',\n );\n ensureFieldIsValidHex(txParams, 'maxFeePerGas');\n }\n\n if (txParams.maxPriorityFeePerGas) {\n ensureProperTransactionEnvelopeTypeProvided(\n txParams,\n 'maxPriorityFeePerGas',\n );\n ensureMutuallyExclusiveFieldsNotProvided(\n txParams,\n 'maxPriorityFeePerGas',\n 'gasPrice',\n );\n ensureFieldIsValidHex(txParams, 'maxPriorityFeePerGas');\n }\n\n if (txParams.gasLimit) {\n ensureFieldIsValidHex(txParams, 'gasLimit');\n }\n\n if (txParams.gas) {\n ensureFieldIsValidHex(txParams, 'gas');\n }\n}\n\n/**\n * Ensures that the provided txParams has the proper 'type' specified for the\n * given field, if it is provided. If types do not match throws an\n * invalidParams error.\n *\n * @param txParams - The transaction parameters object\n * @param field - The current field being validated\n * @throws {ethErrors.rpc.invalidParams} Throws if type does not match the\n * expectations for provided field.\n */\nfunction ensureProperTransactionEnvelopeTypeProvided(\n txParams: TransactionParams,\n field: keyof TransactionParams,\n) {\n const type = txParams.type as TransactionEnvelopeType | undefined;\n\n switch (field) {\n case 'authorizationList':\n if (type && type !== TransactionEnvelopeType.setCode) {\n throw rpcErrors.invalidParams(\n `Invalid transaction envelope type: specified type \"${type}\" but including authorizationList requires type: \"${TransactionEnvelopeType.setCode}\"`,\n );\n }\n break;\n case 'maxFeePerGas':\n case 'maxPriorityFeePerGas':\n if (\n type &&\n !TRANSACTION_ENVELOPE_TYPES_FEE_MARKET.includes(\n type as TransactionEnvelopeType,\n )\n ) {\n throw rpcErrors.invalidParams(\n `Invalid transaction envelope type: specified type \"${type}\" but including maxFeePerGas and maxPriorityFeePerGas requires type: \"${TRANSACTION_ENVELOPE_TYPES_FEE_MARKET.join(', ')}\"`,\n );\n }\n break;\n case 'gasPrice':\n default:\n if (\n type &&\n TRANSACTION_ENVELOPE_TYPES_FEE_MARKET.includes(\n type as TransactionEnvelopeType,\n )\n ) {\n throw rpcErrors.invalidParams(\n `Invalid transaction envelope type: specified type \"${type}\" but included a gasPrice instead of maxFeePerGas and maxPriorityFeePerGas`,\n );\n }\n }\n}\n\n/**\n * Given two fields, ensure that the second field is not included in txParams,\n * and if it is throw an invalidParams error.\n *\n * @param txParams - The transaction parameters object\n * @param fieldBeingValidated - The current field being validated\n * @param mutuallyExclusiveField - The field to ensure is not provided\n * @throws {ethErrors.rpc.invalidParams} Throws if mutuallyExclusiveField is\n * present in txParams.\n */\nfunction ensureMutuallyExclusiveFieldsNotProvided(\n txParams: TransactionParams,\n fieldBeingValidated: GasFieldsToValidate,\n mutuallyExclusiveField: GasFieldsToValidate,\n) {\n if (typeof txParams[mutuallyExclusiveField] !== 'undefined') {\n throw rpcErrors.invalidParams(\n `Invalid transaction params: specified ${fieldBeingValidated} but also included ${mutuallyExclusiveField}, these cannot be mixed`,\n );\n }\n}\n\n/**\n * Ensures that the provided value for field is a valid hexadecimal.\n * Throws an invalidParams error if field is not a valid hexadecimal.\n *\n * @param data - The object containing the field\n * @param field - The current field being validated\n * @throws {rpcErrors.invalidParams} Throws if field is not a valid hexadecimal\n */\nfunction ensureFieldIsValidHex<T>(data: T, field: keyof T) {\n const value = data[field];\n if (typeof value !== 'string' || !isStrictHexString(value)) {\n throw rpcErrors.invalidParams(\n `Invalid transaction params: ${String(field)} is not a valid hexadecimal string. got: (${String(\n value,\n )})`,\n );\n }\n}\n\n/**\n * Validate the authorization list property in the transaction parameters.\n *\n * @param txParams - The transaction parameters containing the authorization list to validate.\n */\nfunction validateAuthorizationList(txParams: TransactionParams) {\n const { authorizationList } = txParams;\n\n if (!authorizationList) {\n return;\n }\n\n ensureProperTransactionEnvelopeTypeProvided(txParams, 'authorizationList');\n\n if (!Array.isArray(authorizationList)) {\n throw rpcErrors.invalidParams(\n `Invalid transaction params: authorizationList must be an array`,\n );\n }\n\n for (const authorization of authorizationList) {\n validateAuthorization(authorization);\n }\n}\n\n/**\n * Validate an authorization object.\n *\n * @param authorization - The authorization object to validate.\n */\nfunction validateAuthorization(authorization: Authorization) {\n ensureFieldIsValidHex(authorization, 'address');\n validateHexLength(authorization.address, 20, 'address');\n\n for (const field of ['chainId', 'nonce', 'r', 's'] as const) {\n if (authorization[field]) {\n ensureFieldIsValidHex(authorization, field);\n }\n }\n\n const { yParity } = authorization;\n\n if (yParity && !['0x', '0x1'].includes(yParity)) {\n throw rpcErrors.invalidParams(\n `Invalid transaction params: yParity must be '0x' or '0x1'. got: ${yParity}`,\n );\n }\n}\n\n/**\n * Validate the number of bytes in a hex string.\n *\n * @param value - The hex string to validate.\n * @param lengthBytes - The expected length in bytes.\n * @param fieldName - The name of the field being validated.\n */\nfunction validateHexLength(\n value: string,\n lengthBytes: number,\n fieldName: string,\n) {\n const actualLengthBytes = remove0x(value).length / 2;\n\n if (actualLengthBytes !== lengthBytes) {\n throw rpcErrors.invalidParams(\n `Invalid transaction params: ${fieldName} must be ${lengthBytes} bytes. got: ${actualLengthBytes} bytes`,\n );\n }\n}\n"]}
1
+ {"version":3,"file":"validation.mjs","sourceRoot":"","sources":["../../src/utils/validation.ts"],"names":[],"mappings":"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","sourcesContent":["import { Interface } from '@ethersproject/abi';\nimport { ORIGIN_METAMASK, isValidHexAddress } from '@metamask/controller-utils';\nimport { abiERC20 } from '@metamask/metamask-eth-abis';\nimport { JsonRpcError, providerErrors, rpcErrors } from '@metamask/rpc-errors';\nimport type { Hex } from '@metamask/utils';\nimport { isStrictHexString, remove0x } from '@metamask/utils';\n\nimport { isEIP1559Transaction } from './utils';\nimport type { Authorization, TransactionBatchRequest } from '../types';\nimport {\n TransactionEnvelopeType,\n TransactionType,\n type TransactionParams,\n} from '../types';\n\nexport enum ErrorCode {\n DuplicateBundleId = 5720,\n BundleTooLarge = 5740,\n}\n\nconst TRANSACTION_ENVELOPE_TYPES_FEE_MARKET = [\n TransactionEnvelopeType.feeMarket,\n TransactionEnvelopeType.setCode,\n];\n\ntype GasFieldsToValidate =\n | 'gasPrice'\n | 'maxFeePerGas'\n | 'maxPriorityFeePerGas'\n | 'gas'\n | 'gasLimit';\n\n/**\n * Validates whether a transaction initiated by a specific 'from' address is permitted by the origin.\n *\n * @param options - Options bag.\n * @param options.data - The data included in the transaction.\n * @param options.from - The address from which the transaction is initiated.\n * @param options.internalAccounts - The internal accounts added to the wallet.\n * @param options.origin - The origin or source of the transaction.\n * @param options.permittedAddresses - The permitted accounts for the given origin.\n * @param options.selectedAddress - The currently selected Ethereum address in the wallet.\n * @param options.txParams - The transaction parameters.\n * @param options.type - The transaction type.\n * @throws Throws an error if the transaction is not permitted.\n */\nexport async function validateTransactionOrigin({\n data,\n from,\n internalAccounts,\n origin,\n permittedAddresses,\n txParams,\n type,\n}: {\n data?: string;\n from: string;\n internalAccounts?: string[];\n origin?: string;\n permittedAddresses?: string[];\n selectedAddress?: string;\n txParams: TransactionParams;\n type?: TransactionType;\n}) {\n const isInternal = !origin || origin === ORIGIN_METAMASK;\n\n if (isInternal) {\n return;\n }\n\n const { authorizationList, to, type: envelopeType } = txParams;\n\n if (permittedAddresses && !permittedAddresses.includes(from)) {\n throw providerErrors.unauthorized({ data: { origin } });\n }\n\n if (type === TransactionType.batch) {\n return;\n }\n\n if (authorizationList || envelopeType === TransactionEnvelopeType.setCode) {\n throw rpcErrors.invalidParams(\n 'External EIP-7702 transactions are not supported',\n );\n }\n\n const hasData = Boolean(data && data !== '0x');\n\n if (\n hasData &&\n internalAccounts?.some(\n (account) => account.toLowerCase() === to?.toLowerCase(),\n )\n ) {\n throw rpcErrors.invalidParams(\n 'External transactions to internal accounts cannot include data',\n );\n }\n}\n\n/**\n * Validates the transaction params for required properties and throws in\n * the event of any validation error.\n *\n * @param txParams - Transaction params object to validate.\n * @param isEIP1559Compatible - whether or not the current network supports EIP-1559 transactions.\n * @param chainId - The chain ID of the transaction.\n */\nexport function validateTxParams(\n txParams: TransactionParams,\n isEIP1559Compatible = true,\n chainId?: Hex,\n) {\n validateEnvelopeType(txParams.type);\n validateEIP1559Compatibility(txParams, isEIP1559Compatible);\n validateParamFrom(txParams.from);\n validateParamRecipient(txParams);\n validateParamValue(txParams.value);\n validateParamData(txParams.data);\n validateParamChainId(txParams.chainId, chainId);\n validateGasFeeParams(txParams);\n validateAuthorizationList(txParams);\n}\n\n/**\n * Validates the `type` property, ensuring that if it is specified, it is a valid transaction envelope type.\n *\n * @param type - The transaction envelope type to validate.\n * @throws Throws invalid params if the type is not a valid transaction envelope type.\n */\nfunction validateEnvelopeType(type: string | undefined) {\n if (\n type &&\n !Object.values(TransactionEnvelopeType).includes(\n type as TransactionEnvelopeType,\n )\n ) {\n throw rpcErrors.invalidParams(\n `Invalid transaction envelope type: \"${type}\". Must be one of: ${Object.values(\n TransactionEnvelopeType,\n ).join(', ')}`,\n );\n }\n}\n\n/**\n * Validates EIP-1559 compatibility for transaction creation.\n *\n * @param txParams - The transaction parameters to validate.\n * @param isEIP1559Compatible - Indicates if the current network supports EIP-1559.\n * @throws Throws invalid params if the transaction specifies EIP-1559 but the network does not support it.\n */\nfunction validateEIP1559Compatibility(\n txParams: TransactionParams,\n isEIP1559Compatible: boolean,\n) {\n if (isEIP1559Transaction(txParams) && !isEIP1559Compatible) {\n throw rpcErrors.invalidParams(\n 'Invalid transaction params: params specify an EIP-1559 transaction but the current network does not support EIP-1559',\n );\n }\n}\n\n/**\n * Validates value property, ensuring it is a valid positive integer number\n * denominated in wei.\n *\n * @param value - The value to validate, expressed as a string.\n * @throws Throws an error if the value is not a valid positive integer\n * number denominated in wei.\n * - If the value contains a hyphen (-), it is considered invalid.\n * - If the value contains a decimal point (.), it is considered invalid.\n * - If the value is not a finite number, is NaN, or is not a safe integer, it is considered invalid.\n */\nfunction validateParamValue(value?: string) {\n if (value !== undefined) {\n if (value.includes('-')) {\n throw rpcErrors.invalidParams(\n `Invalid transaction value \"${value}\": not a positive number.`,\n );\n }\n\n if (value.includes('.')) {\n throw rpcErrors.invalidParams(\n `Invalid transaction value \"${value}\": number must be in wei.`,\n );\n }\n const intValue = parseInt(value, 10);\n const isValid =\n Number.isFinite(intValue) &&\n !Number.isNaN(intValue) &&\n !isNaN(Number(value)) &&\n Number.isSafeInteger(intValue);\n if (!isValid) {\n throw rpcErrors.invalidParams(\n `Invalid transaction value ${value}: number must be a valid number.`,\n );\n }\n }\n}\n\n/**\n * Validates the recipient address in a transaction's parameters.\n *\n * @param txParams - The transaction parameters object to validate.\n * @throws Throws an error if the recipient address is invalid:\n * - If the recipient address is an empty string ('0x') or undefined and the transaction contains data,\n * the \"to\" field is removed from the transaction parameters.\n * - If the recipient address is not a valid hexadecimal Ethereum address, an error is thrown.\n */\nfunction validateParamRecipient(txParams: TransactionParams) {\n if (txParams.to === '0x' || txParams.to === undefined) {\n if (txParams.data) {\n delete txParams.to;\n } else {\n throw rpcErrors.invalidParams(`Invalid \"to\" address.`);\n }\n } else if (txParams.to !== undefined && !isValidHexAddress(txParams.to)) {\n throw rpcErrors.invalidParams(`Invalid \"to\" address.`);\n }\n}\n\n/**\n * Validates the recipient address in a transaction's parameters.\n *\n * @param from - The from property to validate.\n * @throws Throws an error if the recipient address is invalid:\n * - If the recipient address is an empty string ('0x') or undefined and the transaction contains data,\n * the \"to\" field is removed from the transaction parameters.\n * - If the recipient address is not a valid hexadecimal Ethereum address, an error is thrown.\n */\nfunction validateParamFrom(from: string) {\n if (!from || typeof from !== 'string') {\n throw rpcErrors.invalidParams(\n `Invalid \"from\" address ${from}: not a string.`,\n );\n }\n if (!isValidHexAddress(from)) {\n throw rpcErrors.invalidParams('Invalid \"from\" address.');\n }\n}\n\n/**\n * Validates the recipient address in a transaction's parameters.\n *\n * @param to - The to property to validate.\n * @throws Throws an error if the recipient address is invalid.\n */\nexport function validateParamTo(to?: string) {\n if (!to || typeof to !== 'string') {\n throw rpcErrors.invalidParams(`Invalid \"to\" address`);\n }\n}\n\n/**\n * Validates a transaction batch request.\n *\n * @param options - Options bag.\n * @param options.internalAccounts - The internal accounts added to the wallet.\n * @param options.request - The batch request object.\n * @param options.sizeLimit - The maximum number of calls allowed in a batch request.\n */\nexport function validateBatchRequest({\n internalAccounts,\n request,\n sizeLimit,\n}: {\n internalAccounts: string[];\n request: TransactionBatchRequest;\n sizeLimit: number;\n}) {\n const { origin } = request;\n const isExternal = origin && origin !== ORIGIN_METAMASK;\n\n const internalAccountsNormalized = internalAccounts.map((account) =>\n account.toLowerCase(),\n );\n\n if (\n isExternal &&\n request.transactions.some((nestedTransaction) => {\n const normalizedCallTo =\n nestedTransaction.params.to?.toLowerCase() as string;\n\n const callData = nestedTransaction.params.data;\n\n const isInternalAccount =\n internalAccountsNormalized.includes(normalizedCallTo);\n\n const hasData = Boolean(callData && callData !== '0x');\n\n return isInternalAccount && hasData;\n })\n ) {\n throw rpcErrors.invalidParams(\n 'External calls to internal accounts cannot include data',\n );\n }\n\n if (isExternal && request.transactions.length > sizeLimit) {\n throw new JsonRpcError(\n ErrorCode.BundleTooLarge,\n `Batch size cannot exceed ${sizeLimit}. got: ${request.transactions.length}`,\n );\n }\n}\n\n/**\n * Validates input data for transactions.\n *\n * @param value - The input data to validate.\n * @throws Throws invalid params if the input data is invalid.\n */\nfunction validateParamData(value?: string) {\n if (value) {\n const ERC20Interface = new Interface(abiERC20);\n try {\n ERC20Interface.parseTransaction({ data: value });\n // TODO: Replace `any` with type\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n } catch (error: any) {\n if (error.message.match(/BUFFER_OVERRUN/u)) {\n throw rpcErrors.invalidParams(\n 'Invalid transaction params: data out-of-bounds, BUFFER_OVERRUN.',\n );\n }\n }\n }\n}\n\n/**\n * Validates chainId type.\n *\n * @param chainIdParams - The chain ID to validate.\n * @param chainIdNetworkClient - The chain ID of the network client.\n */\nfunction validateParamChainId(chainIdParams?: Hex, chainIdNetworkClient?: Hex) {\n if (\n chainIdParams &&\n chainIdNetworkClient &&\n chainIdParams.toLowerCase?.() !== chainIdNetworkClient.toLowerCase()\n ) {\n throw rpcErrors.invalidParams(\n `Invalid transaction params: chainId must match the network client, got: ${chainIdParams}, expected: ${chainIdNetworkClient}`,\n );\n }\n}\n\n/**\n * Validates gas values.\n *\n * @param txParams - The transaction parameters to validate.\n */\nfunction validateGasFeeParams(txParams: TransactionParams) {\n if (txParams.gasPrice) {\n ensureProperTransactionEnvelopeTypeProvided(txParams, 'gasPrice');\n ensureMutuallyExclusiveFieldsNotProvided(\n txParams,\n 'gasPrice',\n 'maxFeePerGas',\n );\n ensureMutuallyExclusiveFieldsNotProvided(\n txParams,\n 'gasPrice',\n 'maxPriorityFeePerGas',\n );\n ensureFieldIsValidHex(txParams, 'gasPrice');\n }\n\n if (txParams.maxFeePerGas) {\n ensureProperTransactionEnvelopeTypeProvided(txParams, 'maxFeePerGas');\n ensureMutuallyExclusiveFieldsNotProvided(\n txParams,\n 'maxFeePerGas',\n 'gasPrice',\n );\n ensureFieldIsValidHex(txParams, 'maxFeePerGas');\n }\n\n if (txParams.maxPriorityFeePerGas) {\n ensureProperTransactionEnvelopeTypeProvided(\n txParams,\n 'maxPriorityFeePerGas',\n );\n ensureMutuallyExclusiveFieldsNotProvided(\n txParams,\n 'maxPriorityFeePerGas',\n 'gasPrice',\n );\n ensureFieldIsValidHex(txParams, 'maxPriorityFeePerGas');\n }\n\n if (txParams.gasLimit) {\n ensureFieldIsValidHex(txParams, 'gasLimit');\n }\n\n if (txParams.gas) {\n ensureFieldIsValidHex(txParams, 'gas');\n }\n}\n\n/**\n * Ensures that the provided txParams has the proper 'type' specified for the\n * given field, if it is provided. If types do not match throws an\n * invalidParams error.\n *\n * @param txParams - The transaction parameters object\n * @param field - The current field being validated\n * @throws {ethErrors.rpc.invalidParams} Throws if type does not match the\n * expectations for provided field.\n */\nfunction ensureProperTransactionEnvelopeTypeProvided(\n txParams: TransactionParams,\n field: keyof TransactionParams,\n) {\n const type = txParams.type as TransactionEnvelopeType | undefined;\n\n switch (field) {\n case 'authorizationList':\n if (type && type !== TransactionEnvelopeType.setCode) {\n throw rpcErrors.invalidParams(\n `Invalid transaction envelope type: specified type \"${type}\" but including authorizationList requires type: \"${TransactionEnvelopeType.setCode}\"`,\n );\n }\n break;\n case 'maxFeePerGas':\n case 'maxPriorityFeePerGas':\n if (\n type &&\n !TRANSACTION_ENVELOPE_TYPES_FEE_MARKET.includes(\n type as TransactionEnvelopeType,\n )\n ) {\n throw rpcErrors.invalidParams(\n `Invalid transaction envelope type: specified type \"${type}\" but including maxFeePerGas and maxPriorityFeePerGas requires type: \"${TRANSACTION_ENVELOPE_TYPES_FEE_MARKET.join(', ')}\"`,\n );\n }\n break;\n case 'gasPrice':\n default:\n if (\n type &&\n TRANSACTION_ENVELOPE_TYPES_FEE_MARKET.includes(\n type as TransactionEnvelopeType,\n )\n ) {\n throw rpcErrors.invalidParams(\n `Invalid transaction envelope type: specified type \"${type}\" but included a gasPrice instead of maxFeePerGas and maxPriorityFeePerGas`,\n );\n }\n }\n}\n\n/**\n * Given two fields, ensure that the second field is not included in txParams,\n * and if it is throw an invalidParams error.\n *\n * @param txParams - The transaction parameters object\n * @param fieldBeingValidated - The current field being validated\n * @param mutuallyExclusiveField - The field to ensure is not provided\n * @throws {ethErrors.rpc.invalidParams} Throws if mutuallyExclusiveField is\n * present in txParams.\n */\nfunction ensureMutuallyExclusiveFieldsNotProvided(\n txParams: TransactionParams,\n fieldBeingValidated: GasFieldsToValidate,\n mutuallyExclusiveField: GasFieldsToValidate,\n) {\n if (typeof txParams[mutuallyExclusiveField] !== 'undefined') {\n throw rpcErrors.invalidParams(\n `Invalid transaction params: specified ${fieldBeingValidated} but also included ${mutuallyExclusiveField}, these cannot be mixed`,\n );\n }\n}\n\n/**\n * Ensures that the provided value for field is a valid hexadecimal.\n * Throws an invalidParams error if field is not a valid hexadecimal.\n *\n * @param data - The object containing the field\n * @param field - The current field being validated\n * @throws {rpcErrors.invalidParams} Throws if field is not a valid hexadecimal\n */\nfunction ensureFieldIsValidHex<T>(data: T, field: keyof T) {\n const value = data[field];\n if (typeof value !== 'string' || !isStrictHexString(value)) {\n throw rpcErrors.invalidParams(\n `Invalid transaction params: ${String(field)} is not a valid hexadecimal string. got: (${String(\n value,\n )})`,\n );\n }\n}\n\n/**\n * Validate the authorization list property in the transaction parameters.\n *\n * @param txParams - The transaction parameters containing the authorization list to validate.\n */\nfunction validateAuthorizationList(txParams: TransactionParams) {\n const { authorizationList } = txParams;\n\n if (!authorizationList) {\n return;\n }\n\n ensureProperTransactionEnvelopeTypeProvided(txParams, 'authorizationList');\n\n if (!Array.isArray(authorizationList)) {\n throw rpcErrors.invalidParams(\n `Invalid transaction params: authorizationList must be an array`,\n );\n }\n\n for (const authorization of authorizationList) {\n validateAuthorization(authorization);\n }\n}\n\n/**\n * Validate an authorization object.\n *\n * @param authorization - The authorization object to validate.\n */\nfunction validateAuthorization(authorization: Authorization) {\n ensureFieldIsValidHex(authorization, 'address');\n validateHexLength(authorization.address, 20, 'address');\n\n for (const field of ['chainId', 'nonce', 'r', 's'] as const) {\n if (authorization[field]) {\n ensureFieldIsValidHex(authorization, field);\n }\n }\n\n const { yParity } = authorization;\n\n if (yParity && !['0x', '0x1'].includes(yParity)) {\n throw rpcErrors.invalidParams(\n `Invalid transaction params: yParity must be '0x' or '0x1'. got: ${yParity}`,\n );\n }\n}\n\n/**\n * Validate the number of bytes in a hex string.\n *\n * @param value - The hex string to validate.\n * @param lengthBytes - The expected length in bytes.\n * @param fieldName - The name of the field being validated.\n */\nfunction validateHexLength(\n value: string,\n lengthBytes: number,\n fieldName: string,\n) {\n const actualLengthBytes = remove0x(value).length / 2;\n\n if (actualLengthBytes !== lengthBytes) {\n throw rpcErrors.invalidParams(\n `Invalid transaction params: ${fieldName} must be ${lengthBytes} bytes. got: ${actualLengthBytes} bytes`,\n );\n }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@metamask/transaction-controller",
3
- "version": "54.2.0",
3
+ "version": "54.4.0",
4
4
  "description": "Stores transactions alongside their periodically updated statuses and manages interactions such as approval and cancellation",
5
5
  "keywords": [
6
6
  "MetaMask",
@@ -54,7 +54,7 @@
54
54
  "@ethersproject/contracts": "^5.7.0",
55
55
  "@ethersproject/providers": "^5.7.0",
56
56
  "@ethersproject/wallet": "^5.7.0",
57
- "@metamask/base-controller": "^8.0.0",
57
+ "@metamask/base-controller": "^8.0.1",
58
58
  "@metamask/controller-utils": "^11.7.0",
59
59
  "@metamask/eth-query": "^4.0.0",
60
60
  "@metamask/metamask-eth-abis": "^3.1.1",
@@ -77,7 +77,7 @@
77
77
  "@metamask/eth-json-rpc-provider": "^4.1.8",
78
78
  "@metamask/ethjs-provider-http": "^0.3.0",
79
79
  "@metamask/gas-fee-controller": "^23.0.0",
80
- "@metamask/network-controller": "^23.2.0",
80
+ "@metamask/network-controller": "^23.3.0",
81
81
  "@metamask/remote-feature-flag-controller": "^1.6.0",
82
82
  "@types/bn.js": "^5.1.5",
83
83
  "@types/jest": "^27.4.1",
@@ -1 +0,0 @@
1
- {"version":3,"file":"simulation-api.cjs","sourceRoot":"","sources":["../../src/utils/simulation-api.ts"],"names":[],"mappings":";;;AAAA,iEAAiE;AACjE,2CAA+D;AAE/D,0CAA8E;AAC9E,0CAA0C;AAE1C,MAAM,GAAG,GAAG,IAAA,0BAAkB,EAAC,sBAAa,EAAE,gBAAgB,CAAC,CAAC;AAEhE,MAAM,UAAU,GAAG,6BAA6B,CAAC;AACjD,MAAM,QAAQ,GAAG,6CAA6C,CAAC;AAC/D,MAAM,iBAAiB,GAAG,UAAU,CAAC;AA0MrC,IAAI,gBAAgB,GAAG,CAAC,CAAC;AAEzB;;;;;;GAMG;AACI,KAAK,UAAU,oBAAoB,CACxC,OAAY,EACZ,OAA0B;IAE1B,MAAM,GAAG,GAAG,MAAM,gBAAgB,CAAC,OAAO,CAAC,CAAC;IAE5C,GAAG,CAAC,iBAAiB,EAAE,GAAG,EAAE,OAAO,CAAC,CAAC;IAErC,MAAM,SAAS,GAAG,gBAAgB,CAAC;IACnC,gBAAgB,IAAI,CAAC,CAAC;IAEtB,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;QAChC,MAAM,EAAE,MAAM;QACd,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;YACnB,EAAE,EAAE,MAAM,CAAC,SAAS,CAAC;YACrB,OAAO,EAAE,KAAK;YACd,MAAM,EAAE,UAAU;YAClB,MAAM,EAAE,CAAC,OAAO,CAAC;SAClB,CAAC;KACH,CAAC,CAAC;IAEH,MAAM,YAAY,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;IAE3C,GAAG,CAAC,mBAAmB,EAAE,YAAY,CAAC,CAAC;IAEvC,IAAI,YAAY,CAAC,KAAK,EAAE;QACtB,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,YAAY,CAAC,KAAK,CAAC;QAC7C,MAAM,IAAI,wBAAe,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;KAC1C;IAED,OAAO,YAAY,EAAE,MAAM,CAAC;AAC9B,CAAC;AA/BD,oDA+BC;AAED;;;;;GAKG;AACH,KAAK,UAAU,gBAAgB,CAAC,OAAY;IAC1C,MAAM,WAAW,GAAG,MAAM,cAAc,EAAE,CAAC;IAC3C,MAAM,cAAc,GAAG,IAAA,sCAAmB,EAAC,OAAO,CAAC,CAAC;IACpD,MAAM,OAAO,GAAG,WAAW,CAAC,cAAc,CAAC,CAAC;IAE5C,IAAI,CAAC,OAAO,EAAE,aAAa,EAAE;QAC3B,GAAG,CAAC,wBAAwB,EAAE,OAAO,CAAC,CAAC;QACvC,MAAM,IAAI,yCAAgC,CAAC,OAAO,CAAC,CAAC;KACrD;IAED,OAAO,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;AACjC,CAAC;AAED;;;;GAIG;AACH,KAAK,UAAU,cAAc;IAC3B,MAAM,GAAG,GAAG,GAAG,MAAM,CAAC,kBAAkB,CAAC,GAAG,iBAAiB,EAAE,CAAC;IAChE,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,CAAC;IAClC,OAAO,QAAQ,CAAC,IAAI,EAAE,CAAC;AACzB,CAAC;AAED;;;;;GAKG;AACH,SAAS,MAAM,CAAC,SAAiB;IAC/B,OAAO,QAAQ,CAAC,OAAO,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;AAC5C,CAAC","sourcesContent":["import { convertHexToDecimal } from '@metamask/controller-utils';\nimport { createModuleLogger, type Hex } from '@metamask/utils';\n\nimport { SimulationChainNotSupportedError, SimulationError } from '../errors';\nimport { projectLogger } from '../logger';\n\nconst log = createModuleLogger(projectLogger, 'simulation-api');\n\nconst RPC_METHOD = 'infura_simulateTransactions';\nconst BASE_URL = 'https://tx-sentinel-{0}.api.cx.metamask.io/';\nconst ENDPOINT_NETWORKS = 'networks';\n\n/** Single transaction to simulate in a simulation API request. */\nexport type SimulationRequestTransaction = {\n /** Data to send with the transaction. */\n data?: Hex;\n\n /** Sender of the transaction. */\n from: Hex;\n\n /** Gas limit for the transaction. */\n gas?: Hex;\n\n /** Maximum fee per gas for the transaction. */\n maxFeePerGas?: Hex;\n\n /** Maximum priority fee per gas for the transaction. */\n maxPriorityFeePerGas?: Hex;\n\n /** Recipient of the transaction. */\n to?: Hex;\n\n /** Value to send with the transaction. */\n value?: Hex;\n};\n\n/** Request to the simulation API to simulate transactions. */\nexport type SimulationRequest = {\n /**\n * Transactions to be sequentially simulated.\n * State changes impact subsequent transactions in the list.\n */\n transactions: SimulationRequestTransaction[];\n\n blockOverrides?: {\n time?: Hex;\n };\n\n /**\n * Overrides to the state of the blockchain, keyed by address.\n */\n overrides?: {\n [address: Hex]: {\n /** Override the code for an address. */\n code?: Hex;\n\n /** Overrides to the storage slots for an address. */\n stateDiff?: {\n [slot: Hex]: Hex;\n };\n };\n };\n\n /**\n * Whether to include available token fees.\n */\n suggestFees?: {\n /* Whether to include the native transfer if available. */\n withTransfer?: boolean;\n\n /* Whether to include the gas fee of the token transfer. */\n withFeeTransfer?: boolean;\n };\n\n /**\n * Whether to include call traces in the response.\n * Defaults to false.\n */\n withCallTrace?: boolean;\n\n /**\n * Whether to include event logs in the response.\n * Defaults to false.\n */\n withLogs?: boolean;\n};\n\n/** Raw event log emitted by a simulated transaction. */\nexport type SimulationResponseLog = {\n /** Address of the account that created the event. */\n address: Hex;\n\n /** Raw data in the event that is not indexed. */\n data: Hex;\n\n /** Raw indexed data from the event. */\n topics: Hex[];\n};\n\n/** Call trace of a single simulated transaction. */\nexport type SimulationResponseCallTrace = {\n /** Nested calls. */\n calls: SimulationResponseCallTrace[];\n\n /** Raw event logs created by the call. */\n logs: SimulationResponseLog[];\n};\n\n/**\n * Changes to the blockchain state.\n * Keyed by account address.\n */\nexport type SimulationResponseStateDiff = {\n [address: Hex]: {\n /** Native balance of the account. */\n balance?: Hex;\n\n /** Nonce of the account. */\n nonce?: Hex;\n\n /** Storage values per slot. */\n storage?: {\n [slot: Hex]: Hex;\n };\n };\n};\n\nexport type SimulationResponseTokenFee = {\n /** Token data independent of current transaction. */\n token: {\n /** Address of the token contract. */\n address: Hex;\n\n /** Decimals of the token. */\n decimals: number;\n\n /** Symbol of the token. */\n symbol: string;\n };\n\n /** Amount of tokens needed to pay for gas. */\n balanceNeededToken: Hex;\n\n /** Current token balance of sender. */\n currentBalanceToken: Hex;\n\n /** Account address that token should be transferred to. */\n feeRecipient: Hex;\n\n /** Conversation rate of 1 token to native WEI. */\n rateWei: Hex;\n};\n\n/** Response from the simulation API for a single transaction. */\nexport type SimulationResponseTransaction = {\n /** Hierarchy of call data including nested calls and logs. */\n callTrace?: SimulationResponseCallTrace;\n\n /** An error message indicating the transaction could not be simulated. */\n error?: string;\n\n /** Recommended gas fees for the transaction. */\n fees?: {\n /** Gas limit for the fee level. */\n gas: Hex;\n\n /** Maximum fee per gas for the fee level. */\n maxFeePerGas: Hex;\n\n /** Maximum priority fee per gas for the fee level. */\n maxPriorityFeePerGas: Hex;\n\n /** Token fee data for the fee level. */\n tokenFees: SimulationResponseTokenFee[];\n }[];\n\n /** The total gas used by the transaction. */\n gasUsed?: Hex;\n\n /** Return value of the transaction, such as the balance if calling balanceOf. */\n return: Hex;\n\n /** Changes to the blockchain state. */\n stateDiff?: {\n /** Initial blockchain state before the transaction. */\n pre?: SimulationResponseStateDiff;\n\n /** Updated blockchain state after the transaction. */\n post?: SimulationResponseStateDiff;\n };\n};\n\n/** Response from the simulation API. */\nexport type SimulationResponse = {\n /** Simulation data for each transaction in the request. */\n transactions: SimulationResponseTransaction[];\n};\n\n/** Data for a network supported by the Simulation API. */\ntype SimulationNetwork = {\n /** Subdomain of the API for the network. */\n network: string;\n\n /** Whether the network supports confirmation simulations. */\n confirmations: boolean;\n};\n\n/** Response from the simulation API containing supported networks. */\ntype SimulationNetworkResponse = {\n [chainIdDecimal: string]: SimulationNetwork;\n};\n\nlet requestIdCounter = 0;\n\n/**\n * Simulate transactions using the transaction simulation API.\n *\n * @param chainId - The chain ID to simulate transactions on.\n * @param request - The request to simulate transactions.\n * @returns The response from the simulation API.\n */\nexport async function simulateTransactions(\n chainId: Hex,\n request: SimulationRequest,\n): Promise<SimulationResponse> {\n const url = await getSimulationUrl(chainId);\n\n log('Sending request', url, request);\n\n const requestId = requestIdCounter;\n requestIdCounter += 1;\n\n const response = await fetch(url, {\n method: 'POST',\n body: JSON.stringify({\n id: String(requestId),\n jsonrpc: '2.0',\n method: RPC_METHOD,\n params: [request],\n }),\n });\n\n const responseJson = await response.json();\n\n log('Received response', responseJson);\n\n if (responseJson.error) {\n const { code, message } = responseJson.error;\n throw new SimulationError(message, code);\n }\n\n return responseJson?.result;\n}\n\n/**\n * Get the URL for the transaction simulation API.\n *\n * @param chainId - The chain ID to get the URL for.\n * @returns The URL for the transaction simulation API.\n */\nasync function getSimulationUrl(chainId: Hex): Promise<string> {\n const networkData = await getNetworkData();\n const chainIdDecimal = convertHexToDecimal(chainId);\n const network = networkData[chainIdDecimal];\n\n if (!network?.confirmations) {\n log('Chain is not supported', chainId);\n throw new SimulationChainNotSupportedError(chainId);\n }\n\n return getUrl(network.network);\n}\n\n/**\n * Retrieve the supported network data from the simulation API.\n *\n * @returns The network data response from the simulation API.\n */\nasync function getNetworkData(): Promise<SimulationNetworkResponse> {\n const url = `${getUrl('ethereum-mainnet')}${ENDPOINT_NETWORKS}`;\n const response = await fetch(url);\n return response.json();\n}\n\n/**\n * Generate the URL for the specified subdomain in the simulation API.\n *\n * @param subdomain - The subdomain to generate the URL for.\n * @returns The URL for the transaction simulation API.\n */\nfunction getUrl(subdomain: string): string {\n return BASE_URL.replace('{0}', subdomain);\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"file":"simulation-api.d.cts","sourceRoot":"","sources":["../../src/utils/simulation-api.ts"],"names":[],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"simulation-api.d.mts","sourceRoot":"","sources":["../../src/utils/simulation-api.ts"],"names":[],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"simulation-api.mjs","sourceRoot":"","sources":["../../src/utils/simulation-api.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,mCAAmC;AACjE,OAAO,EAAE,kBAAkB,EAAY,wBAAwB;AAE/D,OAAO,EAAE,gCAAgC,EAAE,eAAe,EAAE,sBAAkB;AAC9E,OAAO,EAAE,aAAa,EAAE,sBAAkB;AAE1C,MAAM,GAAG,GAAG,kBAAkB,CAAC,aAAa,EAAE,gBAAgB,CAAC,CAAC;AAEhE,MAAM,UAAU,GAAG,6BAA6B,CAAC;AACjD,MAAM,QAAQ,GAAG,6CAA6C,CAAC;AAC/D,MAAM,iBAAiB,GAAG,UAAU,CAAC;AA0MrC,IAAI,gBAAgB,GAAG,CAAC,CAAC;AAEzB;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,OAAY,EACZ,OAA0B;IAE1B,MAAM,GAAG,GAAG,MAAM,gBAAgB,CAAC,OAAO,CAAC,CAAC;IAE5C,GAAG,CAAC,iBAAiB,EAAE,GAAG,EAAE,OAAO,CAAC,CAAC;IAErC,MAAM,SAAS,GAAG,gBAAgB,CAAC;IACnC,gBAAgB,IAAI,CAAC,CAAC;IAEtB,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;QAChC,MAAM,EAAE,MAAM;QACd,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;YACnB,EAAE,EAAE,MAAM,CAAC,SAAS,CAAC;YACrB,OAAO,EAAE,KAAK;YACd,MAAM,EAAE,UAAU;YAClB,MAAM,EAAE,CAAC,OAAO,CAAC;SAClB,CAAC;KACH,CAAC,CAAC;IAEH,MAAM,YAAY,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;IAE3C,GAAG,CAAC,mBAAmB,EAAE,YAAY,CAAC,CAAC;IAEvC,IAAI,YAAY,CAAC,KAAK,EAAE;QACtB,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,YAAY,CAAC,KAAK,CAAC;QAC7C,MAAM,IAAI,eAAe,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;KAC1C;IAED,OAAO,YAAY,EAAE,MAAM,CAAC;AAC9B,CAAC;AAED;;;;;GAKG;AACH,KAAK,UAAU,gBAAgB,CAAC,OAAY;IAC1C,MAAM,WAAW,GAAG,MAAM,cAAc,EAAE,CAAC;IAC3C,MAAM,cAAc,GAAG,mBAAmB,CAAC,OAAO,CAAC,CAAC;IACpD,MAAM,OAAO,GAAG,WAAW,CAAC,cAAc,CAAC,CAAC;IAE5C,IAAI,CAAC,OAAO,EAAE,aAAa,EAAE;QAC3B,GAAG,CAAC,wBAAwB,EAAE,OAAO,CAAC,CAAC;QACvC,MAAM,IAAI,gCAAgC,CAAC,OAAO,CAAC,CAAC;KACrD;IAED,OAAO,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;AACjC,CAAC;AAED;;;;GAIG;AACH,KAAK,UAAU,cAAc;IAC3B,MAAM,GAAG,GAAG,GAAG,MAAM,CAAC,kBAAkB,CAAC,GAAG,iBAAiB,EAAE,CAAC;IAChE,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,CAAC;IAClC,OAAO,QAAQ,CAAC,IAAI,EAAE,CAAC;AACzB,CAAC;AAED;;;;;GAKG;AACH,SAAS,MAAM,CAAC,SAAiB;IAC/B,OAAO,QAAQ,CAAC,OAAO,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;AAC5C,CAAC","sourcesContent":["import { convertHexToDecimal } from '@metamask/controller-utils';\nimport { createModuleLogger, type Hex } from '@metamask/utils';\n\nimport { SimulationChainNotSupportedError, SimulationError } from '../errors';\nimport { projectLogger } from '../logger';\n\nconst log = createModuleLogger(projectLogger, 'simulation-api');\n\nconst RPC_METHOD = 'infura_simulateTransactions';\nconst BASE_URL = 'https://tx-sentinel-{0}.api.cx.metamask.io/';\nconst ENDPOINT_NETWORKS = 'networks';\n\n/** Single transaction to simulate in a simulation API request. */\nexport type SimulationRequestTransaction = {\n /** Data to send with the transaction. */\n data?: Hex;\n\n /** Sender of the transaction. */\n from: Hex;\n\n /** Gas limit for the transaction. */\n gas?: Hex;\n\n /** Maximum fee per gas for the transaction. */\n maxFeePerGas?: Hex;\n\n /** Maximum priority fee per gas for the transaction. */\n maxPriorityFeePerGas?: Hex;\n\n /** Recipient of the transaction. */\n to?: Hex;\n\n /** Value to send with the transaction. */\n value?: Hex;\n};\n\n/** Request to the simulation API to simulate transactions. */\nexport type SimulationRequest = {\n /**\n * Transactions to be sequentially simulated.\n * State changes impact subsequent transactions in the list.\n */\n transactions: SimulationRequestTransaction[];\n\n blockOverrides?: {\n time?: Hex;\n };\n\n /**\n * Overrides to the state of the blockchain, keyed by address.\n */\n overrides?: {\n [address: Hex]: {\n /** Override the code for an address. */\n code?: Hex;\n\n /** Overrides to the storage slots for an address. */\n stateDiff?: {\n [slot: Hex]: Hex;\n };\n };\n };\n\n /**\n * Whether to include available token fees.\n */\n suggestFees?: {\n /* Whether to include the native transfer if available. */\n withTransfer?: boolean;\n\n /* Whether to include the gas fee of the token transfer. */\n withFeeTransfer?: boolean;\n };\n\n /**\n * Whether to include call traces in the response.\n * Defaults to false.\n */\n withCallTrace?: boolean;\n\n /**\n * Whether to include event logs in the response.\n * Defaults to false.\n */\n withLogs?: boolean;\n};\n\n/** Raw event log emitted by a simulated transaction. */\nexport type SimulationResponseLog = {\n /** Address of the account that created the event. */\n address: Hex;\n\n /** Raw data in the event that is not indexed. */\n data: Hex;\n\n /** Raw indexed data from the event. */\n topics: Hex[];\n};\n\n/** Call trace of a single simulated transaction. */\nexport type SimulationResponseCallTrace = {\n /** Nested calls. */\n calls: SimulationResponseCallTrace[];\n\n /** Raw event logs created by the call. */\n logs: SimulationResponseLog[];\n};\n\n/**\n * Changes to the blockchain state.\n * Keyed by account address.\n */\nexport type SimulationResponseStateDiff = {\n [address: Hex]: {\n /** Native balance of the account. */\n balance?: Hex;\n\n /** Nonce of the account. */\n nonce?: Hex;\n\n /** Storage values per slot. */\n storage?: {\n [slot: Hex]: Hex;\n };\n };\n};\n\nexport type SimulationResponseTokenFee = {\n /** Token data independent of current transaction. */\n token: {\n /** Address of the token contract. */\n address: Hex;\n\n /** Decimals of the token. */\n decimals: number;\n\n /** Symbol of the token. */\n symbol: string;\n };\n\n /** Amount of tokens needed to pay for gas. */\n balanceNeededToken: Hex;\n\n /** Current token balance of sender. */\n currentBalanceToken: Hex;\n\n /** Account address that token should be transferred to. */\n feeRecipient: Hex;\n\n /** Conversation rate of 1 token to native WEI. */\n rateWei: Hex;\n};\n\n/** Response from the simulation API for a single transaction. */\nexport type SimulationResponseTransaction = {\n /** Hierarchy of call data including nested calls and logs. */\n callTrace?: SimulationResponseCallTrace;\n\n /** An error message indicating the transaction could not be simulated. */\n error?: string;\n\n /** Recommended gas fees for the transaction. */\n fees?: {\n /** Gas limit for the fee level. */\n gas: Hex;\n\n /** Maximum fee per gas for the fee level. */\n maxFeePerGas: Hex;\n\n /** Maximum priority fee per gas for the fee level. */\n maxPriorityFeePerGas: Hex;\n\n /** Token fee data for the fee level. */\n tokenFees: SimulationResponseTokenFee[];\n }[];\n\n /** The total gas used by the transaction. */\n gasUsed?: Hex;\n\n /** Return value of the transaction, such as the balance if calling balanceOf. */\n return: Hex;\n\n /** Changes to the blockchain state. */\n stateDiff?: {\n /** Initial blockchain state before the transaction. */\n pre?: SimulationResponseStateDiff;\n\n /** Updated blockchain state after the transaction. */\n post?: SimulationResponseStateDiff;\n };\n};\n\n/** Response from the simulation API. */\nexport type SimulationResponse = {\n /** Simulation data for each transaction in the request. */\n transactions: SimulationResponseTransaction[];\n};\n\n/** Data for a network supported by the Simulation API. */\ntype SimulationNetwork = {\n /** Subdomain of the API for the network. */\n network: string;\n\n /** Whether the network supports confirmation simulations. */\n confirmations: boolean;\n};\n\n/** Response from the simulation API containing supported networks. */\ntype SimulationNetworkResponse = {\n [chainIdDecimal: string]: SimulationNetwork;\n};\n\nlet requestIdCounter = 0;\n\n/**\n * Simulate transactions using the transaction simulation API.\n *\n * @param chainId - The chain ID to simulate transactions on.\n * @param request - The request to simulate transactions.\n * @returns The response from the simulation API.\n */\nexport async function simulateTransactions(\n chainId: Hex,\n request: SimulationRequest,\n): Promise<SimulationResponse> {\n const url = await getSimulationUrl(chainId);\n\n log('Sending request', url, request);\n\n const requestId = requestIdCounter;\n requestIdCounter += 1;\n\n const response = await fetch(url, {\n method: 'POST',\n body: JSON.stringify({\n id: String(requestId),\n jsonrpc: '2.0',\n method: RPC_METHOD,\n params: [request],\n }),\n });\n\n const responseJson = await response.json();\n\n log('Received response', responseJson);\n\n if (responseJson.error) {\n const { code, message } = responseJson.error;\n throw new SimulationError(message, code);\n }\n\n return responseJson?.result;\n}\n\n/**\n * Get the URL for the transaction simulation API.\n *\n * @param chainId - The chain ID to get the URL for.\n * @returns The URL for the transaction simulation API.\n */\nasync function getSimulationUrl(chainId: Hex): Promise<string> {\n const networkData = await getNetworkData();\n const chainIdDecimal = convertHexToDecimal(chainId);\n const network = networkData[chainIdDecimal];\n\n if (!network?.confirmations) {\n log('Chain is not supported', chainId);\n throw new SimulationChainNotSupportedError(chainId);\n }\n\n return getUrl(network.network);\n}\n\n/**\n * Retrieve the supported network data from the simulation API.\n *\n * @returns The network data response from the simulation API.\n */\nasync function getNetworkData(): Promise<SimulationNetworkResponse> {\n const url = `${getUrl('ethereum-mainnet')}${ENDPOINT_NETWORKS}`;\n const response = await fetch(url);\n return response.json();\n}\n\n/**\n * Generate the URL for the specified subdomain in the simulation API.\n *\n * @param subdomain - The subdomain to generate the URL for.\n * @returns The URL for the transaction simulation API.\n */\nfunction getUrl(subdomain: string): string {\n return BASE_URL.replace('{0}', subdomain);\n}\n"]}
File without changes
File without changes