@metamask/money-account-upgrade-controller 1.3.1 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +30 -1
- package/dist/MoneyAccountUpgradeController.cjs +36 -6
- package/dist/MoneyAccountUpgradeController.cjs.map +1 -1
- package/dist/MoneyAccountUpgradeController.d.cts +16 -7
- package/dist/MoneyAccountUpgradeController.d.cts.map +1 -1
- package/dist/MoneyAccountUpgradeController.d.mts +16 -7
- package/dist/MoneyAccountUpgradeController.d.mts.map +1 -1
- package/dist/MoneyAccountUpgradeController.mjs +36 -6
- package/dist/MoneyAccountUpgradeController.mjs.map +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs.map +1 -1
- package/dist/steps/build-delegations.cjs +130 -0
- package/dist/steps/build-delegations.cjs.map +1 -0
- package/dist/steps/build-delegations.d.cts +3 -0
- package/dist/steps/build-delegations.d.cts.map +1 -0
- package/dist/steps/build-delegations.d.mts +3 -0
- package/dist/steps/build-delegations.d.mts.map +1 -0
- package/dist/steps/build-delegations.mjs +127 -0
- package/dist/steps/build-delegations.mjs.map +1 -0
- package/dist/steps/delegation-matchers.cjs +26 -0
- package/dist/steps/delegation-matchers.cjs.map +1 -0
- package/dist/steps/delegation-matchers.d.cts +16 -0
- package/dist/steps/delegation-matchers.d.cts.map +1 -0
- package/dist/steps/delegation-matchers.d.mts +16 -0
- package/dist/steps/delegation-matchers.d.mts.map +1 -0
- package/dist/steps/delegation-matchers.mjs +21 -0
- package/dist/steps/delegation-matchers.mjs.map +1 -0
- package/dist/steps/eip-7702-authorization.cjs +29 -9
- package/dist/steps/eip-7702-authorization.cjs.map +1 -1
- package/dist/steps/eip-7702-authorization.d.cts.map +1 -1
- package/dist/steps/eip-7702-authorization.d.mts.map +1 -1
- package/dist/steps/eip-7702-authorization.mjs +29 -9
- package/dist/steps/eip-7702-authorization.mjs.map +1 -1
- package/dist/steps/register-intents.cjs +69 -0
- package/dist/steps/register-intents.cjs.map +1 -0
- package/dist/steps/register-intents.d.cts +18 -0
- package/dist/steps/register-intents.d.cts.map +1 -0
- package/dist/steps/register-intents.d.mts +18 -0
- package/dist/steps/register-intents.d.mts.map +1 -0
- package/dist/steps/register-intents.mjs +66 -0
- package/dist/steps/register-intents.mjs.map +1 -0
- package/dist/steps/step.cjs.map +1 -1
- package/dist/steps/step.d.cts +7 -0
- package/dist/steps/step.d.cts.map +1 -1
- package/dist/steps/step.d.mts +7 -0
- package/dist/steps/step.d.mts.map +1 -1
- package/dist/steps/step.mjs.map +1 -1
- package/dist/types.cjs.map +1 -1
- package/dist/types.d.cts +12 -10
- package/dist/types.d.cts.map +1 -1
- package/dist/types.d.mts +12 -10
- package/dist/types.d.mts.map +1 -1
- package/dist/types.mjs.map +1 -1
- package/package.json +9 -4
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"build-delegations.d.mts","sourceRoot":"","sources":["../../src/steps/build-delegations.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,IAAI,EAAE,mBAAe;AAsHnC,eAAO,MAAM,mBAAmB,EAAE,IAqEjC,CAAC"}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { ROOT_AUTHORITY, createERC20TransferAmountTerms, createRedeemerTerms, createValueLteTerms, hashDelegation } from "@metamask/delegation-core";
|
|
2
|
+
import { add0x, bytesToHex } from "@metamask/utils";
|
|
3
|
+
import { equalsIgnoreCase, makeHasVedaRedeemerCaveat } from "./delegation-matchers.mjs";
|
|
4
|
+
const MAX_UINT256 = 2n ** 256n - 1n;
|
|
5
|
+
const MAX_UINT256_HEX = add0x(MAX_UINT256.toString(16));
|
|
6
|
+
/**
|
|
7
|
+
* Builds, signs, verifies (with CHOMP), and persists a single auto-deposit
|
|
8
|
+
* delegation for the given token. Both the deposit (mUSD) and withdrawal
|
|
9
|
+
* (vmUSD / boring vault) delegations share this shape; only the token
|
|
10
|
+
* address, symbol, and metadata `type` differ.
|
|
11
|
+
*
|
|
12
|
+
* @param params - The parameters for building the delegation.
|
|
13
|
+
* @param params.messenger - The messenger to call signing/verifying actions on.
|
|
14
|
+
* @param params.address - The delegator (the Money Account being upgraded).
|
|
15
|
+
* @param params.chainId - The chain to scope the delegation to.
|
|
16
|
+
* @param params.delegateAddress - CHOMP's delegate.
|
|
17
|
+
* @param params.tokenAddress - The token the delegation authorises transfers of.
|
|
18
|
+
* @param params.tokenSymbol - Symbol stored in the delegation metadata (e.g. "mUSD").
|
|
19
|
+
* @param params.delegationType - Storage metadata `type` field; matches CHOMP's intent type.
|
|
20
|
+
* @param params.vedaVaultAdapterAddress - The redeemer (Veda vault adapter).
|
|
21
|
+
* @param params.erc20TransferAmountEnforcer - The ERC20TransferAmountEnforcer contract.
|
|
22
|
+
* @param params.redeemerEnforcer - The RedeemerEnforcer contract.
|
|
23
|
+
* @param params.valueLteEnforcer - The ValueLteEnforcer contract.
|
|
24
|
+
*/
|
|
25
|
+
async function signAndStoreDelegation(params) {
|
|
26
|
+
const { messenger, address, chainId, delegateAddress, tokenAddress, tokenSymbol, delegationType, vedaVaultAdapterAddress, erc20TransferAmountEnforcer, redeemerEnforcer, valueLteEnforcer, } = params;
|
|
27
|
+
const saltBytes = globalThis.crypto.getRandomValues(new Uint8Array(32));
|
|
28
|
+
const salt = bytesToHex(saltBytes);
|
|
29
|
+
const delegation = {
|
|
30
|
+
delegate: delegateAddress,
|
|
31
|
+
delegator: address,
|
|
32
|
+
authority: ROOT_AUTHORITY,
|
|
33
|
+
caveats: [
|
|
34
|
+
{
|
|
35
|
+
enforcer: valueLteEnforcer,
|
|
36
|
+
terms: createValueLteTerms({ maxValue: 0n }),
|
|
37
|
+
args: '0x',
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
enforcer: erc20TransferAmountEnforcer,
|
|
41
|
+
terms: createERC20TransferAmountTerms({
|
|
42
|
+
tokenAddress,
|
|
43
|
+
maxAmount: MAX_UINT256,
|
|
44
|
+
}),
|
|
45
|
+
args: '0x',
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
enforcer: redeemerEnforcer,
|
|
49
|
+
terms: createRedeemerTerms({ redeemers: [vedaVaultAdapterAddress] }),
|
|
50
|
+
args: '0x',
|
|
51
|
+
},
|
|
52
|
+
],
|
|
53
|
+
salt,
|
|
54
|
+
};
|
|
55
|
+
const signature = (await messenger.call('DelegationController:signDelegation', { delegation, chainId }));
|
|
56
|
+
const signedDelegation = { ...delegation, signature };
|
|
57
|
+
const result = await messenger.call('ChompApiService:verifyDelegation', {
|
|
58
|
+
signedDelegation,
|
|
59
|
+
chainId,
|
|
60
|
+
});
|
|
61
|
+
if (!result.valid) {
|
|
62
|
+
throw new Error(`CHOMP rejected delegation: ${result.errors?.join(', ') ?? 'unknown error'}`);
|
|
63
|
+
}
|
|
64
|
+
const delegationHash = hashDelegation({
|
|
65
|
+
...delegation,
|
|
66
|
+
salt: BigInt(salt),
|
|
67
|
+
signature,
|
|
68
|
+
});
|
|
69
|
+
await messenger.call('AuthenticatedUserStorageService:createDelegation', {
|
|
70
|
+
signedDelegation,
|
|
71
|
+
metadata: {
|
|
72
|
+
delegationHash,
|
|
73
|
+
chainIdHex: chainId,
|
|
74
|
+
allowance: MAX_UINT256_HEX,
|
|
75
|
+
tokenSymbol,
|
|
76
|
+
tokenAddress,
|
|
77
|
+
type: delegationType,
|
|
78
|
+
},
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
export const buildDelegationStep = {
|
|
82
|
+
name: 'build-delegation',
|
|
83
|
+
async run({ messenger, address, chainId, boringVaultAddress, delegateAddress, erc20TransferAmountEnforcer, musdTokenAddress, redeemerEnforcer, valueLteEnforcer, vedaVaultAdapterAddress, }) {
|
|
84
|
+
const existingDelegations = await messenger.call('AuthenticatedUserStorageService:listDelegations');
|
|
85
|
+
const hasVedaRedeemerCaveat = makeHasVedaRedeemerCaveat(redeemerEnforcer, vedaVaultAdapterAddress);
|
|
86
|
+
const matches = (tokenAddress) => (entry) => equalsIgnoreCase(entry.signedDelegation.delegator, address) &&
|
|
87
|
+
equalsIgnoreCase(entry.signedDelegation.delegate, delegateAddress) &&
|
|
88
|
+
equalsIgnoreCase(entry.metadata.chainIdHex, chainId) &&
|
|
89
|
+
equalsIgnoreCase(entry.metadata.tokenAddress, tokenAddress) &&
|
|
90
|
+
hasVedaRedeemerCaveat(entry);
|
|
91
|
+
// The deposit delegation authorises transfers of mUSD (delegator → vault);
|
|
92
|
+
// the withdrawal delegation authorises transfers of vmUSD (vault share
|
|
93
|
+
// token → adapter, which redeems back to mUSD).
|
|
94
|
+
const delegations = [
|
|
95
|
+
{
|
|
96
|
+
tokenAddress: musdTokenAddress,
|
|
97
|
+
tokenSymbol: 'mUSD',
|
|
98
|
+
delegationType: 'cash-deposit',
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
tokenAddress: boringVaultAddress,
|
|
102
|
+
tokenSymbol: 'vmUSD',
|
|
103
|
+
delegationType: 'cash-withdrawal',
|
|
104
|
+
},
|
|
105
|
+
];
|
|
106
|
+
let didWork = false;
|
|
107
|
+
for (const config of delegations) {
|
|
108
|
+
if (existingDelegations.some(matches(config.tokenAddress))) {
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
await signAndStoreDelegation({
|
|
112
|
+
messenger,
|
|
113
|
+
address,
|
|
114
|
+
chainId,
|
|
115
|
+
delegateAddress,
|
|
116
|
+
...config,
|
|
117
|
+
vedaVaultAdapterAddress,
|
|
118
|
+
erc20TransferAmountEnforcer,
|
|
119
|
+
redeemerEnforcer,
|
|
120
|
+
valueLteEnforcer,
|
|
121
|
+
});
|
|
122
|
+
didWork = true;
|
|
123
|
+
}
|
|
124
|
+
return didWork ? 'completed' : 'already-done';
|
|
125
|
+
},
|
|
126
|
+
};
|
|
127
|
+
//# sourceMappingURL=build-delegations.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"build-delegations.mjs","sourceRoot":"","sources":["../../src/steps/build-delegations.ts"],"names":[],"mappings":"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","sourcesContent":["import type { DelegationResponse } from '@metamask/authenticated-user-storage';\nimport {\n ROOT_AUTHORITY,\n createERC20TransferAmountTerms,\n createRedeemerTerms,\n createValueLteTerms,\n hashDelegation,\n} from '@metamask/delegation-core';\nimport { add0x, bytesToHex } from '@metamask/utils';\nimport type { Hex } from '@metamask/utils';\n\nimport type { MoneyAccountUpgradeControllerMessenger } from '../MoneyAccountUpgradeController';\nimport {\n equalsIgnoreCase,\n makeHasVedaRedeemerCaveat,\n} from './delegation-matchers';\nimport type { Step } from './step';\n\nconst MAX_UINT256 = 2n ** 256n - 1n;\nconst MAX_UINT256_HEX: Hex = add0x(MAX_UINT256.toString(16));\n\n/**\n * Builds, signs, verifies (with CHOMP), and persists a single auto-deposit\n * delegation for the given token. Both the deposit (mUSD) and withdrawal\n * (vmUSD / boring vault) delegations share this shape; only the token\n * address, symbol, and metadata `type` differ.\n *\n * @param params - The parameters for building the delegation.\n * @param params.messenger - The messenger to call signing/verifying actions on.\n * @param params.address - The delegator (the Money Account being upgraded).\n * @param params.chainId - The chain to scope the delegation to.\n * @param params.delegateAddress - CHOMP's delegate.\n * @param params.tokenAddress - The token the delegation authorises transfers of.\n * @param params.tokenSymbol - Symbol stored in the delegation metadata (e.g. \"mUSD\").\n * @param params.delegationType - Storage metadata `type` field; matches CHOMP's intent type.\n * @param params.vedaVaultAdapterAddress - The redeemer (Veda vault adapter).\n * @param params.erc20TransferAmountEnforcer - The ERC20TransferAmountEnforcer contract.\n * @param params.redeemerEnforcer - The RedeemerEnforcer contract.\n * @param params.valueLteEnforcer - The ValueLteEnforcer contract.\n */\nasync function signAndStoreDelegation(params: {\n messenger: MoneyAccountUpgradeControllerMessenger;\n address: Hex;\n chainId: Hex;\n delegateAddress: Hex;\n tokenAddress: Hex;\n tokenSymbol: string;\n delegationType: 'cash-deposit' | 'cash-withdrawal';\n vedaVaultAdapterAddress: Hex;\n erc20TransferAmountEnforcer: Hex;\n redeemerEnforcer: Hex;\n valueLteEnforcer: Hex;\n}): Promise<void> {\n const {\n messenger,\n address,\n chainId,\n delegateAddress,\n tokenAddress,\n tokenSymbol,\n delegationType,\n vedaVaultAdapterAddress,\n erc20TransferAmountEnforcer,\n redeemerEnforcer,\n valueLteEnforcer,\n } = params;\n\n const saltBytes = globalThis.crypto.getRandomValues(new Uint8Array(32));\n const salt = bytesToHex(saltBytes);\n\n const delegation = {\n delegate: delegateAddress,\n delegator: address,\n authority: ROOT_AUTHORITY,\n caveats: [\n {\n enforcer: valueLteEnforcer,\n terms: createValueLteTerms({ maxValue: 0n }),\n args: '0x' as Hex,\n },\n {\n enforcer: erc20TransferAmountEnforcer,\n terms: createERC20TransferAmountTerms({\n tokenAddress,\n maxAmount: MAX_UINT256,\n }),\n args: '0x' as Hex,\n },\n {\n enforcer: redeemerEnforcer,\n terms: createRedeemerTerms({ redeemers: [vedaVaultAdapterAddress] }),\n args: '0x' as Hex,\n },\n ],\n salt,\n };\n\n const signature = (await messenger.call(\n 'DelegationController:signDelegation',\n { delegation, chainId },\n )) as Hex;\n\n const signedDelegation = { ...delegation, signature };\n\n const result = await messenger.call('ChompApiService:verifyDelegation', {\n signedDelegation,\n chainId,\n });\n\n if (!result.valid) {\n throw new Error(\n `CHOMP rejected delegation: ${result.errors?.join(', ') ?? 'unknown error'}`,\n );\n }\n\n const delegationHash = hashDelegation({\n ...delegation,\n salt: BigInt(salt),\n signature,\n });\n\n await messenger.call('AuthenticatedUserStorageService:createDelegation', {\n signedDelegation,\n metadata: {\n delegationHash,\n chainIdHex: chainId,\n allowance: MAX_UINT256_HEX,\n tokenSymbol,\n tokenAddress,\n type: delegationType,\n },\n });\n}\n\nexport const buildDelegationStep: Step = {\n name: 'build-delegation',\n async run({\n messenger,\n address,\n chainId,\n boringVaultAddress,\n delegateAddress,\n erc20TransferAmountEnforcer,\n musdTokenAddress,\n redeemerEnforcer,\n valueLteEnforcer,\n vedaVaultAdapterAddress,\n }) {\n const existingDelegations = await messenger.call(\n 'AuthenticatedUserStorageService:listDelegations',\n );\n\n const hasVedaRedeemerCaveat = makeHasVedaRedeemerCaveat(\n redeemerEnforcer,\n vedaVaultAdapterAddress,\n );\n\n const matches =\n (tokenAddress: Hex) =>\n (entry: DelegationResponse): boolean =>\n equalsIgnoreCase(entry.signedDelegation.delegator, address) &&\n equalsIgnoreCase(entry.signedDelegation.delegate, delegateAddress) &&\n equalsIgnoreCase(entry.metadata.chainIdHex, chainId) &&\n equalsIgnoreCase(entry.metadata.tokenAddress, tokenAddress) &&\n hasVedaRedeemerCaveat(entry);\n\n // The deposit delegation authorises transfers of mUSD (delegator → vault);\n // the withdrawal delegation authorises transfers of vmUSD (vault share\n // token → adapter, which redeems back to mUSD).\n const delegations = [\n {\n tokenAddress: musdTokenAddress,\n tokenSymbol: 'mUSD',\n delegationType: 'cash-deposit' as const,\n },\n {\n tokenAddress: boringVaultAddress,\n tokenSymbol: 'vmUSD',\n delegationType: 'cash-withdrawal' as const,\n },\n ];\n\n let didWork = false;\n for (const config of delegations) {\n if (existingDelegations.some(matches(config.tokenAddress))) {\n continue;\n }\n await signAndStoreDelegation({\n messenger,\n address,\n chainId,\n delegateAddress,\n ...config,\n vedaVaultAdapterAddress,\n erc20TransferAmountEnforcer,\n redeemerEnforcer,\n valueLteEnforcer,\n });\n didWork = true;\n }\n\n return didWork ? 'completed' : 'already-done';\n },\n};\n"]}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.makeHasVedaRedeemerCaveat = exports.equalsIgnoreCase = void 0;
|
|
4
|
+
const delegation_core_1 = require("@metamask/delegation-core");
|
|
5
|
+
const equalsIgnoreCase = (a, b) => a.toLowerCase() === b.toLowerCase();
|
|
6
|
+
exports.equalsIgnoreCase = equalsIgnoreCase;
|
|
7
|
+
/**
|
|
8
|
+
* Builds a predicate that matches stored delegations carrying a redeemer
|
|
9
|
+
* caveat targeting the Veda vault adapter — i.e. delegations we wrote for
|
|
10
|
+
* auto-deposit / auto-withdrawal. The expected terms blob is computed once
|
|
11
|
+
* and reused across calls.
|
|
12
|
+
*
|
|
13
|
+
* @param redeemerEnforcer - The RedeemerEnforcer contract address.
|
|
14
|
+
* @param vedaVaultAdapterAddress - The Veda vault adapter address that must
|
|
15
|
+
* be encoded as the sole redeemer.
|
|
16
|
+
* @returns A predicate over `DelegationResponse`.
|
|
17
|
+
*/
|
|
18
|
+
const makeHasVedaRedeemerCaveat = (redeemerEnforcer, vedaVaultAdapterAddress) => {
|
|
19
|
+
const expectedRedeemerTerms = (0, delegation_core_1.createRedeemerTerms)({
|
|
20
|
+
redeemers: [vedaVaultAdapterAddress],
|
|
21
|
+
});
|
|
22
|
+
return (entry) => entry.signedDelegation.caveats.some((caveat) => (0, exports.equalsIgnoreCase)(caveat.enforcer, redeemerEnforcer) &&
|
|
23
|
+
(0, exports.equalsIgnoreCase)(caveat.terms, expectedRedeemerTerms));
|
|
24
|
+
};
|
|
25
|
+
exports.makeHasVedaRedeemerCaveat = makeHasVedaRedeemerCaveat;
|
|
26
|
+
//# sourceMappingURL=delegation-matchers.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"delegation-matchers.cjs","sourceRoot":"","sources":["../../src/steps/delegation-matchers.ts"],"names":[],"mappings":";;;AACA,+DAAgE;AAGzD,MAAM,gBAAgB,GAAG,CAAC,CAAM,EAAE,CAAM,EAAW,EAAE,CAC1D,CAAC,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC,WAAW,EAAE,CAAC;AADzB,QAAA,gBAAgB,oBACS;AAEtC;;;;;;;;;;GAUG;AACI,MAAM,yBAAyB,GAAG,CACvC,gBAAqB,EACrB,uBAA4B,EACc,EAAE;IAC5C,MAAM,qBAAqB,GAAG,IAAA,qCAAmB,EAAC;QAChD,SAAS,EAAE,CAAC,uBAAuB,CAAC;KACrC,CAAC,CAAC;IACH,OAAO,CAAC,KAAK,EAAE,EAAE,CACf,KAAK,CAAC,gBAAgB,CAAC,OAAO,CAAC,IAAI,CACjC,CAAC,MAAM,EAAE,EAAE,CACT,IAAA,wBAAgB,EAAC,MAAM,CAAC,QAAQ,EAAE,gBAAgB,CAAC;QACnD,IAAA,wBAAgB,EAAC,MAAM,CAAC,KAAK,EAAE,qBAAqB,CAAC,CACxD,CAAC;AACN,CAAC,CAAC;AAbW,QAAA,yBAAyB,6BAapC","sourcesContent":["import type { DelegationResponse } from '@metamask/authenticated-user-storage';\nimport { createRedeemerTerms } from '@metamask/delegation-core';\nimport type { Hex } from '@metamask/utils';\n\nexport const equalsIgnoreCase = (a: Hex, b: Hex): boolean =>\n a.toLowerCase() === b.toLowerCase();\n\n/**\n * Builds a predicate that matches stored delegations carrying a redeemer\n * caveat targeting the Veda vault adapter — i.e. delegations we wrote for\n * auto-deposit / auto-withdrawal. The expected terms blob is computed once\n * and reused across calls.\n *\n * @param redeemerEnforcer - The RedeemerEnforcer contract address.\n * @param vedaVaultAdapterAddress - The Veda vault adapter address that must\n * be encoded as the sole redeemer.\n * @returns A predicate over `DelegationResponse`.\n */\nexport const makeHasVedaRedeemerCaveat = (\n redeemerEnforcer: Hex,\n vedaVaultAdapterAddress: Hex,\n): ((entry: DelegationResponse) => boolean) => {\n const expectedRedeemerTerms = createRedeemerTerms({\n redeemers: [vedaVaultAdapterAddress],\n });\n return (entry) =>\n entry.signedDelegation.caveats.some(\n (caveat) =>\n equalsIgnoreCase(caveat.enforcer, redeemerEnforcer) &&\n equalsIgnoreCase(caveat.terms, expectedRedeemerTerms),\n );\n};\n"]}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { DelegationResponse } from "@metamask/authenticated-user-storage";
|
|
2
|
+
import type { Hex } from "@metamask/utils";
|
|
3
|
+
export declare const equalsIgnoreCase: (a: Hex, b: Hex) => boolean;
|
|
4
|
+
/**
|
|
5
|
+
* Builds a predicate that matches stored delegations carrying a redeemer
|
|
6
|
+
* caveat targeting the Veda vault adapter — i.e. delegations we wrote for
|
|
7
|
+
* auto-deposit / auto-withdrawal. The expected terms blob is computed once
|
|
8
|
+
* and reused across calls.
|
|
9
|
+
*
|
|
10
|
+
* @param redeemerEnforcer - The RedeemerEnforcer contract address.
|
|
11
|
+
* @param vedaVaultAdapterAddress - The Veda vault adapter address that must
|
|
12
|
+
* be encoded as the sole redeemer.
|
|
13
|
+
* @returns A predicate over `DelegationResponse`.
|
|
14
|
+
*/
|
|
15
|
+
export declare const makeHasVedaRedeemerCaveat: (redeemerEnforcer: Hex, vedaVaultAdapterAddress: Hex) => (entry: DelegationResponse) => boolean;
|
|
16
|
+
//# sourceMappingURL=delegation-matchers.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"delegation-matchers.d.cts","sourceRoot":"","sources":["../../src/steps/delegation-matchers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,6CAA6C;AAE/E,OAAO,KAAK,EAAE,GAAG,EAAE,wBAAwB;AAE3C,eAAO,MAAM,gBAAgB,MAAO,GAAG,KAAK,GAAG,KAAG,OACb,CAAC;AAEtC;;;;;;;;;;GAUG;AACH,eAAO,MAAM,yBAAyB,qBAClB,GAAG,2BACI,GAAG,aAClB,kBAAkB,KAAK,OAUlC,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { DelegationResponse } from "@metamask/authenticated-user-storage";
|
|
2
|
+
import type { Hex } from "@metamask/utils";
|
|
3
|
+
export declare const equalsIgnoreCase: (a: Hex, b: Hex) => boolean;
|
|
4
|
+
/**
|
|
5
|
+
* Builds a predicate that matches stored delegations carrying a redeemer
|
|
6
|
+
* caveat targeting the Veda vault adapter — i.e. delegations we wrote for
|
|
7
|
+
* auto-deposit / auto-withdrawal. The expected terms blob is computed once
|
|
8
|
+
* and reused across calls.
|
|
9
|
+
*
|
|
10
|
+
* @param redeemerEnforcer - The RedeemerEnforcer contract address.
|
|
11
|
+
* @param vedaVaultAdapterAddress - The Veda vault adapter address that must
|
|
12
|
+
* be encoded as the sole redeemer.
|
|
13
|
+
* @returns A predicate over `DelegationResponse`.
|
|
14
|
+
*/
|
|
15
|
+
export declare const makeHasVedaRedeemerCaveat: (redeemerEnforcer: Hex, vedaVaultAdapterAddress: Hex) => (entry: DelegationResponse) => boolean;
|
|
16
|
+
//# sourceMappingURL=delegation-matchers.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"delegation-matchers.d.mts","sourceRoot":"","sources":["../../src/steps/delegation-matchers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,6CAA6C;AAE/E,OAAO,KAAK,EAAE,GAAG,EAAE,wBAAwB;AAE3C,eAAO,MAAM,gBAAgB,MAAO,GAAG,KAAK,GAAG,KAAG,OACb,CAAC;AAEtC;;;;;;;;;;GAUG;AACH,eAAO,MAAM,yBAAyB,qBAClB,GAAG,2BACI,GAAG,aAClB,kBAAkB,KAAK,OAUlC,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { createRedeemerTerms } from "@metamask/delegation-core";
|
|
2
|
+
export const equalsIgnoreCase = (a, b) => a.toLowerCase() === b.toLowerCase();
|
|
3
|
+
/**
|
|
4
|
+
* Builds a predicate that matches stored delegations carrying a redeemer
|
|
5
|
+
* caveat targeting the Veda vault adapter — i.e. delegations we wrote for
|
|
6
|
+
* auto-deposit / auto-withdrawal. The expected terms blob is computed once
|
|
7
|
+
* and reused across calls.
|
|
8
|
+
*
|
|
9
|
+
* @param redeemerEnforcer - The RedeemerEnforcer contract address.
|
|
10
|
+
* @param vedaVaultAdapterAddress - The Veda vault adapter address that must
|
|
11
|
+
* be encoded as the sole redeemer.
|
|
12
|
+
* @returns A predicate over `DelegationResponse`.
|
|
13
|
+
*/
|
|
14
|
+
export const makeHasVedaRedeemerCaveat = (redeemerEnforcer, vedaVaultAdapterAddress) => {
|
|
15
|
+
const expectedRedeemerTerms = createRedeemerTerms({
|
|
16
|
+
redeemers: [vedaVaultAdapterAddress],
|
|
17
|
+
});
|
|
18
|
+
return (entry) => entry.signedDelegation.caveats.some((caveat) => equalsIgnoreCase(caveat.enforcer, redeemerEnforcer) &&
|
|
19
|
+
equalsIgnoreCase(caveat.terms, expectedRedeemerTerms));
|
|
20
|
+
};
|
|
21
|
+
//# sourceMappingURL=delegation-matchers.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"delegation-matchers.mjs","sourceRoot":"","sources":["../../src/steps/delegation-matchers.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,kCAAkC;AAGhE,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAM,EAAE,CAAM,EAAW,EAAE,CAC1D,CAAC,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC,WAAW,EAAE,CAAC;AAEtC;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAG,CACvC,gBAAqB,EACrB,uBAA4B,EACc,EAAE;IAC5C,MAAM,qBAAqB,GAAG,mBAAmB,CAAC;QAChD,SAAS,EAAE,CAAC,uBAAuB,CAAC;KACrC,CAAC,CAAC;IACH,OAAO,CAAC,KAAK,EAAE,EAAE,CACf,KAAK,CAAC,gBAAgB,CAAC,OAAO,CAAC,IAAI,CACjC,CAAC,MAAM,EAAE,EAAE,CACT,gBAAgB,CAAC,MAAM,CAAC,QAAQ,EAAE,gBAAgB,CAAC;QACnD,gBAAgB,CAAC,MAAM,CAAC,KAAK,EAAE,qBAAqB,CAAC,CACxD,CAAC;AACN,CAAC,CAAC","sourcesContent":["import type { DelegationResponse } from '@metamask/authenticated-user-storage';\nimport { createRedeemerTerms } from '@metamask/delegation-core';\nimport type { Hex } from '@metamask/utils';\n\nexport const equalsIgnoreCase = (a: Hex, b: Hex): boolean =>\n a.toLowerCase() === b.toLowerCase();\n\n/**\n * Builds a predicate that matches stored delegations carrying a redeemer\n * caveat targeting the Veda vault adapter — i.e. delegations we wrote for\n * auto-deposit / auto-withdrawal. The expected terms blob is computed once\n * and reused across calls.\n *\n * @param redeemerEnforcer - The RedeemerEnforcer contract address.\n * @param vedaVaultAdapterAddress - The Veda vault adapter address that must\n * be encoded as the sole redeemer.\n * @returns A predicate over `DelegationResponse`.\n */\nexport const makeHasVedaRedeemerCaveat = (\n redeemerEnforcer: Hex,\n vedaVaultAdapterAddress: Hex,\n): ((entry: DelegationResponse) => boolean) => {\n const expectedRedeemerTerms = createRedeemerTerms({\n redeemers: [vedaVaultAdapterAddress],\n });\n return (entry) =>\n entry.signedDelegation.caveats.some(\n (caveat) =>\n equalsIgnoreCase(caveat.enforcer, redeemerEnforcer) &&\n equalsIgnoreCase(caveat.terms, expectedRedeemerTerms),\n );\n};\n"]}
|
|
@@ -53,18 +53,38 @@ exports.eip7702AuthorizationStep = {
|
|
|
53
53
|
from: address,
|
|
54
54
|
});
|
|
55
55
|
const { r, s, v, yParity } = splitEip7702Signature(signature);
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
56
|
+
try {
|
|
57
|
+
await messenger.call('ChompApiService:createUpgrade', {
|
|
58
|
+
r,
|
|
59
|
+
s,
|
|
60
|
+
v,
|
|
61
|
+
yParity,
|
|
62
|
+
address: delegatorImplAddress,
|
|
63
|
+
chainId,
|
|
64
|
+
nonce: (0, utils_1.add0x)(nonce.toString(16)),
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
// CHOMP returns 409 when an authorization for this address already
|
|
69
|
+
// exists with the same or higher nonce — typically on retry when a
|
|
70
|
+
// previous submission was accepted but hasn't yet been observed
|
|
71
|
+
// on-chain (so `fetchDelegationAddress` returned undefined above).
|
|
72
|
+
// Treat as already-done so the upgrade sequence is retry-safe.
|
|
73
|
+
if (isHttp409(error)) {
|
|
74
|
+
return 'already-done';
|
|
75
|
+
}
|
|
76
|
+
throw error;
|
|
77
|
+
}
|
|
65
78
|
return 'completed';
|
|
66
79
|
},
|
|
67
80
|
};
|
|
81
|
+
function isHttp409(error) {
|
|
82
|
+
if (typeof error !== 'object' || error === null) {
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
const { httpStatus } = error;
|
|
86
|
+
return httpStatus === 409;
|
|
87
|
+
}
|
|
68
88
|
/**
|
|
69
89
|
* Splits a 65-byte ECDSA signature produced by
|
|
70
90
|
* `KeyringController:signEip7702Authorization` into its `r`, `s`, `v`
|
|
@@ -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: 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"]}
|
|
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 try {\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 } catch (error) {\n // CHOMP returns 409 when an authorization for this address already\n // exists with the same or higher nonce — typically on retry when a\n // previous submission was accepted but hasn't yet been observed\n // on-chain (so `fetchDelegationAddress` returned undefined above).\n // Treat as already-done so the upgrade sequence is retry-safe.\n if (isHttp409(error)) {\n return 'already-done';\n }\n throw error;\n }\n\n return 'completed';\n },\n};\n\nfunction isHttp409(error: unknown): boolean {\n if (typeof error !== 'object' || error === null) {\n return false;\n }\n const { httpStatus } = error as { httpStatus?: unknown };\n return httpStatus === 409;\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 +1 @@
|
|
|
1
|
-
{"version":3,"file":"eip-7702-authorization.d.cts","sourceRoot":"","sources":["../../src/steps/eip-7702-authorization.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,IAAI,EAAe,mBAAe;AAiBhD;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,wBAAwB,EAAE,
|
|
1
|
+
{"version":3,"file":"eip-7702-authorization.d.cts","sourceRoot":"","sources":["../../src/steps/eip-7702-authorization.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,IAAI,EAAe,mBAAe;AAiBhD;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,wBAAwB,EAAE,IAsDtC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"eip-7702-authorization.d.mts","sourceRoot":"","sources":["../../src/steps/eip-7702-authorization.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,IAAI,EAAe,mBAAe;AAiBhD;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,wBAAwB,EAAE,
|
|
1
|
+
{"version":3,"file":"eip-7702-authorization.d.mts","sourceRoot":"","sources":["../../src/steps/eip-7702-authorization.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,IAAI,EAAe,mBAAe;AAiBhD;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,wBAAwB,EAAE,IAsDtC,CAAC"}
|
|
@@ -50,18 +50,38 @@ export const eip7702AuthorizationStep = {
|
|
|
50
50
|
from: address,
|
|
51
51
|
});
|
|
52
52
|
const { r, s, v, yParity } = splitEip7702Signature(signature);
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
53
|
+
try {
|
|
54
|
+
await messenger.call('ChompApiService:createUpgrade', {
|
|
55
|
+
r,
|
|
56
|
+
s,
|
|
57
|
+
v,
|
|
58
|
+
yParity,
|
|
59
|
+
address: delegatorImplAddress,
|
|
60
|
+
chainId,
|
|
61
|
+
nonce: add0x(nonce.toString(16)),
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
// CHOMP returns 409 when an authorization for this address already
|
|
66
|
+
// exists with the same or higher nonce — typically on retry when a
|
|
67
|
+
// previous submission was accepted but hasn't yet been observed
|
|
68
|
+
// on-chain (so `fetchDelegationAddress` returned undefined above).
|
|
69
|
+
// Treat as already-done so the upgrade sequence is retry-safe.
|
|
70
|
+
if (isHttp409(error)) {
|
|
71
|
+
return 'already-done';
|
|
72
|
+
}
|
|
73
|
+
throw error;
|
|
74
|
+
}
|
|
62
75
|
return 'completed';
|
|
63
76
|
},
|
|
64
77
|
};
|
|
78
|
+
function isHttp409(error) {
|
|
79
|
+
if (typeof error !== 'object' || error === null) {
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
const { httpStatus } = error;
|
|
83
|
+
return httpStatus === 409;
|
|
84
|
+
}
|
|
65
85
|
/**
|
|
66
86
|
* Splits a 65-byte ECDSA signature produced by
|
|
67
87
|
* `KeyringController:signEip7702Authorization` into its `r`, `s`, `v`
|
|
@@ -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: 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"]}
|
|
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 try {\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 } catch (error) {\n // CHOMP returns 409 when an authorization for this address already\n // exists with the same or higher nonce — typically on retry when a\n // previous submission was accepted but hasn't yet been observed\n // on-chain (so `fetchDelegationAddress` returned undefined above).\n // Treat as already-done so the upgrade sequence is retry-safe.\n if (isHttp409(error)) {\n return 'already-done';\n }\n throw error;\n }\n\n return 'completed';\n },\n};\n\nfunction isHttp409(error: unknown): boolean {\n if (typeof error !== 'object' || error === null) {\n return false;\n }\n const { httpStatus } = error as { httpStatus?: unknown };\n return httpStatus === 409;\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"]}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerIntentsStep = void 0;
|
|
4
|
+
const delegation_matchers_1 = require("./delegation-matchers.cjs");
|
|
5
|
+
/**
|
|
6
|
+
* Parses a delegation's metadata `type` field — typed as `string` in storage —
|
|
7
|
+
* into the narrow set of CHOMP intent types. Throws if the field carries any
|
|
8
|
+
* other value, since registering it as an intent would be a category error.
|
|
9
|
+
*
|
|
10
|
+
* @param type - The `type` field from `DelegationMetadata`.
|
|
11
|
+
* @returns The same value, narrowed to `IntentMetadataType`.
|
|
12
|
+
*/
|
|
13
|
+
function parseIntentMetadataType(type) {
|
|
14
|
+
if (type !== 'cash-deposit' && type !== 'cash-withdrawal') {
|
|
15
|
+
throw new Error(`Expected delegation type to be "cash-deposit" or "cash-withdrawal", got "${type}"`);
|
|
16
|
+
}
|
|
17
|
+
return type;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Registers CHOMP intents for the auto-deposit / auto-withdrawal delegations
|
|
21
|
+
* persisted by the build-delegation step.
|
|
22
|
+
*
|
|
23
|
+
* For each stored delegation between this account and CHOMP's delegate on
|
|
24
|
+
* this chain, the step builds an intent referencing the stored
|
|
25
|
+
* `delegationHash` and submits the batch to `POST /v1/intent`. Delegations
|
|
26
|
+
* whose `delegationHash` already has an active intent on CHOMP are skipped
|
|
27
|
+
* (revoked intents are re-registered). Reports `'already-done'` when every
|
|
28
|
+
* eligible delegation already has an active intent.
|
|
29
|
+
*
|
|
30
|
+
* Once registered, CHOMP re-fetches the delegation from Authenticated User
|
|
31
|
+
* Storage, re-validates it, and adds the account to its monitoring list so
|
|
32
|
+
* subsequent eligible operations can be picked up automatically.
|
|
33
|
+
*/
|
|
34
|
+
exports.registerIntentsStep = {
|
|
35
|
+
name: 'register-intents',
|
|
36
|
+
async run({ messenger, address, chainId, delegateAddress, redeemerEnforcer, vedaVaultAdapterAddress, }) {
|
|
37
|
+
const [delegations, existingIntents] = await Promise.all([
|
|
38
|
+
messenger.call('AuthenticatedUserStorageService:listDelegations'),
|
|
39
|
+
messenger.call('ChompApiService:getIntentsByAddress', address),
|
|
40
|
+
]);
|
|
41
|
+
const activeIntentHashes = new Set(existingIntents
|
|
42
|
+
.filter((intent) => intent.status === 'active')
|
|
43
|
+
.map((intent) => intent.delegationHash.toLowerCase()));
|
|
44
|
+
const hasVedaRedeemerCaveat = (0, delegation_matchers_1.makeHasVedaRedeemerCaveat)(redeemerEnforcer, vedaVaultAdapterAddress);
|
|
45
|
+
const needsIntent = (entry) => (0, delegation_matchers_1.equalsIgnoreCase)(entry.signedDelegation.delegator, address) &&
|
|
46
|
+
(0, delegation_matchers_1.equalsIgnoreCase)(entry.signedDelegation.delegate, delegateAddress) &&
|
|
47
|
+
(0, delegation_matchers_1.equalsIgnoreCase)(entry.metadata.chainIdHex, chainId) &&
|
|
48
|
+
hasVedaRedeemerCaveat(entry) &&
|
|
49
|
+
!activeIntentHashes.has(entry.metadata.delegationHash.toLowerCase());
|
|
50
|
+
const toIntent = (entry) => ({
|
|
51
|
+
account: address,
|
|
52
|
+
delegationHash: entry.metadata.delegationHash,
|
|
53
|
+
chainId,
|
|
54
|
+
metadata: {
|
|
55
|
+
allowance: entry.metadata.allowance,
|
|
56
|
+
tokenSymbol: entry.metadata.tokenSymbol,
|
|
57
|
+
tokenAddress: entry.metadata.tokenAddress,
|
|
58
|
+
type: parseIntentMetadataType(entry.metadata.type),
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
const intents = delegations.filter(needsIntent).map(toIntent);
|
|
62
|
+
if (intents.length === 0) {
|
|
63
|
+
return 'already-done';
|
|
64
|
+
}
|
|
65
|
+
await messenger.call('ChompApiService:createIntents', intents);
|
|
66
|
+
return 'completed';
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
//# sourceMappingURL=register-intents.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"register-intents.cjs","sourceRoot":"","sources":["../../src/steps/register-intents.ts"],"names":[],"mappings":";;;AAMA,mEAG+B;AAK/B;;;;;;;GAOG;AACH,SAAS,uBAAuB,CAAC,IAAY;IAC3C,IAAI,IAAI,KAAK,cAAc,IAAI,IAAI,KAAK,iBAAiB,EAAE,CAAC;QAC1D,MAAM,IAAI,KAAK,CACb,4EAA4E,IAAI,GAAG,CACpF,CAAC;IACJ,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACU,QAAA,mBAAmB,GAAS;IACvC,IAAI,EAAE,kBAAkB;IACxB,KAAK,CAAC,GAAG,CAAC,EACR,SAAS,EACT,OAAO,EACP,OAAO,EACP,eAAe,EACf,gBAAgB,EAChB,uBAAuB,GACxB;QACC,MAAM,CAAC,WAAW,EAAE,eAAe,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;YACvD,SAAS,CAAC,IAAI,CAAC,iDAAiD,CAAC;YACjE,SAAS,CAAC,IAAI,CAAC,qCAAqC,EAAE,OAAO,CAAC;SAC/D,CAAC,CAAC;QAEH,MAAM,kBAAkB,GAAG,IAAI,GAAG,CAChC,eAAe;aACZ,MAAM,CAAC,CAAC,MAAmB,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,KAAK,QAAQ,CAAC;aAC3D,GAAG,CAAC,CAAC,MAAmB,EAAE,EAAE,CAAC,MAAM,CAAC,cAAc,CAAC,WAAW,EAAE,CAAC,CACrE,CAAC;QAEF,MAAM,qBAAqB,GAAG,IAAA,+CAAyB,EACrD,gBAAgB,EAChB,uBAAuB,CACxB,CAAC;QAEF,MAAM,WAAW,GAAG,CAAC,KAAyB,EAAW,EAAE,CACzD,IAAA,sCAAgB,EAAC,KAAK,CAAC,gBAAgB,CAAC,SAAS,EAAE,OAAO,CAAC;YAC3D,IAAA,sCAAgB,EAAC,KAAK,CAAC,gBAAgB,CAAC,QAAQ,EAAE,eAAe,CAAC;YAClE,IAAA,sCAAgB,EAAC,KAAK,CAAC,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;YACpD,qBAAqB,CAAC,KAAK,CAAC;YAC5B,CAAC,kBAAkB,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,cAAc,CAAC,WAAW,EAAE,CAAC,CAAC;QAEvE,MAAM,QAAQ,GAAG,CAAC,KAAyB,EAAoB,EAAE,CAAC,CAAC;YACjE,OAAO,EAAE,OAAO;YAChB,cAAc,EAAE,KAAK,CAAC,QAAQ,CAAC,cAAc;YAC7C,OAAO;YACP,QAAQ,EAAE;gBACR,SAAS,EAAE,KAAK,CAAC,QAAQ,CAAC,SAAS;gBACnC,WAAW,EAAE,KAAK,CAAC,QAAQ,CAAC,WAAW;gBACvC,YAAY,EAAE,KAAK,CAAC,QAAQ,CAAC,YAAY;gBACzC,IAAI,EAAE,uBAAuB,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC;aACnD;SACF,CAAC,CAAC;QAEH,MAAM,OAAO,GAAG,WAAW,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAE9D,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACzB,OAAO,cAAc,CAAC;QACxB,CAAC;QAED,MAAM,SAAS,CAAC,IAAI,CAAC,+BAA+B,EAAE,OAAO,CAAC,CAAC;QAC/D,OAAO,WAAW,CAAC;IACrB,CAAC;CACF,CAAC","sourcesContent":["import type { DelegationResponse } from '@metamask/authenticated-user-storage';\nimport type {\n IntentEntry,\n SendIntentParams,\n} from '@metamask/chomp-api-service';\n\nimport {\n equalsIgnoreCase,\n makeHasVedaRedeemerCaveat,\n} from './delegation-matchers';\nimport type { Step } from './step';\n\ntype IntentMetadataType = SendIntentParams['metadata']['type'];\n\n/**\n * Parses a delegation's metadata `type` field — typed as `string` in storage —\n * into the narrow set of CHOMP intent types. Throws if the field carries any\n * other value, since registering it as an intent would be a category error.\n *\n * @param type - The `type` field from `DelegationMetadata`.\n * @returns The same value, narrowed to `IntentMetadataType`.\n */\nfunction parseIntentMetadataType(type: string): IntentMetadataType {\n if (type !== 'cash-deposit' && type !== 'cash-withdrawal') {\n throw new Error(\n `Expected delegation type to be \"cash-deposit\" or \"cash-withdrawal\", got \"${type}\"`,\n );\n }\n return type;\n}\n\n/**\n * Registers CHOMP intents for the auto-deposit / auto-withdrawal delegations\n * persisted by the build-delegation step.\n *\n * For each stored delegation between this account and CHOMP's delegate on\n * this chain, the step builds an intent referencing the stored\n * `delegationHash` and submits the batch to `POST /v1/intent`. Delegations\n * whose `delegationHash` already has an active intent on CHOMP are skipped\n * (revoked intents are re-registered). Reports `'already-done'` when every\n * eligible delegation already has an active intent.\n *\n * Once registered, CHOMP re-fetches the delegation from Authenticated User\n * Storage, re-validates it, and adds the account to its monitoring list so\n * subsequent eligible operations can be picked up automatically.\n */\nexport const registerIntentsStep: Step = {\n name: 'register-intents',\n async run({\n messenger,\n address,\n chainId,\n delegateAddress,\n redeemerEnforcer,\n vedaVaultAdapterAddress,\n }) {\n const [delegations, existingIntents] = await Promise.all([\n messenger.call('AuthenticatedUserStorageService:listDelegations'),\n messenger.call('ChompApiService:getIntentsByAddress', address),\n ]);\n\n const activeIntentHashes = new Set(\n existingIntents\n .filter((intent: IntentEntry) => intent.status === 'active')\n .map((intent: IntentEntry) => intent.delegationHash.toLowerCase()),\n );\n\n const hasVedaRedeemerCaveat = makeHasVedaRedeemerCaveat(\n redeemerEnforcer,\n vedaVaultAdapterAddress,\n );\n\n const needsIntent = (entry: DelegationResponse): boolean =>\n equalsIgnoreCase(entry.signedDelegation.delegator, address) &&\n equalsIgnoreCase(entry.signedDelegation.delegate, delegateAddress) &&\n equalsIgnoreCase(entry.metadata.chainIdHex, chainId) &&\n hasVedaRedeemerCaveat(entry) &&\n !activeIntentHashes.has(entry.metadata.delegationHash.toLowerCase());\n\n const toIntent = (entry: DelegationResponse): SendIntentParams => ({\n account: address,\n delegationHash: entry.metadata.delegationHash,\n chainId,\n metadata: {\n allowance: entry.metadata.allowance,\n tokenSymbol: entry.metadata.tokenSymbol,\n tokenAddress: entry.metadata.tokenAddress,\n type: parseIntentMetadataType(entry.metadata.type),\n },\n });\n\n const intents = delegations.filter(needsIntent).map(toIntent);\n\n if (intents.length === 0) {\n return 'already-done';\n }\n\n await messenger.call('ChompApiService:createIntents', intents);\n return 'completed';\n },\n};\n"]}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Step } from "./step.cjs";
|
|
2
|
+
/**
|
|
3
|
+
* Registers CHOMP intents for the auto-deposit / auto-withdrawal delegations
|
|
4
|
+
* persisted by the build-delegation step.
|
|
5
|
+
*
|
|
6
|
+
* For each stored delegation between this account and CHOMP's delegate on
|
|
7
|
+
* this chain, the step builds an intent referencing the stored
|
|
8
|
+
* `delegationHash` and submits the batch to `POST /v1/intent`. Delegations
|
|
9
|
+
* whose `delegationHash` already has an active intent on CHOMP are skipped
|
|
10
|
+
* (revoked intents are re-registered). Reports `'already-done'` when every
|
|
11
|
+
* eligible delegation already has an active intent.
|
|
12
|
+
*
|
|
13
|
+
* Once registered, CHOMP re-fetches the delegation from Authenticated User
|
|
14
|
+
* Storage, re-validates it, and adds the account to its monitoring list so
|
|
15
|
+
* subsequent eligible operations can be picked up automatically.
|
|
16
|
+
*/
|
|
17
|
+
export declare const registerIntentsStep: Step;
|
|
18
|
+
//# sourceMappingURL=register-intents.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"register-intents.d.cts","sourceRoot":"","sources":["../../src/steps/register-intents.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,IAAI,EAAE,mBAAe;AAqBnC;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,mBAAmB,EAAE,IAsDjC,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Step } from "./step.mjs";
|
|
2
|
+
/**
|
|
3
|
+
* Registers CHOMP intents for the auto-deposit / auto-withdrawal delegations
|
|
4
|
+
* persisted by the build-delegation step.
|
|
5
|
+
*
|
|
6
|
+
* For each stored delegation between this account and CHOMP's delegate on
|
|
7
|
+
* this chain, the step builds an intent referencing the stored
|
|
8
|
+
* `delegationHash` and submits the batch to `POST /v1/intent`. Delegations
|
|
9
|
+
* whose `delegationHash` already has an active intent on CHOMP are skipped
|
|
10
|
+
* (revoked intents are re-registered). Reports `'already-done'` when every
|
|
11
|
+
* eligible delegation already has an active intent.
|
|
12
|
+
*
|
|
13
|
+
* Once registered, CHOMP re-fetches the delegation from Authenticated User
|
|
14
|
+
* Storage, re-validates it, and adds the account to its monitoring list so
|
|
15
|
+
* subsequent eligible operations can be picked up automatically.
|
|
16
|
+
*/
|
|
17
|
+
export declare const registerIntentsStep: Step;
|
|
18
|
+
//# sourceMappingURL=register-intents.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"register-intents.d.mts","sourceRoot":"","sources":["../../src/steps/register-intents.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,IAAI,EAAE,mBAAe;AAqBnC;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,mBAAmB,EAAE,IAsDjC,CAAC"}
|