@metamask/money-account-upgrade-controller 1.2.0 → 1.3.1

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/CHANGELOG.md CHANGED
@@ -7,6 +7,29 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [1.3.1]
11
+
12
+ ### Changed
13
+
14
+ - Bump `@metamask/keyring-controller` from `^25.3.0` to `^25.4.0` ([#8665](https://github.com/MetaMask/core/pull/8665))
15
+
16
+ ### Fixed
17
+
18
+ - Fix the ChompApiService:createUpgrade call in the EIP-7702 auth step, pasing correct arguments ([#8657](https://github.com/MetaMask/core/pull/8657))
19
+
20
+ ## [1.3.0]
21
+
22
+ ### Changed
23
+
24
+ - Bump `@metamask/chomp-api-service` from `^2.0.0` to `^3.0.0` ([#8651](https://github.com/MetaMask/core/pull/8651))
25
+ - Bump `@metamask/messenger` from `^1.1.1` to `^1.2.0` ([#8632](https://github.com/MetaMask/core/pull/8632))
26
+ - Bump `@metamask/keyring-controller` from `^25.2.0` to `^25.3.0` ([#8634](https://github.com/MetaMask/core/pull/8634))
27
+ - Bump `@metamask/network-controller` from `^30.0.1` to `^30.1.0` ([#8636](https://github.com/MetaMask/core/pull/8636))
28
+
29
+ ### Fixed
30
+
31
+ - Fix the associate-address step to detect the already-associated case via `status: 'active'`. ([#8635](https://github.com/MetaMask/core/pull/8635))
32
+
10
33
  ## [1.2.0]
11
34
 
12
35
  ### Changed
@@ -29,7 +52,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
29
52
 
30
53
  - Add `MoneyAccountUpgradeController` with `upgradeAccount` method ([#8426](https://github.com/MetaMask/core/pull/8426))
31
54
 
32
- [Unreleased]: https://github.com/MetaMask/core/compare/@metamask/money-account-upgrade-controller@1.2.0...HEAD
55
+ [Unreleased]: https://github.com/MetaMask/core/compare/@metamask/money-account-upgrade-controller@1.3.1...HEAD
56
+ [1.3.1]: https://github.com/MetaMask/core/compare/@metamask/money-account-upgrade-controller@1.3.0...@metamask/money-account-upgrade-controller@1.3.1
57
+ [1.3.0]: https://github.com/MetaMask/core/compare/@metamask/money-account-upgrade-controller@1.2.0...@metamask/money-account-upgrade-controller@1.3.0
33
58
  [1.2.0]: https://github.com/MetaMask/core/compare/@metamask/money-account-upgrade-controller@1.1.0...@metamask/money-account-upgrade-controller@1.2.0
34
59
  [1.1.0]: https://github.com/MetaMask/core/compare/@metamask/money-account-upgrade-controller@1.0.0...@metamask/money-account-upgrade-controller@1.1.0
35
60
  [1.0.0]: https://github.com/MetaMask/core/releases/tag/@metamask/money-account-upgrade-controller@1.0.0
@@ -1,7 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.associateAddressStep = void 0;
4
- const ALREADY_ASSOCIATED_STATUS = 'already_associated';
5
4
  /**
6
5
  * Associates the Money Account address with the user's CHOMP profile.
7
6
  *
@@ -9,10 +8,11 @@ const ALREADY_ASSOCIATED_STATUS = 'already_associated';
9
8
  * and submits the signature to CHOMP, which verifies the timestamp is fresh,
10
9
  * recovers the signer, and records the profile–address mapping.
11
10
  *
12
- * CHOMP responds with 201 and `status: 'created'` when the association is
13
- * made, and 409 with `status: 'already_associated'` when the address is
14
- * already linked to a profile. The service surfaces both responses, so this
15
- * step reports `'already-done'` for the 409 case and `'completed'` otherwise.
11
+ * CHOMP responds with 201 and `status: 'created'` when a new association is
12
+ * made, and 409 with `status: 'active'` when the address is already
13
+ * associated with the authenticated profile. The service surfaces both
14
+ * responses, so this step reports `'already-done'` for the 409 case and
15
+ * `'completed'` otherwise.
16
16
  */
17
17
  exports.associateAddressStep = {
18
18
  name: 'associate-address',
@@ -25,7 +25,7 @@ exports.associateAddressStep = {
25
25
  timestamp,
26
26
  address,
27
27
  });
28
- if (response.status === ALREADY_ASSOCIATED_STATUS) {
28
+ if (response.status === 'active') {
29
29
  return 'already-done';
30
30
  }
31
31
  return 'completed';
@@ -1 +1 @@
1
- {"version":3,"file":"associate-address.cjs","sourceRoot":"","sources":["../../src/steps/associate-address.ts"],"names":[],"mappings":";;;AAIA,MAAM,yBAAyB,GAAG,oBAAoB,CAAC;AAEvD;;;;;;;;;;;GAWG;AACU,QAAA,oBAAoB,GAAS;IACxC,IAAI,EAAE,mBAAmB;IACzB,KAAK,CAAC,GAAG,CAAC,EAAE,SAAS,EAAE,OAAO,EAAE;QAC9B,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC7B,MAAM,OAAO,GAAG,wBAAwB,SAAS,EAAE,CAAC;QAEpD,MAAM,SAAS,GAAG,CAAC,MAAM,SAAS,CAAC,IAAI,CACrC,uCAAuC,EACvC,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CACjC,CAAQ,CAAC;QAEV,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,IAAI,CAAC,kCAAkC,EAAE;YACxE,SAAS;YACT,SAAS;YACT,OAAO;SACR,CAAC,CAAC;QAEH,IAAI,QAAQ,CAAC,MAAM,KAAK,yBAAyB,EAAE,CAAC;YAClD,OAAO,cAAc,CAAC;QACxB,CAAC;QAED,OAAO,WAAW,CAAC;IACrB,CAAC;CACF,CAAC","sourcesContent":["import type { Hex } from '@metamask/utils';\n\nimport type { Step } from './step';\n\nconst ALREADY_ASSOCIATED_STATUS = 'already_associated';\n\n/**\n * Associates the Money Account address with the user's CHOMP profile.\n *\n * Signs `CHOMP Authentication {timestamp}` (EIP-191) with the account's key\n * and submits the signature to CHOMP, which verifies the timestamp is fresh,\n * recovers the signer, and records the profile–address mapping.\n *\n * CHOMP responds with 201 and `status: 'created'` when the association is\n * made, and 409 with `status: 'already_associated'` when the address is\n * already linked to a profile. The service surfaces both responses, so this\n * step reports `'already-done'` for the 409 case and `'completed'` otherwise.\n */\nexport const associateAddressStep: Step = {\n name: 'associate-address',\n async run({ messenger, address }) {\n const timestamp = Date.now();\n const message = `CHOMP Authentication ${timestamp}`;\n\n const signature = (await messenger.call(\n 'KeyringController:signPersonalMessage',\n { data: message, from: address },\n )) as Hex;\n\n const response = await messenger.call('ChompApiService:associateAddress', {\n signature,\n timestamp,\n address,\n });\n\n if (response.status === ALREADY_ASSOCIATED_STATUS) {\n return 'already-done';\n }\n\n return 'completed';\n },\n};\n"]}
1
+ {"version":3,"file":"associate-address.cjs","sourceRoot":"","sources":["../../src/steps/associate-address.ts"],"names":[],"mappings":";;;AAIA;;;;;;;;;;;;GAYG;AACU,QAAA,oBAAoB,GAAS;IACxC,IAAI,EAAE,mBAAmB;IACzB,KAAK,CAAC,GAAG,CAAC,EAAE,SAAS,EAAE,OAAO,EAAE;QAC9B,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC7B,MAAM,OAAO,GAAG,wBAAwB,SAAS,EAAE,CAAC;QAEpD,MAAM,SAAS,GAAG,CAAC,MAAM,SAAS,CAAC,IAAI,CACrC,uCAAuC,EACvC,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CACjC,CAAQ,CAAC;QAEV,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,IAAI,CAAC,kCAAkC,EAAE;YACxE,SAAS;YACT,SAAS;YACT,OAAO;SACR,CAAC,CAAC;QAEH,IAAI,QAAQ,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;YACjC,OAAO,cAAc,CAAC;QACxB,CAAC;QAED,OAAO,WAAW,CAAC;IACrB,CAAC;CACF,CAAC","sourcesContent":["import type { Hex } from '@metamask/utils';\n\nimport type { Step } from './step';\n\n/**\n * Associates the Money Account address with the user's CHOMP profile.\n *\n * Signs `CHOMP Authentication {timestamp}` (EIP-191) with the account's key\n * and submits the signature to CHOMP, which verifies the timestamp is fresh,\n * recovers the signer, and records the profile–address mapping.\n *\n * CHOMP responds with 201 and `status: 'created'` when a new association is\n * made, and 409 with `status: 'active'` when the address is already\n * associated with the authenticated profile. The service surfaces both\n * responses, so this step reports `'already-done'` for the 409 case and\n * `'completed'` otherwise.\n */\nexport const associateAddressStep: Step = {\n name: 'associate-address',\n async run({ messenger, address }) {\n const timestamp = Date.now();\n const message = `CHOMP Authentication ${timestamp}`;\n\n const signature = (await messenger.call(\n 'KeyringController:signPersonalMessage',\n { data: message, from: address },\n )) as Hex;\n\n const response = await messenger.call('ChompApiService:associateAddress', {\n signature,\n timestamp,\n address,\n });\n\n if (response.status === 'active') {\n return 'already-done';\n }\n\n return 'completed';\n },\n};\n"]}
@@ -6,10 +6,11 @@ import type { Step } from "./step.cjs";
6
6
  * and submits the signature to CHOMP, which verifies the timestamp is fresh,
7
7
  * recovers the signer, and records the profile–address mapping.
8
8
  *
9
- * CHOMP responds with 201 and `status: 'created'` when the association is
10
- * made, and 409 with `status: 'already_associated'` when the address is
11
- * already linked to a profile. The service surfaces both responses, so this
12
- * step reports `'already-done'` for the 409 case and `'completed'` otherwise.
9
+ * CHOMP responds with 201 and `status: 'created'` when a new association is
10
+ * made, and 409 with `status: 'active'` when the address is already
11
+ * associated with the authenticated profile. The service surfaces both
12
+ * responses, so this step reports `'already-done'` for the 409 case and
13
+ * `'completed'` otherwise.
13
14
  */
14
15
  export declare const associateAddressStep: Step;
15
16
  //# sourceMappingURL=associate-address.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"associate-address.d.cts","sourceRoot":"","sources":["../../src/steps/associate-address.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,IAAI,EAAE,mBAAe;AAInC;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,oBAAoB,EAAE,IAuBlC,CAAC"}
1
+ {"version":3,"file":"associate-address.d.cts","sourceRoot":"","sources":["../../src/steps/associate-address.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,IAAI,EAAE,mBAAe;AAEnC;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,oBAAoB,EAAE,IAuBlC,CAAC"}
@@ -6,10 +6,11 @@ import type { Step } from "./step.mjs";
6
6
  * and submits the signature to CHOMP, which verifies the timestamp is fresh,
7
7
  * recovers the signer, and records the profile–address mapping.
8
8
  *
9
- * CHOMP responds with 201 and `status: 'created'` when the association is
10
- * made, and 409 with `status: 'already_associated'` when the address is
11
- * already linked to a profile. The service surfaces both responses, so this
12
- * step reports `'already-done'` for the 409 case and `'completed'` otherwise.
9
+ * CHOMP responds with 201 and `status: 'created'` when a new association is
10
+ * made, and 409 with `status: 'active'` when the address is already
11
+ * associated with the authenticated profile. The service surfaces both
12
+ * responses, so this step reports `'already-done'` for the 409 case and
13
+ * `'completed'` otherwise.
13
14
  */
14
15
  export declare const associateAddressStep: Step;
15
16
  //# sourceMappingURL=associate-address.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"associate-address.d.mts","sourceRoot":"","sources":["../../src/steps/associate-address.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,IAAI,EAAE,mBAAe;AAInC;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,oBAAoB,EAAE,IAuBlC,CAAC"}
1
+ {"version":3,"file":"associate-address.d.mts","sourceRoot":"","sources":["../../src/steps/associate-address.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,IAAI,EAAE,mBAAe;AAEnC;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,oBAAoB,EAAE,IAuBlC,CAAC"}
@@ -1,4 +1,3 @@
1
- const ALREADY_ASSOCIATED_STATUS = 'already_associated';
2
1
  /**
3
2
  * Associates the Money Account address with the user's CHOMP profile.
4
3
  *
@@ -6,10 +5,11 @@ const ALREADY_ASSOCIATED_STATUS = 'already_associated';
6
5
  * and submits the signature to CHOMP, which verifies the timestamp is fresh,
7
6
  * recovers the signer, and records the profile–address mapping.
8
7
  *
9
- * CHOMP responds with 201 and `status: 'created'` when the association is
10
- * made, and 409 with `status: 'already_associated'` when the address is
11
- * already linked to a profile. The service surfaces both responses, so this
12
- * step reports `'already-done'` for the 409 case and `'completed'` otherwise.
8
+ * CHOMP responds with 201 and `status: 'created'` when a new association is
9
+ * made, and 409 with `status: 'active'` when the address is already
10
+ * associated with the authenticated profile. The service surfaces both
11
+ * responses, so this step reports `'already-done'` for the 409 case and
12
+ * `'completed'` otherwise.
13
13
  */
14
14
  export const associateAddressStep = {
15
15
  name: 'associate-address',
@@ -22,7 +22,7 @@ export const associateAddressStep = {
22
22
  timestamp,
23
23
  address,
24
24
  });
25
- if (response.status === ALREADY_ASSOCIATED_STATUS) {
25
+ if (response.status === 'active') {
26
26
  return 'already-done';
27
27
  }
28
28
  return 'completed';
@@ -1 +1 @@
1
- {"version":3,"file":"associate-address.mjs","sourceRoot":"","sources":["../../src/steps/associate-address.ts"],"names":[],"mappings":"AAIA,MAAM,yBAAyB,GAAG,oBAAoB,CAAC;AAEvD;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAS;IACxC,IAAI,EAAE,mBAAmB;IACzB,KAAK,CAAC,GAAG,CAAC,EAAE,SAAS,EAAE,OAAO,EAAE;QAC9B,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC7B,MAAM,OAAO,GAAG,wBAAwB,SAAS,EAAE,CAAC;QAEpD,MAAM,SAAS,GAAG,CAAC,MAAM,SAAS,CAAC,IAAI,CACrC,uCAAuC,EACvC,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CACjC,CAAQ,CAAC;QAEV,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,IAAI,CAAC,kCAAkC,EAAE;YACxE,SAAS;YACT,SAAS;YACT,OAAO;SACR,CAAC,CAAC;QAEH,IAAI,QAAQ,CAAC,MAAM,KAAK,yBAAyB,EAAE,CAAC;YAClD,OAAO,cAAc,CAAC;QACxB,CAAC;QAED,OAAO,WAAW,CAAC;IACrB,CAAC;CACF,CAAC","sourcesContent":["import type { Hex } from '@metamask/utils';\n\nimport type { Step } from './step';\n\nconst ALREADY_ASSOCIATED_STATUS = 'already_associated';\n\n/**\n * Associates the Money Account address with the user's CHOMP profile.\n *\n * Signs `CHOMP Authentication {timestamp}` (EIP-191) with the account's key\n * and submits the signature to CHOMP, which verifies the timestamp is fresh,\n * recovers the signer, and records the profile–address mapping.\n *\n * CHOMP responds with 201 and `status: 'created'` when the association is\n * made, and 409 with `status: 'already_associated'` when the address is\n * already linked to a profile. The service surfaces both responses, so this\n * step reports `'already-done'` for the 409 case and `'completed'` otherwise.\n */\nexport const associateAddressStep: Step = {\n name: 'associate-address',\n async run({ messenger, address }) {\n const timestamp = Date.now();\n const message = `CHOMP Authentication ${timestamp}`;\n\n const signature = (await messenger.call(\n 'KeyringController:signPersonalMessage',\n { data: message, from: address },\n )) as Hex;\n\n const response = await messenger.call('ChompApiService:associateAddress', {\n signature,\n timestamp,\n address,\n });\n\n if (response.status === ALREADY_ASSOCIATED_STATUS) {\n return 'already-done';\n }\n\n return 'completed';\n },\n};\n"]}
1
+ {"version":3,"file":"associate-address.mjs","sourceRoot":"","sources":["../../src/steps/associate-address.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAS;IACxC,IAAI,EAAE,mBAAmB;IACzB,KAAK,CAAC,GAAG,CAAC,EAAE,SAAS,EAAE,OAAO,EAAE;QAC9B,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC7B,MAAM,OAAO,GAAG,wBAAwB,SAAS,EAAE,CAAC;QAEpD,MAAM,SAAS,GAAG,CAAC,MAAM,SAAS,CAAC,IAAI,CACrC,uCAAuC,EACvC,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CACjC,CAAQ,CAAC;QAEV,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,IAAI,CAAC,kCAAkC,EAAE;YACxE,SAAS;YACT,SAAS;YACT,OAAO;SACR,CAAC,CAAC;QAEH,IAAI,QAAQ,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;YACjC,OAAO,cAAc,CAAC;QACxB,CAAC;QAED,OAAO,WAAW,CAAC;IACrB,CAAC;CACF,CAAC","sourcesContent":["import type { Hex } from '@metamask/utils';\n\nimport type { Step } from './step';\n\n/**\n * Associates the Money Account address with the user's CHOMP profile.\n *\n * Signs `CHOMP Authentication {timestamp}` (EIP-191) with the account's key\n * and submits the signature to CHOMP, which verifies the timestamp is fresh,\n * recovers the signer, and records the profile–address mapping.\n *\n * CHOMP responds with 201 and `status: 'created'` when a new association is\n * made, and 409 with `status: 'active'` when the address is already\n * associated with the authenticated profile. The service surfaces both\n * responses, so this step reports `'already-done'` for the 409 case and\n * `'completed'` otherwise.\n */\nexport const associateAddressStep: Step = {\n name: 'associate-address',\n async run({ messenger, address }) {\n const timestamp = Date.now();\n const message = `CHOMP Authentication ${timestamp}`;\n\n const signature = (await messenger.call(\n 'KeyringController:signPersonalMessage',\n { data: message, from: address },\n )) as Hex;\n\n const response = await messenger.call('ChompApiService:associateAddress', {\n signature,\n timestamp,\n address,\n });\n\n if (response.status === 'active') {\n return 'already-done';\n }\n\n return 'completed';\n },\n};\n"]}
@@ -58,9 +58,9 @@ exports.eip7702AuthorizationStep = {
58
58
  s,
59
59
  v,
60
60
  yParity,
61
- address,
62
- chainId: chainIdDecimal.toString(),
63
- nonce: nonce.toString(),
61
+ address: delegatorImplAddress,
62
+ chainId,
63
+ nonce: (0, utils_1.add0x)(nonce.toString(16)),
64
64
  });
65
65
  return 'completed';
66
66
  },
@@ -1 +1 @@
1
- {"version":3,"file":"eip-7702-authorization.cjs","sourceRoot":"","sources":["../../src/steps/eip-7702-authorization.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Provider } from '@metamask/network-controller';\nimport { add0x, isStrictHexString } from '@metamask/utils';\nimport type { Hex } from '@metamask/utils';\n\nimport type { Step, StepContext } from './step';\n\nconst EIP_7702_DELEGATION_PREFIX = '0xef0100';\n// '0x' (2) + 'ef0100' (6) + 20-byte address (40) = 48 characters.\nconst EIP_7702_DELEGATED_CODE_LENGTH = 48;\n\n// 65-byte signature: 32-byte r + 32-byte s + 1-byte v.\n// '0x' (2) + 32 bytes (64) + 32 bytes (64) + 1 byte (2) = 132 characters.\nconst SIGNATURE_HEX_LENGTH = 132;\n// '0x' + 32-byte r = 66 characters.\nconst R_END_INDEX = 66;\n// r (66 chars) + 32-byte s (64 chars) = 130 characters.\nconst S_END_INDEX = 130;\nconst V_END_INDEX = SIGNATURE_HEX_LENGTH;\n// v = 27 means yParity = 0; v = 28 means yParity = 1.\nconst V_BASE = 27;\n\n/**\n * Submits the EIP-7702 delegation-slot authorization to CHOMP so the Money\n * Account can be upgraded to a smart account pointed at the configured\n * delegator impl.\n *\n * The step:\n *\n * 1. Reads the account's on-chain code. If it is already delegated to the\n * configured `delegatorImplAddress`, reports `'already-done'`. If it is\n * delegated to a different address, throws rather than silently\n * overwriting an existing delegation.\n * 2. Fetches the account's current on-chain transaction count — CHOMP\n * validates the nonce matches when it applies the authorization.\n * 3. Signs the EIP-7702 authorization `{ chainId, delegatorImpl, nonce }`\n * with the Money Account's key via the keyring.\n * 4. Splits the 65-byte signature into `r`, `s`, `v`, `yParity` and submits\n * it to `POST /v1/account-upgrade`.\n */\nexport const eip7702AuthorizationStep: Step = {\n name: 'eip-7702-authorization',\n async run({ messenger, address, chainId, delegatorImplAddress }) {\n const provider = getProvider(messenger, chainId);\n\n const existingDelegation = await fetchDelegationAddress(provider, address);\n if (existingDelegation !== undefined) {\n if (existingDelegation === delegatorImplAddress.toLowerCase()) {\n return 'already-done';\n }\n throw new Error(\n `Account ${address} is already upgraded to another smart account: ${existingDelegation}.`,\n );\n }\n\n const chainIdDecimal = parseInt(chainId, 16);\n const nonce = await fetchNonce(provider, address);\n\n const signature = await messenger.call(\n 'KeyringController:signEip7702Authorization',\n {\n chainId: chainIdDecimal,\n contractAddress: delegatorImplAddress,\n nonce,\n from: address,\n },\n );\n\n const { r, s, v, yParity } = splitEip7702Signature(signature);\n\n await messenger.call('ChompApiService:createUpgrade', {\n r,\n s,\n v,\n yParity,\n address,\n chainId: chainIdDecimal.toString(),\n nonce: nonce.toString(),\n });\n\n return 'completed';\n },\n};\n\n/**\n * Splits a 65-byte ECDSA signature produced by\n * `KeyringController:signEip7702Authorization` into its `r`, `s`, `v`\n * components and derives `yParity` (`0` for `v = 27`, `1` for `v = 28`).\n *\n * @param signature - A 0x-prefixed 132-character hex string. Accepted in any\n * case; normalized to lowercase before validation.\n * @returns The signature components.\n */\nfunction splitEip7702Signature(signature: unknown): {\n r: Hex;\n s: Hex;\n v: number;\n yParity: 0 | 1;\n} {\n const normalized =\n typeof signature === 'string' ? signature.toLowerCase() : signature;\n\n if (\n !isStrictHexString(normalized) ||\n normalized.length !== SIGNATURE_HEX_LENGTH\n ) {\n throw new Error(\n `Expected a 0x-prefixed 65-byte signature from signEip7702Authorization, got ${JSON.stringify(signature)}`,\n );\n }\n\n // eslint-disable-next-line id-length\n const v = parseInt(normalized.slice(S_END_INDEX, V_END_INDEX), 16);\n if (v !== 27 && v !== 28) {\n throw new Error(\n `Expected v to be 27 or 28 in signEip7702Authorization signature, got ${v}`,\n );\n }\n\n return {\n r: normalized.slice(0, R_END_INDEX) as Hex,\n s: add0x(normalized.slice(R_END_INDEX, S_END_INDEX)),\n v,\n yParity: v === V_BASE ? 0 : 1,\n };\n}\n\n/**\n * Reads the account's on-chain code and, if the account is currently\n * delegated via EIP-7702, returns the implementation address the delegation\n * points at. Returns `undefined` if the account has no code (a plain EOA).\n * Throws if the code is present but not a valid EIP-7702 delegation, since\n * that means the address is a regular contract and is not eligible for\n * upgrade.\n *\n * @param provider - JSON-RPC provider for the target chain.\n * @param address - The Money Account address.\n * @returns The current delegation address, or `undefined` if none.\n */\nasync function fetchDelegationAddress(\n provider: Provider,\n address: Hex,\n): Promise<Hex | undefined> {\n const code = await provider.request({\n method: 'eth_getCode',\n params: [address, 'latest'],\n });\n\n if (typeof code !== 'string' || !code.startsWith('0x')) {\n throw new Error(\n `Expected 0x-prefixed hex string from eth_getCode, got ${JSON.stringify(code)}`,\n );\n }\n\n const normalized = code.toLowerCase();\n\n if (normalized === '0x') {\n return undefined;\n }\n\n if (\n normalized.length === EIP_7702_DELEGATED_CODE_LENGTH &&\n normalized.startsWith(EIP_7702_DELEGATION_PREFIX)\n ) {\n return add0x(normalized.slice(EIP_7702_DELEGATION_PREFIX.length));\n }\n\n throw new Error(\n `Account ${address} has unexpected on-chain code; expected either no code or an EIP-7702 delegation.`,\n );\n}\n\n/**\n * Fetches the current on-chain transaction count for the given address by\n * issuing an `eth_getTransactionCount` RPC request.\n *\n * @param provider - JSON-RPC provider for the target chain.\n * @param address - The Money Account address.\n * @returns The current nonce as a decimal number.\n */\nasync function fetchNonce(provider: Provider, address: Hex): Promise<number> {\n const nonceHex = await provider.request({\n method: 'eth_getTransactionCount',\n params: [address, 'latest'],\n });\n\n if (!isStrictHexString(nonceHex)) {\n throw new Error(\n `Expected hex string from eth_getTransactionCount, got ${JSON.stringify(nonceHex)}`,\n );\n }\n\n return parseInt(nonceHex, 16);\n}\n\n/**\n * Resolves the JSON-RPC provider for the given chain via NetworkController.\n *\n * @param messenger - The upgrade controller messenger.\n * @param chainId - The chain to query.\n * @returns The provider for that chain.\n */\nfunction getProvider(\n messenger: StepContext['messenger'],\n chainId: Hex,\n): Provider {\n const networkClientId = messenger.call(\n 'NetworkController:findNetworkClientIdByChainId',\n chainId,\n );\n return messenger.call(\n 'NetworkController:getNetworkClientById',\n networkClientId,\n ).provider;\n}\n"]}
1
+ {"version":3,"file":"eip-7702-authorization.cjs","sourceRoot":"","sources":["../../src/steps/eip-7702-authorization.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Provider } from '@metamask/network-controller';\nimport { add0x, isStrictHexString } from '@metamask/utils';\nimport type { Hex } from '@metamask/utils';\n\nimport type { Step, StepContext } from './step';\n\nconst EIP_7702_DELEGATION_PREFIX = '0xef0100';\n// '0x' (2) + 'ef0100' (6) + 20-byte address (40) = 48 characters.\nconst EIP_7702_DELEGATED_CODE_LENGTH = 48;\n\n// 65-byte signature: 32-byte r + 32-byte s + 1-byte v.\n// '0x' (2) + 32 bytes (64) + 32 bytes (64) + 1 byte (2) = 132 characters.\nconst SIGNATURE_HEX_LENGTH = 132;\n// '0x' + 32-byte r = 66 characters.\nconst R_END_INDEX = 66;\n// r (66 chars) + 32-byte s (64 chars) = 130 characters.\nconst S_END_INDEX = 130;\nconst V_END_INDEX = SIGNATURE_HEX_LENGTH;\n// v = 27 means yParity = 0; v = 28 means yParity = 1.\nconst V_BASE = 27;\n\n/**\n * Submits the EIP-7702 delegation-slot authorization to CHOMP so the Money\n * Account can be upgraded to a smart account pointed at the configured\n * delegator impl.\n *\n * The step:\n *\n * 1. Reads the account's on-chain code. If it is already delegated to the\n * configured `delegatorImplAddress`, reports `'already-done'`. If it is\n * delegated to a different address, throws rather than silently\n * overwriting an existing delegation.\n * 2. Fetches the account's current on-chain transaction count — CHOMP\n * validates the nonce matches when it applies the authorization.\n * 3. Signs the EIP-7702 authorization `{ chainId, delegatorImpl, nonce }`\n * with the Money Account's key via the keyring.\n * 4. Splits the 65-byte signature into `r`, `s`, `v`, `yParity` and submits\n * it to `POST /v1/account-upgrade`.\n */\nexport const eip7702AuthorizationStep: Step = {\n name: 'eip-7702-authorization',\n async run({ messenger, address, chainId, delegatorImplAddress }) {\n const provider = getProvider(messenger, chainId);\n\n const existingDelegation = await fetchDelegationAddress(provider, address);\n if (existingDelegation !== undefined) {\n if (existingDelegation === delegatorImplAddress.toLowerCase()) {\n return 'already-done';\n }\n throw new Error(\n `Account ${address} is already upgraded to another smart account: ${existingDelegation}.`,\n );\n }\n\n const chainIdDecimal = parseInt(chainId, 16);\n const nonce = await fetchNonce(provider, address);\n\n const signature = await messenger.call(\n 'KeyringController:signEip7702Authorization',\n {\n chainId: chainIdDecimal,\n contractAddress: delegatorImplAddress,\n nonce,\n from: address,\n },\n );\n\n const { r, s, v, yParity } = splitEip7702Signature(signature);\n\n await messenger.call('ChompApiService:createUpgrade', {\n r,\n s,\n v,\n yParity,\n address: delegatorImplAddress,\n chainId,\n nonce: add0x(nonce.toString(16)),\n });\n\n return 'completed';\n },\n};\n\n/**\n * Splits a 65-byte ECDSA signature produced by\n * `KeyringController:signEip7702Authorization` into its `r`, `s`, `v`\n * components and derives `yParity` (`0` for `v = 27`, `1` for `v = 28`).\n *\n * @param signature - A 0x-prefixed 132-character hex string. Accepted in any\n * case; normalized to lowercase before validation.\n * @returns The signature components.\n */\nfunction splitEip7702Signature(signature: unknown): {\n r: Hex;\n s: Hex;\n v: number;\n yParity: 0 | 1;\n} {\n const normalized =\n typeof signature === 'string' ? signature.toLowerCase() : signature;\n\n if (\n !isStrictHexString(normalized) ||\n normalized.length !== SIGNATURE_HEX_LENGTH\n ) {\n throw new Error(\n `Expected a 0x-prefixed 65-byte signature from signEip7702Authorization, got ${JSON.stringify(signature)}`,\n );\n }\n\n // eslint-disable-next-line id-length\n const v = parseInt(normalized.slice(S_END_INDEX, V_END_INDEX), 16);\n if (v !== 27 && v !== 28) {\n throw new Error(\n `Expected v to be 27 or 28 in signEip7702Authorization signature, got ${v}`,\n );\n }\n\n return {\n r: normalized.slice(0, R_END_INDEX) as Hex,\n s: add0x(normalized.slice(R_END_INDEX, S_END_INDEX)),\n v,\n yParity: v === V_BASE ? 0 : 1,\n };\n}\n\n/**\n * Reads the account's on-chain code and, if the account is currently\n * delegated via EIP-7702, returns the implementation address the delegation\n * points at. Returns `undefined` if the account has no code (a plain EOA).\n * Throws if the code is present but not a valid EIP-7702 delegation, since\n * that means the address is a regular contract and is not eligible for\n * upgrade.\n *\n * @param provider - JSON-RPC provider for the target chain.\n * @param address - The Money Account address.\n * @returns The current delegation address, or `undefined` if none.\n */\nasync function fetchDelegationAddress(\n provider: Provider,\n address: Hex,\n): Promise<Hex | undefined> {\n const code = await provider.request({\n method: 'eth_getCode',\n params: [address, 'latest'],\n });\n\n if (typeof code !== 'string' || !code.startsWith('0x')) {\n throw new Error(\n `Expected 0x-prefixed hex string from eth_getCode, got ${JSON.stringify(code)}`,\n );\n }\n\n const normalized = code.toLowerCase();\n\n if (normalized === '0x') {\n return undefined;\n }\n\n if (\n normalized.length === EIP_7702_DELEGATED_CODE_LENGTH &&\n normalized.startsWith(EIP_7702_DELEGATION_PREFIX)\n ) {\n return add0x(normalized.slice(EIP_7702_DELEGATION_PREFIX.length));\n }\n\n throw new Error(\n `Account ${address} has unexpected on-chain code; expected either no code or an EIP-7702 delegation.`,\n );\n}\n\n/**\n * Fetches the current on-chain transaction count for the given address by\n * issuing an `eth_getTransactionCount` RPC request.\n *\n * @param provider - JSON-RPC provider for the target chain.\n * @param address - The Money Account address.\n * @returns The current nonce as a decimal number.\n */\nasync function fetchNonce(provider: Provider, address: Hex): Promise<number> {\n const nonceHex = await provider.request({\n method: 'eth_getTransactionCount',\n params: [address, 'latest'],\n });\n\n if (!isStrictHexString(nonceHex)) {\n throw new Error(\n `Expected hex string from eth_getTransactionCount, got ${JSON.stringify(nonceHex)}`,\n );\n }\n\n return parseInt(nonceHex, 16);\n}\n\n/**\n * Resolves the JSON-RPC provider for the given chain via NetworkController.\n *\n * @param messenger - The upgrade controller messenger.\n * @param chainId - The chain to query.\n * @returns The provider for that chain.\n */\nfunction getProvider(\n messenger: StepContext['messenger'],\n chainId: Hex,\n): Provider {\n const networkClientId = messenger.call(\n 'NetworkController:findNetworkClientIdByChainId',\n chainId,\n );\n return messenger.call(\n 'NetworkController:getNetworkClientById',\n networkClientId,\n ).provider;\n}\n"]}
@@ -55,9 +55,9 @@ export const eip7702AuthorizationStep = {
55
55
  s,
56
56
  v,
57
57
  yParity,
58
- address,
59
- chainId: chainIdDecimal.toString(),
60
- nonce: nonce.toString(),
58
+ address: delegatorImplAddress,
59
+ chainId,
60
+ nonce: add0x(nonce.toString(16)),
61
61
  });
62
62
  return 'completed';
63
63
  },
@@ -1 +1 @@
1
- {"version":3,"file":"eip-7702-authorization.mjs","sourceRoot":"","sources":["../../src/steps/eip-7702-authorization.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Provider } from '@metamask/network-controller';\nimport { add0x, isStrictHexString } from '@metamask/utils';\nimport type { Hex } from '@metamask/utils';\n\nimport type { Step, StepContext } from './step';\n\nconst EIP_7702_DELEGATION_PREFIX = '0xef0100';\n// '0x' (2) + 'ef0100' (6) + 20-byte address (40) = 48 characters.\nconst EIP_7702_DELEGATED_CODE_LENGTH = 48;\n\n// 65-byte signature: 32-byte r + 32-byte s + 1-byte v.\n// '0x' (2) + 32 bytes (64) + 32 bytes (64) + 1 byte (2) = 132 characters.\nconst SIGNATURE_HEX_LENGTH = 132;\n// '0x' + 32-byte r = 66 characters.\nconst R_END_INDEX = 66;\n// r (66 chars) + 32-byte s (64 chars) = 130 characters.\nconst S_END_INDEX = 130;\nconst V_END_INDEX = SIGNATURE_HEX_LENGTH;\n// v = 27 means yParity = 0; v = 28 means yParity = 1.\nconst V_BASE = 27;\n\n/**\n * Submits the EIP-7702 delegation-slot authorization to CHOMP so the Money\n * Account can be upgraded to a smart account pointed at the configured\n * delegator impl.\n *\n * The step:\n *\n * 1. Reads the account's on-chain code. If it is already delegated to the\n * configured `delegatorImplAddress`, reports `'already-done'`. If it is\n * delegated to a different address, throws rather than silently\n * overwriting an existing delegation.\n * 2. Fetches the account's current on-chain transaction count — CHOMP\n * validates the nonce matches when it applies the authorization.\n * 3. Signs the EIP-7702 authorization `{ chainId, delegatorImpl, nonce }`\n * with the Money Account's key via the keyring.\n * 4. Splits the 65-byte signature into `r`, `s`, `v`, `yParity` and submits\n * it to `POST /v1/account-upgrade`.\n */\nexport const eip7702AuthorizationStep: Step = {\n name: 'eip-7702-authorization',\n async run({ messenger, address, chainId, delegatorImplAddress }) {\n const provider = getProvider(messenger, chainId);\n\n const existingDelegation = await fetchDelegationAddress(provider, address);\n if (existingDelegation !== undefined) {\n if (existingDelegation === delegatorImplAddress.toLowerCase()) {\n return 'already-done';\n }\n throw new Error(\n `Account ${address} is already upgraded to another smart account: ${existingDelegation}.`,\n );\n }\n\n const chainIdDecimal = parseInt(chainId, 16);\n const nonce = await fetchNonce(provider, address);\n\n const signature = await messenger.call(\n 'KeyringController:signEip7702Authorization',\n {\n chainId: chainIdDecimal,\n contractAddress: delegatorImplAddress,\n nonce,\n from: address,\n },\n );\n\n const { r, s, v, yParity } = splitEip7702Signature(signature);\n\n await messenger.call('ChompApiService:createUpgrade', {\n r,\n s,\n v,\n yParity,\n address,\n chainId: chainIdDecimal.toString(),\n nonce: nonce.toString(),\n });\n\n return 'completed';\n },\n};\n\n/**\n * Splits a 65-byte ECDSA signature produced by\n * `KeyringController:signEip7702Authorization` into its `r`, `s`, `v`\n * components and derives `yParity` (`0` for `v = 27`, `1` for `v = 28`).\n *\n * @param signature - A 0x-prefixed 132-character hex string. Accepted in any\n * case; normalized to lowercase before validation.\n * @returns The signature components.\n */\nfunction splitEip7702Signature(signature: unknown): {\n r: Hex;\n s: Hex;\n v: number;\n yParity: 0 | 1;\n} {\n const normalized =\n typeof signature === 'string' ? signature.toLowerCase() : signature;\n\n if (\n !isStrictHexString(normalized) ||\n normalized.length !== SIGNATURE_HEX_LENGTH\n ) {\n throw new Error(\n `Expected a 0x-prefixed 65-byte signature from signEip7702Authorization, got ${JSON.stringify(signature)}`,\n );\n }\n\n // eslint-disable-next-line id-length\n const v = parseInt(normalized.slice(S_END_INDEX, V_END_INDEX), 16);\n if (v !== 27 && v !== 28) {\n throw new Error(\n `Expected v to be 27 or 28 in signEip7702Authorization signature, got ${v}`,\n );\n }\n\n return {\n r: normalized.slice(0, R_END_INDEX) as Hex,\n s: add0x(normalized.slice(R_END_INDEX, S_END_INDEX)),\n v,\n yParity: v === V_BASE ? 0 : 1,\n };\n}\n\n/**\n * Reads the account's on-chain code and, if the account is currently\n * delegated via EIP-7702, returns the implementation address the delegation\n * points at. Returns `undefined` if the account has no code (a plain EOA).\n * Throws if the code is present but not a valid EIP-7702 delegation, since\n * that means the address is a regular contract and is not eligible for\n * upgrade.\n *\n * @param provider - JSON-RPC provider for the target chain.\n * @param address - The Money Account address.\n * @returns The current delegation address, or `undefined` if none.\n */\nasync function fetchDelegationAddress(\n provider: Provider,\n address: Hex,\n): Promise<Hex | undefined> {\n const code = await provider.request({\n method: 'eth_getCode',\n params: [address, 'latest'],\n });\n\n if (typeof code !== 'string' || !code.startsWith('0x')) {\n throw new Error(\n `Expected 0x-prefixed hex string from eth_getCode, got ${JSON.stringify(code)}`,\n );\n }\n\n const normalized = code.toLowerCase();\n\n if (normalized === '0x') {\n return undefined;\n }\n\n if (\n normalized.length === EIP_7702_DELEGATED_CODE_LENGTH &&\n normalized.startsWith(EIP_7702_DELEGATION_PREFIX)\n ) {\n return add0x(normalized.slice(EIP_7702_DELEGATION_PREFIX.length));\n }\n\n throw new Error(\n `Account ${address} has unexpected on-chain code; expected either no code or an EIP-7702 delegation.`,\n );\n}\n\n/**\n * Fetches the current on-chain transaction count for the given address by\n * issuing an `eth_getTransactionCount` RPC request.\n *\n * @param provider - JSON-RPC provider for the target chain.\n * @param address - The Money Account address.\n * @returns The current nonce as a decimal number.\n */\nasync function fetchNonce(provider: Provider, address: Hex): Promise<number> {\n const nonceHex = await provider.request({\n method: 'eth_getTransactionCount',\n params: [address, 'latest'],\n });\n\n if (!isStrictHexString(nonceHex)) {\n throw new Error(\n `Expected hex string from eth_getTransactionCount, got ${JSON.stringify(nonceHex)}`,\n );\n }\n\n return parseInt(nonceHex, 16);\n}\n\n/**\n * Resolves the JSON-RPC provider for the given chain via NetworkController.\n *\n * @param messenger - The upgrade controller messenger.\n * @param chainId - The chain to query.\n * @returns The provider for that chain.\n */\nfunction getProvider(\n messenger: StepContext['messenger'],\n chainId: Hex,\n): Provider {\n const networkClientId = messenger.call(\n 'NetworkController:findNetworkClientIdByChainId',\n chainId,\n );\n return messenger.call(\n 'NetworkController:getNetworkClientById',\n networkClientId,\n ).provider;\n}\n"]}
1
+ {"version":3,"file":"eip-7702-authorization.mjs","sourceRoot":"","sources":["../../src/steps/eip-7702-authorization.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Provider } from '@metamask/network-controller';\nimport { add0x, isStrictHexString } from '@metamask/utils';\nimport type { Hex } from '@metamask/utils';\n\nimport type { Step, StepContext } from './step';\n\nconst EIP_7702_DELEGATION_PREFIX = '0xef0100';\n// '0x' (2) + 'ef0100' (6) + 20-byte address (40) = 48 characters.\nconst EIP_7702_DELEGATED_CODE_LENGTH = 48;\n\n// 65-byte signature: 32-byte r + 32-byte s + 1-byte v.\n// '0x' (2) + 32 bytes (64) + 32 bytes (64) + 1 byte (2) = 132 characters.\nconst SIGNATURE_HEX_LENGTH = 132;\n// '0x' + 32-byte r = 66 characters.\nconst R_END_INDEX = 66;\n// r (66 chars) + 32-byte s (64 chars) = 130 characters.\nconst S_END_INDEX = 130;\nconst V_END_INDEX = SIGNATURE_HEX_LENGTH;\n// v = 27 means yParity = 0; v = 28 means yParity = 1.\nconst V_BASE = 27;\n\n/**\n * Submits the EIP-7702 delegation-slot authorization to CHOMP so the Money\n * Account can be upgraded to a smart account pointed at the configured\n * delegator impl.\n *\n * The step:\n *\n * 1. Reads the account's on-chain code. If it is already delegated to the\n * configured `delegatorImplAddress`, reports `'already-done'`. If it is\n * delegated to a different address, throws rather than silently\n * overwriting an existing delegation.\n * 2. Fetches the account's current on-chain transaction count — CHOMP\n * validates the nonce matches when it applies the authorization.\n * 3. Signs the EIP-7702 authorization `{ chainId, delegatorImpl, nonce }`\n * with the Money Account's key via the keyring.\n * 4. Splits the 65-byte signature into `r`, `s`, `v`, `yParity` and submits\n * it to `POST /v1/account-upgrade`.\n */\nexport const eip7702AuthorizationStep: Step = {\n name: 'eip-7702-authorization',\n async run({ messenger, address, chainId, delegatorImplAddress }) {\n const provider = getProvider(messenger, chainId);\n\n const existingDelegation = await fetchDelegationAddress(provider, address);\n if (existingDelegation !== undefined) {\n if (existingDelegation === delegatorImplAddress.toLowerCase()) {\n return 'already-done';\n }\n throw new Error(\n `Account ${address} is already upgraded to another smart account: ${existingDelegation}.`,\n );\n }\n\n const chainIdDecimal = parseInt(chainId, 16);\n const nonce = await fetchNonce(provider, address);\n\n const signature = await messenger.call(\n 'KeyringController:signEip7702Authorization',\n {\n chainId: chainIdDecimal,\n contractAddress: delegatorImplAddress,\n nonce,\n from: address,\n },\n );\n\n const { r, s, v, yParity } = splitEip7702Signature(signature);\n\n await messenger.call('ChompApiService:createUpgrade', {\n r,\n s,\n v,\n yParity,\n address: delegatorImplAddress,\n chainId,\n nonce: add0x(nonce.toString(16)),\n });\n\n return 'completed';\n },\n};\n\n/**\n * Splits a 65-byte ECDSA signature produced by\n * `KeyringController:signEip7702Authorization` into its `r`, `s`, `v`\n * components and derives `yParity` (`0` for `v = 27`, `1` for `v = 28`).\n *\n * @param signature - A 0x-prefixed 132-character hex string. Accepted in any\n * case; normalized to lowercase before validation.\n * @returns The signature components.\n */\nfunction splitEip7702Signature(signature: unknown): {\n r: Hex;\n s: Hex;\n v: number;\n yParity: 0 | 1;\n} {\n const normalized =\n typeof signature === 'string' ? signature.toLowerCase() : signature;\n\n if (\n !isStrictHexString(normalized) ||\n normalized.length !== SIGNATURE_HEX_LENGTH\n ) {\n throw new Error(\n `Expected a 0x-prefixed 65-byte signature from signEip7702Authorization, got ${JSON.stringify(signature)}`,\n );\n }\n\n // eslint-disable-next-line id-length\n const v = parseInt(normalized.slice(S_END_INDEX, V_END_INDEX), 16);\n if (v !== 27 && v !== 28) {\n throw new Error(\n `Expected v to be 27 or 28 in signEip7702Authorization signature, got ${v}`,\n );\n }\n\n return {\n r: normalized.slice(0, R_END_INDEX) as Hex,\n s: add0x(normalized.slice(R_END_INDEX, S_END_INDEX)),\n v,\n yParity: v === V_BASE ? 0 : 1,\n };\n}\n\n/**\n * Reads the account's on-chain code and, if the account is currently\n * delegated via EIP-7702, returns the implementation address the delegation\n * points at. Returns `undefined` if the account has no code (a plain EOA).\n * Throws if the code is present but not a valid EIP-7702 delegation, since\n * that means the address is a regular contract and is not eligible for\n * upgrade.\n *\n * @param provider - JSON-RPC provider for the target chain.\n * @param address - The Money Account address.\n * @returns The current delegation address, or `undefined` if none.\n */\nasync function fetchDelegationAddress(\n provider: Provider,\n address: Hex,\n): Promise<Hex | undefined> {\n const code = await provider.request({\n method: 'eth_getCode',\n params: [address, 'latest'],\n });\n\n if (typeof code !== 'string' || !code.startsWith('0x')) {\n throw new Error(\n `Expected 0x-prefixed hex string from eth_getCode, got ${JSON.stringify(code)}`,\n );\n }\n\n const normalized = code.toLowerCase();\n\n if (normalized === '0x') {\n return undefined;\n }\n\n if (\n normalized.length === EIP_7702_DELEGATED_CODE_LENGTH &&\n normalized.startsWith(EIP_7702_DELEGATION_PREFIX)\n ) {\n return add0x(normalized.slice(EIP_7702_DELEGATION_PREFIX.length));\n }\n\n throw new Error(\n `Account ${address} has unexpected on-chain code; expected either no code or an EIP-7702 delegation.`,\n );\n}\n\n/**\n * Fetches the current on-chain transaction count for the given address by\n * issuing an `eth_getTransactionCount` RPC request.\n *\n * @param provider - JSON-RPC provider for the target chain.\n * @param address - The Money Account address.\n * @returns The current nonce as a decimal number.\n */\nasync function fetchNonce(provider: Provider, address: Hex): Promise<number> {\n const nonceHex = await provider.request({\n method: 'eth_getTransactionCount',\n params: [address, 'latest'],\n });\n\n if (!isStrictHexString(nonceHex)) {\n throw new Error(\n `Expected hex string from eth_getTransactionCount, got ${JSON.stringify(nonceHex)}`,\n );\n }\n\n return parseInt(nonceHex, 16);\n}\n\n/**\n * Resolves the JSON-RPC provider for the given chain via NetworkController.\n *\n * @param messenger - The upgrade controller messenger.\n * @param chainId - The chain to query.\n * @returns The provider for that chain.\n */\nfunction getProvider(\n messenger: StepContext['messenger'],\n chainId: Hex,\n): Provider {\n const networkClientId = messenger.call(\n 'NetworkController:findNetworkClientIdByChainId',\n chainId,\n );\n return messenger.call(\n 'NetworkController:getNetworkClientById',\n networkClientId,\n ).provider;\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@metamask/money-account-upgrade-controller",
3
- "version": "1.2.0",
3
+ "version": "1.3.1",
4
4
  "description": "MetaMask Money account upgrade controller",
5
5
  "keywords": [
6
6
  "Ethereum",
@@ -54,10 +54,10 @@
54
54
  },
55
55
  "dependencies": {
56
56
  "@metamask/base-controller": "^9.1.0",
57
- "@metamask/chomp-api-service": "^2.0.0",
58
- "@metamask/keyring-controller": "^25.2.0",
59
- "@metamask/messenger": "^1.1.1",
60
- "@metamask/network-controller": "^30.0.1",
57
+ "@metamask/chomp-api-service": "^3.0.0",
58
+ "@metamask/keyring-controller": "^25.4.0",
59
+ "@metamask/messenger": "^1.2.0",
60
+ "@metamask/network-controller": "^30.1.0",
61
61
  "@metamask/utils": "^11.9.0"
62
62
  },
63
63
  "devDependencies": {