@metamask-previews/claims-controller 0.0.0-preview-1f85e85a
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 +22 -0
- package/LICENSE +20 -0
- package/README.md +15 -0
- package/dist/ClaimsController.cjs +134 -0
- package/dist/ClaimsController.cjs.map +1 -0
- package/dist/ClaimsController.d.cts +48 -0
- package/dist/ClaimsController.d.cts.map +1 -0
- package/dist/ClaimsController.d.mts +48 -0
- package/dist/ClaimsController.d.mts.map +1 -0
- package/dist/ClaimsController.mjs +129 -0
- package/dist/ClaimsController.mjs.map +1 -0
- package/dist/ClaimsService.cjs +142 -0
- package/dist/ClaimsService.cjs.map +1 -0
- package/dist/ClaimsService.d.cts +87 -0
- package/dist/ClaimsService.d.cts.map +1 -0
- package/dist/ClaimsService.d.mts +87 -0
- package/dist/ClaimsService.d.mts.map +1 -0
- package/dist/ClaimsService.mjs +138 -0
- package/dist/ClaimsService.mjs.map +1 -0
- package/dist/constants.cjs +39 -0
- package/dist/constants.cjs.map +1 -0
- package/dist/constants.d.cts +22 -0
- package/dist/constants.d.cts.map +1 -0
- package/dist/constants.d.mts +22 -0
- package/dist/constants.d.mts.map +1 -0
- package/dist/constants.mjs +36 -0
- package/dist/constants.mjs.map +1 -0
- package/dist/index.cjs +12 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +7 -0
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.mts +7 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +4 -0
- package/dist/index.mjs.map +1 -0
- package/dist/types.cjs +3 -0
- package/dist/types.cjs.map +1 -0
- package/dist/types.d.cts +54 -0
- package/dist/types.d.cts.map +1 -0
- package/dist/types.d.mts +54 -0
- package/dist/types.d.mts.map +1 -0
- package/dist/types.mjs +2 -0
- package/dist/types.mjs.map +1 -0
- package/package.json +76 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- Added new `@metamask/claims-controller` package to handle shield subscription claims logics. ([#7072](https://github.com/MetaMask/core/pull/7072))
|
|
13
|
+
- Implementation of `ClaimsController`. ([#7072](https://github.com/MetaMask/core/pull/7072))
|
|
14
|
+
- `getSubmitClaimConfig`: Generate configurations required for the claim submission.
|
|
15
|
+
- `generateClaimSignature`: Generate signature for the claim submission.
|
|
16
|
+
- Implementation of Data-Service, `ClaimsService`. ([#7072](https://github.com/MetaMask/core/pull/7072))
|
|
17
|
+
- `getClaims`: fetch list of users' claims from the backend.
|
|
18
|
+
- `getClaimById`: fetch single claim by id.
|
|
19
|
+
- `generateMessageForClaimSignature`: generate message to sign for the claim signature.
|
|
20
|
+
- `verifyClaimSignature`: verify claim signature produced by user.
|
|
21
|
+
|
|
22
|
+
[Unreleased]: https://github.com/MetaMask/core/
|
package/LICENSE
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 MetaMask
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
package/README.md
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# `@metamask/claims-controller`
|
|
2
|
+
|
|
3
|
+
Controller handling shield subscription claims logic
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
`yarn add @metamask/claims-controller`
|
|
8
|
+
|
|
9
|
+
or
|
|
10
|
+
|
|
11
|
+
`npm install @metamask/claims-controller`
|
|
12
|
+
|
|
13
|
+
## Contributing
|
|
14
|
+
|
|
15
|
+
This package is part of a monorepo. Instructions for contributing can be found in the [monorepo README](https://github.com/MetaMask/core#readme).
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
3
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
4
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
5
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
6
|
+
};
|
|
7
|
+
var _ClaimsController_instances, _ClaimsController_validateSubmitClaimRequest;
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.ClaimsController = exports.getDefaultClaimsControllerState = void 0;
|
|
10
|
+
const base_controller_1 = require("@metamask/base-controller");
|
|
11
|
+
const controller_utils_1 = require("@metamask/controller-utils");
|
|
12
|
+
const constants_1 = require("./constants.cjs");
|
|
13
|
+
const ClaimsControllerStateMetadata = {
|
|
14
|
+
claims: {
|
|
15
|
+
includeInStateLogs: true,
|
|
16
|
+
persist: true,
|
|
17
|
+
includeInDebugSnapshot: true,
|
|
18
|
+
usedInUi: true,
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Get an initial default state for the controller.
|
|
23
|
+
*
|
|
24
|
+
* @returns The initial default controller state.
|
|
25
|
+
*/
|
|
26
|
+
function getDefaultClaimsControllerState() {
|
|
27
|
+
return {
|
|
28
|
+
claims: [],
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
exports.getDefaultClaimsControllerState = getDefaultClaimsControllerState;
|
|
32
|
+
class ClaimsController extends base_controller_1.BaseController {
|
|
33
|
+
constructor({ messenger, state }) {
|
|
34
|
+
super({
|
|
35
|
+
messenger,
|
|
36
|
+
metadata: ClaimsControllerStateMetadata,
|
|
37
|
+
name: constants_1.CONTROLLER_NAME,
|
|
38
|
+
state: { ...getDefaultClaimsControllerState(), ...state },
|
|
39
|
+
});
|
|
40
|
+
_ClaimsController_instances.add(this);
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Get required config for submitting a claim.
|
|
44
|
+
*
|
|
45
|
+
* @param claim - The claim request to get the required config for.
|
|
46
|
+
* @returns The required config for submitting the claim.
|
|
47
|
+
*/
|
|
48
|
+
async getSubmitClaimConfig(claim) {
|
|
49
|
+
// Validate the claim before submitting it.
|
|
50
|
+
__classPrivateFieldGet(this, _ClaimsController_instances, "m", _ClaimsController_validateSubmitClaimRequest).call(this, claim);
|
|
51
|
+
const headers = await this.messenger.call(`${constants_1.SERVICE_NAME}:getRequestHeaders`, constants_1.HttpContentTypeHeader.MULTIPART_FORM_DATA);
|
|
52
|
+
const baseUrl = this.messenger.call(`${constants_1.SERVICE_NAME}:getClaimsApiUrl`);
|
|
53
|
+
const url = `${baseUrl}/claims`;
|
|
54
|
+
return {
|
|
55
|
+
data: claim,
|
|
56
|
+
headers,
|
|
57
|
+
method: 'POST',
|
|
58
|
+
url,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Generate a signature for a claim.
|
|
63
|
+
*
|
|
64
|
+
* @param chainId - The chain id of the claim.
|
|
65
|
+
* @param walletAddress - The impacted wallet address of the claim.
|
|
66
|
+
* @returns The signature for the claim.
|
|
67
|
+
*/
|
|
68
|
+
async generateClaimSignature(chainId, walletAddress) {
|
|
69
|
+
// generate the message to be signed
|
|
70
|
+
const { message } = await this.messenger.call(`${constants_1.SERVICE_NAME}:generateMessageForClaimSignature`, chainId, walletAddress);
|
|
71
|
+
console.log('message', message);
|
|
72
|
+
// generate and parse the SIWE message
|
|
73
|
+
const messageHex = textToHex(message);
|
|
74
|
+
const siwe = (0, controller_utils_1.detectSIWE)({ data: messageHex });
|
|
75
|
+
if (!siwe.isSIWEMessage) {
|
|
76
|
+
throw new Error('Invalid Signature message');
|
|
77
|
+
}
|
|
78
|
+
// sign the message
|
|
79
|
+
const signature = await this.messenger.call('KeyringController:signPersonalMessage', {
|
|
80
|
+
data: message,
|
|
81
|
+
from: walletAddress,
|
|
82
|
+
siwe,
|
|
83
|
+
});
|
|
84
|
+
console.log('signature', signature);
|
|
85
|
+
// verify the signature
|
|
86
|
+
const isSignatureValid = await this.messenger.call(`${constants_1.SERVICE_NAME}:verifyClaimSignature`, signature, walletAddress, message);
|
|
87
|
+
if (!isSignatureValid) {
|
|
88
|
+
throw new Error('Invalid signature');
|
|
89
|
+
}
|
|
90
|
+
return signature;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Get the list of claims for the current user.
|
|
94
|
+
*
|
|
95
|
+
* @returns The list of claims for the current user.
|
|
96
|
+
*/
|
|
97
|
+
async getClaims() {
|
|
98
|
+
const claims = await this.messenger.call(`${constants_1.SERVICE_NAME}:getClaims`);
|
|
99
|
+
this.update((state) => {
|
|
100
|
+
state.claims = claims;
|
|
101
|
+
});
|
|
102
|
+
return claims;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
exports.ClaimsController = ClaimsController;
|
|
106
|
+
_ClaimsController_instances = new WeakSet(), _ClaimsController_validateSubmitClaimRequest = function _ClaimsController_validateSubmitClaimRequest(claim) {
|
|
107
|
+
const { claims: existingClaims } = this.state;
|
|
108
|
+
const isClaimAlreadySubmitted = existingClaims.some((existingClaim) => existingClaim.email === claim.email &&
|
|
109
|
+
existingClaim.impactedTxHash === claim.impactedTxHash);
|
|
110
|
+
if (isClaimAlreadySubmitted) {
|
|
111
|
+
throw new Error('Claim already submitted');
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
/**
|
|
115
|
+
* Converts a text string to its hexadecimal representation.
|
|
116
|
+
*
|
|
117
|
+
* @param text - The input string.
|
|
118
|
+
* @returns The hexadecimal representation of the string's UTF-8 bytes.
|
|
119
|
+
*/
|
|
120
|
+
function textToHex(text) {
|
|
121
|
+
// 1. Encode the string into a Uint8Array (UTF-8 bytes)
|
|
122
|
+
const encoder = new TextEncoder();
|
|
123
|
+
const utf8Bytes = encoder.encode(text);
|
|
124
|
+
// 2. Convert bytes to hex string
|
|
125
|
+
let hexString = '';
|
|
126
|
+
for (const byte of utf8Bytes) {
|
|
127
|
+
// Convert the byte (a number 0-255) to a hexadecimal string
|
|
128
|
+
const hex = byte.toString(16);
|
|
129
|
+
// Ensure the hex value is always two characters long by padding with a leading zero
|
|
130
|
+
hexString += hex.padStart(2, '0');
|
|
131
|
+
}
|
|
132
|
+
return `0x${hexString}`;
|
|
133
|
+
}
|
|
134
|
+
//# sourceMappingURL=ClaimsController.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ClaimsController.cjs","sourceRoot":"","sources":["../src/ClaimsController.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n StateMetadata,\n} from '@metamask/base-controller';\nimport { BaseController } from '@metamask/base-controller';\nimport { detectSIWE } from '@metamask/controller-utils';\nimport type { KeyringControllerSignPersonalMessageAction } from '@metamask/keyring-controller';\nimport type { Messenger } from '@metamask/messenger';\nimport type { Hex } from '@metamask/utils';\n\nimport type {\n ClaimsServiceGenerateMessageForClaimSignatureAction,\n ClaimsServiceGetClaimByIdAction,\n ClaimsServiceGetClaimsAction,\n ClaimsServiceGetClaimsApiUrlAction,\n ClaimsServiceGetRequestHeadersAction,\n ClaimsServiceVerifyClaimSignatureAction,\n} from './ClaimsService';\nimport {\n CONTROLLER_NAME,\n HttpContentTypeHeader,\n SERVICE_NAME,\n} from './constants';\nimport type {\n Claim,\n ClaimsControllerState,\n CreateClaimRequest,\n SubmitClaimConfig,\n} from './types';\n\nexport type ClaimsControllerGetStateAction = ControllerGetStateAction<\n typeof CONTROLLER_NAME,\n ClaimsControllerState\n>;\n\nexport type ClaimsControllerActions = ClaimsControllerGetStateAction;\n\nexport type AllowedActions =\n | ClaimsServiceGetClaimsAction\n | ClaimsServiceGetClaimByIdAction\n | ClaimsServiceGetRequestHeadersAction\n | ClaimsServiceGetClaimsApiUrlAction\n | ClaimsServiceGenerateMessageForClaimSignatureAction\n | ClaimsServiceVerifyClaimSignatureAction\n | ClaimsServiceGetClaimsAction\n | KeyringControllerSignPersonalMessageAction;\n\nexport type ClaimsControllerStateChangeEvent = ControllerStateChangeEvent<\n typeof CONTROLLER_NAME,\n ClaimsControllerState\n>;\n\nexport type ClaimsControllerMessenger = Messenger<\n typeof CONTROLLER_NAME,\n ClaimsControllerActions | AllowedActions,\n ClaimsControllerStateChangeEvent\n>;\n\nexport type ClaimsControllerOptions = {\n messenger: ClaimsControllerMessenger;\n state?: Partial<ClaimsControllerState>;\n};\n\nconst ClaimsControllerStateMetadata: StateMetadata<ClaimsControllerState> = {\n claims: {\n includeInStateLogs: true,\n persist: true,\n includeInDebugSnapshot: true,\n usedInUi: true,\n },\n};\n\n/**\n * Get an initial default state for the controller.\n *\n * @returns The initial default controller state.\n */\nexport function getDefaultClaimsControllerState(): ClaimsControllerState {\n return {\n claims: [],\n };\n}\n\nexport class ClaimsController extends BaseController<\n typeof CONTROLLER_NAME,\n ClaimsControllerState,\n ClaimsControllerMessenger\n> {\n constructor({ messenger, state }: ClaimsControllerOptions) {\n super({\n messenger,\n metadata: ClaimsControllerStateMetadata,\n name: CONTROLLER_NAME,\n state: { ...getDefaultClaimsControllerState(), ...state },\n });\n }\n\n /**\n * Get required config for submitting a claim.\n *\n * @param claim - The claim request to get the required config for.\n * @returns The required config for submitting the claim.\n */\n async getSubmitClaimConfig(\n claim: CreateClaimRequest,\n ): Promise<SubmitClaimConfig> {\n // Validate the claim before submitting it.\n this.#validateSubmitClaimRequest(claim);\n\n const headers = await this.messenger.call(\n `${SERVICE_NAME}:getRequestHeaders`,\n HttpContentTypeHeader.MULTIPART_FORM_DATA,\n );\n const baseUrl = this.messenger.call(`${SERVICE_NAME}:getClaimsApiUrl`);\n const url = `${baseUrl}/claims`;\n\n return {\n data: claim,\n headers,\n method: 'POST',\n url,\n };\n }\n\n /**\n * Generate a signature for a claim.\n *\n * @param chainId - The chain id of the claim.\n * @param walletAddress - The impacted wallet address of the claim.\n * @returns The signature for the claim.\n */\n async generateClaimSignature(\n chainId: number,\n walletAddress: `0x${string}`,\n ): Promise<string> {\n // generate the message to be signed\n const { message } = await this.messenger.call(\n `${SERVICE_NAME}:generateMessageForClaimSignature`,\n chainId,\n walletAddress,\n );\n console.log('message', message);\n\n // generate and parse the SIWE message\n const messageHex = textToHex(message);\n const siwe = detectSIWE({ data: messageHex });\n if (!siwe.isSIWEMessage) {\n throw new Error('Invalid Signature message');\n }\n\n // sign the message\n const signature = await this.messenger.call(\n 'KeyringController:signPersonalMessage',\n {\n data: message,\n from: walletAddress,\n siwe,\n },\n );\n console.log('signature', signature);\n\n // verify the signature\n const isSignatureValid = await this.messenger.call(\n `${SERVICE_NAME}:verifyClaimSignature`,\n signature as Hex,\n walletAddress,\n message,\n );\n\n if (!isSignatureValid) {\n throw new Error('Invalid signature');\n }\n\n return signature;\n }\n\n /**\n * Get the list of claims for the current user.\n *\n * @returns The list of claims for the current user.\n */\n async getClaims(): Promise<Claim[]> {\n const claims = await this.messenger.call(`${SERVICE_NAME}:getClaims`);\n this.update((state) => {\n state.claims = claims;\n });\n return claims;\n }\n\n /**\n * Validate the claim before submitting it.\n *\n * @param claim - The claim to validate.\n */\n #validateSubmitClaimRequest(claim: CreateClaimRequest): void {\n const { claims: existingClaims } = this.state;\n const isClaimAlreadySubmitted = existingClaims.some(\n (existingClaim) =>\n existingClaim.email === claim.email &&\n existingClaim.impactedTxHash === claim.impactedTxHash,\n // Question: should we allow users to submit the rejected claim again?\n );\n if (isClaimAlreadySubmitted) {\n throw new Error('Claim already submitted');\n }\n }\n}\n\n/**\n * Converts a text string to its hexadecimal representation.\n *\n * @param text - The input string.\n * @returns The hexadecimal representation of the string's UTF-8 bytes.\n */\nfunction textToHex(text: string): Hex {\n // 1. Encode the string into a Uint8Array (UTF-8 bytes)\n const encoder = new TextEncoder();\n const utf8Bytes = encoder.encode(text);\n\n // 2. Convert bytes to hex string\n let hexString = '';\n for (const byte of utf8Bytes) {\n // Convert the byte (a number 0-255) to a hexadecimal string\n const hex = byte.toString(16);\n\n // Ensure the hex value is always two characters long by padding with a leading zero\n hexString += hex.padStart(2, '0');\n }\n\n return `0x${hexString}`;\n}\n"]}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { ControllerGetStateAction, ControllerStateChangeEvent } from "@metamask/base-controller";
|
|
2
|
+
import { BaseController } from "@metamask/base-controller";
|
|
3
|
+
import type { KeyringControllerSignPersonalMessageAction } from "@metamask/keyring-controller";
|
|
4
|
+
import type { Messenger } from "@metamask/messenger";
|
|
5
|
+
import type { ClaimsServiceGenerateMessageForClaimSignatureAction, ClaimsServiceGetClaimByIdAction, ClaimsServiceGetClaimsAction, ClaimsServiceGetClaimsApiUrlAction, ClaimsServiceGetRequestHeadersAction, ClaimsServiceVerifyClaimSignatureAction } from "./ClaimsService.cjs";
|
|
6
|
+
import { CONTROLLER_NAME } from "./constants.cjs";
|
|
7
|
+
import type { Claim, ClaimsControllerState, CreateClaimRequest, SubmitClaimConfig } from "./types.cjs";
|
|
8
|
+
export type ClaimsControllerGetStateAction = ControllerGetStateAction<typeof CONTROLLER_NAME, ClaimsControllerState>;
|
|
9
|
+
export type ClaimsControllerActions = ClaimsControllerGetStateAction;
|
|
10
|
+
export type AllowedActions = ClaimsServiceGetClaimsAction | ClaimsServiceGetClaimByIdAction | ClaimsServiceGetRequestHeadersAction | ClaimsServiceGetClaimsApiUrlAction | ClaimsServiceGenerateMessageForClaimSignatureAction | ClaimsServiceVerifyClaimSignatureAction | ClaimsServiceGetClaimsAction | KeyringControllerSignPersonalMessageAction;
|
|
11
|
+
export type ClaimsControllerStateChangeEvent = ControllerStateChangeEvent<typeof CONTROLLER_NAME, ClaimsControllerState>;
|
|
12
|
+
export type ClaimsControllerMessenger = Messenger<typeof CONTROLLER_NAME, ClaimsControllerActions | AllowedActions, ClaimsControllerStateChangeEvent>;
|
|
13
|
+
export type ClaimsControllerOptions = {
|
|
14
|
+
messenger: ClaimsControllerMessenger;
|
|
15
|
+
state?: Partial<ClaimsControllerState>;
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Get an initial default state for the controller.
|
|
19
|
+
*
|
|
20
|
+
* @returns The initial default controller state.
|
|
21
|
+
*/
|
|
22
|
+
export declare function getDefaultClaimsControllerState(): ClaimsControllerState;
|
|
23
|
+
export declare class ClaimsController extends BaseController<typeof CONTROLLER_NAME, ClaimsControllerState, ClaimsControllerMessenger> {
|
|
24
|
+
#private;
|
|
25
|
+
constructor({ messenger, state }: ClaimsControllerOptions);
|
|
26
|
+
/**
|
|
27
|
+
* Get required config for submitting a claim.
|
|
28
|
+
*
|
|
29
|
+
* @param claim - The claim request to get the required config for.
|
|
30
|
+
* @returns The required config for submitting the claim.
|
|
31
|
+
*/
|
|
32
|
+
getSubmitClaimConfig(claim: CreateClaimRequest): Promise<SubmitClaimConfig>;
|
|
33
|
+
/**
|
|
34
|
+
* Generate a signature for a claim.
|
|
35
|
+
*
|
|
36
|
+
* @param chainId - The chain id of the claim.
|
|
37
|
+
* @param walletAddress - The impacted wallet address of the claim.
|
|
38
|
+
* @returns The signature for the claim.
|
|
39
|
+
*/
|
|
40
|
+
generateClaimSignature(chainId: number, walletAddress: `0x${string}`): Promise<string>;
|
|
41
|
+
/**
|
|
42
|
+
* Get the list of claims for the current user.
|
|
43
|
+
*
|
|
44
|
+
* @returns The list of claims for the current user.
|
|
45
|
+
*/
|
|
46
|
+
getClaims(): Promise<Claim[]>;
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=ClaimsController.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ClaimsController.d.cts","sourceRoot":"","sources":["../src/ClaimsController.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,wBAAwB,EACxB,0BAA0B,EAE3B,kCAAkC;AACnC,OAAO,EAAE,cAAc,EAAE,kCAAkC;AAE3D,OAAO,KAAK,EAAE,0CAA0C,EAAE,qCAAqC;AAC/F,OAAO,KAAK,EAAE,SAAS,EAAE,4BAA4B;AAGrD,OAAO,KAAK,EACV,mDAAmD,EACnD,+BAA+B,EAC/B,4BAA4B,EAC5B,kCAAkC,EAClC,oCAAoC,EACpC,uCAAuC,EACxC,4BAAwB;AACzB,OAAO,EACL,eAAe,EAGhB,wBAAoB;AACrB,OAAO,KAAK,EACV,KAAK,EACL,qBAAqB,EACrB,kBAAkB,EAClB,iBAAiB,EAClB,oBAAgB;AAEjB,MAAM,MAAM,8BAA8B,GAAG,wBAAwB,CACnE,OAAO,eAAe,EACtB,qBAAqB,CACtB,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAAG,8BAA8B,CAAC;AAErE,MAAM,MAAM,cAAc,GACtB,4BAA4B,GAC5B,+BAA+B,GAC/B,oCAAoC,GACpC,kCAAkC,GAClC,mDAAmD,GACnD,uCAAuC,GACvC,4BAA4B,GAC5B,0CAA0C,CAAC;AAE/C,MAAM,MAAM,gCAAgC,GAAG,0BAA0B,CACvE,OAAO,eAAe,EACtB,qBAAqB,CACtB,CAAC;AAEF,MAAM,MAAM,yBAAyB,GAAG,SAAS,CAC/C,OAAO,eAAe,EACtB,uBAAuB,GAAG,cAAc,EACxC,gCAAgC,CACjC,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAAG;IACpC,SAAS,EAAE,yBAAyB,CAAC;IACrC,KAAK,CAAC,EAAE,OAAO,CAAC,qBAAqB,CAAC,CAAC;CACxC,CAAC;AAWF;;;;GAIG;AACH,wBAAgB,+BAA+B,IAAI,qBAAqB,CAIvE;AAED,qBAAa,gBAAiB,SAAQ,cAAc,CAClD,OAAO,eAAe,EACtB,qBAAqB,EACrB,yBAAyB,CAC1B;;gBACa,EAAE,SAAS,EAAE,KAAK,EAAE,EAAE,uBAAuB;IASzD;;;;;OAKG;IACG,oBAAoB,CACxB,KAAK,EAAE,kBAAkB,GACxB,OAAO,CAAC,iBAAiB,CAAC;IAmB7B;;;;;;OAMG;IACG,sBAAsB,CAC1B,OAAO,EAAE,MAAM,EACf,aAAa,EAAE,KAAK,MAAM,EAAE,GAC3B,OAAO,CAAC,MAAM,CAAC;IA0ClB;;;;OAIG;IACG,SAAS,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;CAyBpC"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { ControllerGetStateAction, ControllerStateChangeEvent } from "@metamask/base-controller";
|
|
2
|
+
import { BaseController } from "@metamask/base-controller";
|
|
3
|
+
import type { KeyringControllerSignPersonalMessageAction } from "@metamask/keyring-controller";
|
|
4
|
+
import type { Messenger } from "@metamask/messenger";
|
|
5
|
+
import type { ClaimsServiceGenerateMessageForClaimSignatureAction, ClaimsServiceGetClaimByIdAction, ClaimsServiceGetClaimsAction, ClaimsServiceGetClaimsApiUrlAction, ClaimsServiceGetRequestHeadersAction, ClaimsServiceVerifyClaimSignatureAction } from "./ClaimsService.mjs";
|
|
6
|
+
import { CONTROLLER_NAME } from "./constants.mjs";
|
|
7
|
+
import type { Claim, ClaimsControllerState, CreateClaimRequest, SubmitClaimConfig } from "./types.mjs";
|
|
8
|
+
export type ClaimsControllerGetStateAction = ControllerGetStateAction<typeof CONTROLLER_NAME, ClaimsControllerState>;
|
|
9
|
+
export type ClaimsControllerActions = ClaimsControllerGetStateAction;
|
|
10
|
+
export type AllowedActions = ClaimsServiceGetClaimsAction | ClaimsServiceGetClaimByIdAction | ClaimsServiceGetRequestHeadersAction | ClaimsServiceGetClaimsApiUrlAction | ClaimsServiceGenerateMessageForClaimSignatureAction | ClaimsServiceVerifyClaimSignatureAction | ClaimsServiceGetClaimsAction | KeyringControllerSignPersonalMessageAction;
|
|
11
|
+
export type ClaimsControllerStateChangeEvent = ControllerStateChangeEvent<typeof CONTROLLER_NAME, ClaimsControllerState>;
|
|
12
|
+
export type ClaimsControllerMessenger = Messenger<typeof CONTROLLER_NAME, ClaimsControllerActions | AllowedActions, ClaimsControllerStateChangeEvent>;
|
|
13
|
+
export type ClaimsControllerOptions = {
|
|
14
|
+
messenger: ClaimsControllerMessenger;
|
|
15
|
+
state?: Partial<ClaimsControllerState>;
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Get an initial default state for the controller.
|
|
19
|
+
*
|
|
20
|
+
* @returns The initial default controller state.
|
|
21
|
+
*/
|
|
22
|
+
export declare function getDefaultClaimsControllerState(): ClaimsControllerState;
|
|
23
|
+
export declare class ClaimsController extends BaseController<typeof CONTROLLER_NAME, ClaimsControllerState, ClaimsControllerMessenger> {
|
|
24
|
+
#private;
|
|
25
|
+
constructor({ messenger, state }: ClaimsControllerOptions);
|
|
26
|
+
/**
|
|
27
|
+
* Get required config for submitting a claim.
|
|
28
|
+
*
|
|
29
|
+
* @param claim - The claim request to get the required config for.
|
|
30
|
+
* @returns The required config for submitting the claim.
|
|
31
|
+
*/
|
|
32
|
+
getSubmitClaimConfig(claim: CreateClaimRequest): Promise<SubmitClaimConfig>;
|
|
33
|
+
/**
|
|
34
|
+
* Generate a signature for a claim.
|
|
35
|
+
*
|
|
36
|
+
* @param chainId - The chain id of the claim.
|
|
37
|
+
* @param walletAddress - The impacted wallet address of the claim.
|
|
38
|
+
* @returns The signature for the claim.
|
|
39
|
+
*/
|
|
40
|
+
generateClaimSignature(chainId: number, walletAddress: `0x${string}`): Promise<string>;
|
|
41
|
+
/**
|
|
42
|
+
* Get the list of claims for the current user.
|
|
43
|
+
*
|
|
44
|
+
* @returns The list of claims for the current user.
|
|
45
|
+
*/
|
|
46
|
+
getClaims(): Promise<Claim[]>;
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=ClaimsController.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ClaimsController.d.mts","sourceRoot":"","sources":["../src/ClaimsController.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,wBAAwB,EACxB,0BAA0B,EAE3B,kCAAkC;AACnC,OAAO,EAAE,cAAc,EAAE,kCAAkC;AAE3D,OAAO,KAAK,EAAE,0CAA0C,EAAE,qCAAqC;AAC/F,OAAO,KAAK,EAAE,SAAS,EAAE,4BAA4B;AAGrD,OAAO,KAAK,EACV,mDAAmD,EACnD,+BAA+B,EAC/B,4BAA4B,EAC5B,kCAAkC,EAClC,oCAAoC,EACpC,uCAAuC,EACxC,4BAAwB;AACzB,OAAO,EACL,eAAe,EAGhB,wBAAoB;AACrB,OAAO,KAAK,EACV,KAAK,EACL,qBAAqB,EACrB,kBAAkB,EAClB,iBAAiB,EAClB,oBAAgB;AAEjB,MAAM,MAAM,8BAA8B,GAAG,wBAAwB,CACnE,OAAO,eAAe,EACtB,qBAAqB,CACtB,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAAG,8BAA8B,CAAC;AAErE,MAAM,MAAM,cAAc,GACtB,4BAA4B,GAC5B,+BAA+B,GAC/B,oCAAoC,GACpC,kCAAkC,GAClC,mDAAmD,GACnD,uCAAuC,GACvC,4BAA4B,GAC5B,0CAA0C,CAAC;AAE/C,MAAM,MAAM,gCAAgC,GAAG,0BAA0B,CACvE,OAAO,eAAe,EACtB,qBAAqB,CACtB,CAAC;AAEF,MAAM,MAAM,yBAAyB,GAAG,SAAS,CAC/C,OAAO,eAAe,EACtB,uBAAuB,GAAG,cAAc,EACxC,gCAAgC,CACjC,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAAG;IACpC,SAAS,EAAE,yBAAyB,CAAC;IACrC,KAAK,CAAC,EAAE,OAAO,CAAC,qBAAqB,CAAC,CAAC;CACxC,CAAC;AAWF;;;;GAIG;AACH,wBAAgB,+BAA+B,IAAI,qBAAqB,CAIvE;AAED,qBAAa,gBAAiB,SAAQ,cAAc,CAClD,OAAO,eAAe,EACtB,qBAAqB,EACrB,yBAAyB,CAC1B;;gBACa,EAAE,SAAS,EAAE,KAAK,EAAE,EAAE,uBAAuB;IASzD;;;;;OAKG;IACG,oBAAoB,CACxB,KAAK,EAAE,kBAAkB,GACxB,OAAO,CAAC,iBAAiB,CAAC;IAmB7B;;;;;;OAMG;IACG,sBAAsB,CAC1B,OAAO,EAAE,MAAM,EACf,aAAa,EAAE,KAAK,MAAM,EAAE,GAC3B,OAAO,CAAC,MAAM,CAAC;IA0ClB;;;;OAIG;IACG,SAAS,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;CAyBpC"}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
2
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
3
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
4
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
5
|
+
};
|
|
6
|
+
var _ClaimsController_instances, _ClaimsController_validateSubmitClaimRequest;
|
|
7
|
+
import { BaseController } from "@metamask/base-controller";
|
|
8
|
+
import { detectSIWE } from "@metamask/controller-utils";
|
|
9
|
+
import { CONTROLLER_NAME, HttpContentTypeHeader, SERVICE_NAME } from "./constants.mjs";
|
|
10
|
+
const ClaimsControllerStateMetadata = {
|
|
11
|
+
claims: {
|
|
12
|
+
includeInStateLogs: true,
|
|
13
|
+
persist: true,
|
|
14
|
+
includeInDebugSnapshot: true,
|
|
15
|
+
usedInUi: true,
|
|
16
|
+
},
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Get an initial default state for the controller.
|
|
20
|
+
*
|
|
21
|
+
* @returns The initial default controller state.
|
|
22
|
+
*/
|
|
23
|
+
export function getDefaultClaimsControllerState() {
|
|
24
|
+
return {
|
|
25
|
+
claims: [],
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
export class ClaimsController extends BaseController {
|
|
29
|
+
constructor({ messenger, state }) {
|
|
30
|
+
super({
|
|
31
|
+
messenger,
|
|
32
|
+
metadata: ClaimsControllerStateMetadata,
|
|
33
|
+
name: CONTROLLER_NAME,
|
|
34
|
+
state: { ...getDefaultClaimsControllerState(), ...state },
|
|
35
|
+
});
|
|
36
|
+
_ClaimsController_instances.add(this);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Get required config for submitting a claim.
|
|
40
|
+
*
|
|
41
|
+
* @param claim - The claim request to get the required config for.
|
|
42
|
+
* @returns The required config for submitting the claim.
|
|
43
|
+
*/
|
|
44
|
+
async getSubmitClaimConfig(claim) {
|
|
45
|
+
// Validate the claim before submitting it.
|
|
46
|
+
__classPrivateFieldGet(this, _ClaimsController_instances, "m", _ClaimsController_validateSubmitClaimRequest).call(this, claim);
|
|
47
|
+
const headers = await this.messenger.call(`${SERVICE_NAME}:getRequestHeaders`, HttpContentTypeHeader.MULTIPART_FORM_DATA);
|
|
48
|
+
const baseUrl = this.messenger.call(`${SERVICE_NAME}:getClaimsApiUrl`);
|
|
49
|
+
const url = `${baseUrl}/claims`;
|
|
50
|
+
return {
|
|
51
|
+
data: claim,
|
|
52
|
+
headers,
|
|
53
|
+
method: 'POST',
|
|
54
|
+
url,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Generate a signature for a claim.
|
|
59
|
+
*
|
|
60
|
+
* @param chainId - The chain id of the claim.
|
|
61
|
+
* @param walletAddress - The impacted wallet address of the claim.
|
|
62
|
+
* @returns The signature for the claim.
|
|
63
|
+
*/
|
|
64
|
+
async generateClaimSignature(chainId, walletAddress) {
|
|
65
|
+
// generate the message to be signed
|
|
66
|
+
const { message } = await this.messenger.call(`${SERVICE_NAME}:generateMessageForClaimSignature`, chainId, walletAddress);
|
|
67
|
+
console.log('message', message);
|
|
68
|
+
// generate and parse the SIWE message
|
|
69
|
+
const messageHex = textToHex(message);
|
|
70
|
+
const siwe = detectSIWE({ data: messageHex });
|
|
71
|
+
if (!siwe.isSIWEMessage) {
|
|
72
|
+
throw new Error('Invalid Signature message');
|
|
73
|
+
}
|
|
74
|
+
// sign the message
|
|
75
|
+
const signature = await this.messenger.call('KeyringController:signPersonalMessage', {
|
|
76
|
+
data: message,
|
|
77
|
+
from: walletAddress,
|
|
78
|
+
siwe,
|
|
79
|
+
});
|
|
80
|
+
console.log('signature', signature);
|
|
81
|
+
// verify the signature
|
|
82
|
+
const isSignatureValid = await this.messenger.call(`${SERVICE_NAME}:verifyClaimSignature`, signature, walletAddress, message);
|
|
83
|
+
if (!isSignatureValid) {
|
|
84
|
+
throw new Error('Invalid signature');
|
|
85
|
+
}
|
|
86
|
+
return signature;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Get the list of claims for the current user.
|
|
90
|
+
*
|
|
91
|
+
* @returns The list of claims for the current user.
|
|
92
|
+
*/
|
|
93
|
+
async getClaims() {
|
|
94
|
+
const claims = await this.messenger.call(`${SERVICE_NAME}:getClaims`);
|
|
95
|
+
this.update((state) => {
|
|
96
|
+
state.claims = claims;
|
|
97
|
+
});
|
|
98
|
+
return claims;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
_ClaimsController_instances = new WeakSet(), _ClaimsController_validateSubmitClaimRequest = function _ClaimsController_validateSubmitClaimRequest(claim) {
|
|
102
|
+
const { claims: existingClaims } = this.state;
|
|
103
|
+
const isClaimAlreadySubmitted = existingClaims.some((existingClaim) => existingClaim.email === claim.email &&
|
|
104
|
+
existingClaim.impactedTxHash === claim.impactedTxHash);
|
|
105
|
+
if (isClaimAlreadySubmitted) {
|
|
106
|
+
throw new Error('Claim already submitted');
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
/**
|
|
110
|
+
* Converts a text string to its hexadecimal representation.
|
|
111
|
+
*
|
|
112
|
+
* @param text - The input string.
|
|
113
|
+
* @returns The hexadecimal representation of the string's UTF-8 bytes.
|
|
114
|
+
*/
|
|
115
|
+
function textToHex(text) {
|
|
116
|
+
// 1. Encode the string into a Uint8Array (UTF-8 bytes)
|
|
117
|
+
const encoder = new TextEncoder();
|
|
118
|
+
const utf8Bytes = encoder.encode(text);
|
|
119
|
+
// 2. Convert bytes to hex string
|
|
120
|
+
let hexString = '';
|
|
121
|
+
for (const byte of utf8Bytes) {
|
|
122
|
+
// Convert the byte (a number 0-255) to a hexadecimal string
|
|
123
|
+
const hex = byte.toString(16);
|
|
124
|
+
// Ensure the hex value is always two characters long by padding with a leading zero
|
|
125
|
+
hexString += hex.padStart(2, '0');
|
|
126
|
+
}
|
|
127
|
+
return `0x${hexString}`;
|
|
128
|
+
}
|
|
129
|
+
//# sourceMappingURL=ClaimsController.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ClaimsController.mjs","sourceRoot":"","sources":["../src/ClaimsController.ts"],"names":[],"mappings":";;;;;;AAKA,OAAO,EAAE,cAAc,EAAE,kCAAkC;AAC3D,OAAO,EAAE,UAAU,EAAE,mCAAmC;AAaxD,OAAO,EACL,eAAe,EACf,qBAAqB,EACrB,YAAY,EACb,wBAAoB;AAyCrB,MAAM,6BAA6B,GAAyC;IAC1E,MAAM,EAAE;QACN,kBAAkB,EAAE,IAAI;QACxB,OAAO,EAAE,IAAI;QACb,sBAAsB,EAAE,IAAI;QAC5B,QAAQ,EAAE,IAAI;KACf;CACF,CAAC;AAEF;;;;GAIG;AACH,MAAM,UAAU,+BAA+B;IAC7C,OAAO;QACL,MAAM,EAAE,EAAE;KACX,CAAC;AACJ,CAAC;AAED,MAAM,OAAO,gBAAiB,SAAQ,cAIrC;IACC,YAAY,EAAE,SAAS,EAAE,KAAK,EAA2B;QACvD,KAAK,CAAC;YACJ,SAAS;YACT,QAAQ,EAAE,6BAA6B;YACvC,IAAI,EAAE,eAAe;YACrB,KAAK,EAAE,EAAE,GAAG,+BAA+B,EAAE,EAAE,GAAG,KAAK,EAAE;SAC1D,CAAC,CAAC;;IACL,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,oBAAoB,CACxB,KAAyB;QAEzB,2CAA2C;QAC3C,uBAAA,IAAI,iFAA4B,MAAhC,IAAI,EAA6B,KAAK,CAAC,CAAC;QAExC,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,IAAI,CACvC,GAAG,YAAY,oBAAoB,EACnC,qBAAqB,CAAC,mBAAmB,CAC1C,CAAC;QACF,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,YAAY,kBAAkB,CAAC,CAAC;QACvE,MAAM,GAAG,GAAG,GAAG,OAAO,SAAS,CAAC;QAEhC,OAAO;YACL,IAAI,EAAE,KAAK;YACX,OAAO;YACP,MAAM,EAAE,MAAM;YACd,GAAG;SACJ,CAAC;IACJ,CAAC;IAED;;;;;;OAMG;IACH,KAAK,CAAC,sBAAsB,CAC1B,OAAe,EACf,aAA4B;QAE5B,oCAAoC;QACpC,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,IAAI,CAC3C,GAAG,YAAY,mCAAmC,EAClD,OAAO,EACP,aAAa,CACd,CAAC;QACF,OAAO,CAAC,GAAG,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;QAEhC,sCAAsC;QACtC,MAAM,UAAU,GAAG,SAAS,CAAC,OAAO,CAAC,CAAC;QACtC,MAAM,IAAI,GAAG,UAAU,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,CAAC;QAC9C,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE;YACvB,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;SAC9C;QAED,mBAAmB;QACnB,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,IAAI,CACzC,uCAAuC,EACvC;YACE,IAAI,EAAE,OAAO;YACb,IAAI,EAAE,aAAa;YACnB,IAAI;SACL,CACF,CAAC;QACF,OAAO,CAAC,GAAG,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC;QAEpC,uBAAuB;QACvB,MAAM,gBAAgB,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,IAAI,CAChD,GAAG,YAAY,uBAAuB,EACtC,SAAgB,EAChB,aAAa,EACb,OAAO,CACR,CAAC;QAEF,IAAI,CAAC,gBAAgB,EAAE;YACrB,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC;SACtC;QAED,OAAO,SAAS,CAAC;IACnB,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,SAAS;QACb,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,YAAY,YAAY,CAAC,CAAC;QACtE,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE;YACpB,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC;QACxB,CAAC,CAAC,CAAC;QACH,OAAO,MAAM,CAAC;IAChB,CAAC;CAmBF;kJAZ6B,KAAyB;IACnD,MAAM,EAAE,MAAM,EAAE,cAAc,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC;IAC9C,MAAM,uBAAuB,GAAG,cAAc,CAAC,IAAI,CACjD,CAAC,aAAa,EAAE,EAAE,CAChB,aAAa,CAAC,KAAK,KAAK,KAAK,CAAC,KAAK;QACnC,aAAa,CAAC,cAAc,KAAK,KAAK,CAAC,cAAc,CAExD,CAAC;IACF,IAAI,uBAAuB,EAAE;QAC3B,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;KAC5C;AACH,CAAC;AAGH;;;;;GAKG;AACH,SAAS,SAAS,CAAC,IAAY;IAC7B,uDAAuD;IACvD,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;IAClC,MAAM,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAEvC,iCAAiC;IACjC,IAAI,SAAS,GAAG,EAAE,CAAC;IACnB,KAAK,MAAM,IAAI,IAAI,SAAS,EAAE;QAC5B,4DAA4D;QAC5D,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;QAE9B,oFAAoF;QACpF,SAAS,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;KACnC;IAED,OAAO,KAAK,SAAS,EAAE,CAAC;AAC1B,CAAC","sourcesContent":["import type {\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n StateMetadata,\n} from '@metamask/base-controller';\nimport { BaseController } from '@metamask/base-controller';\nimport { detectSIWE } from '@metamask/controller-utils';\nimport type { KeyringControllerSignPersonalMessageAction } from '@metamask/keyring-controller';\nimport type { Messenger } from '@metamask/messenger';\nimport type { Hex } from '@metamask/utils';\n\nimport type {\n ClaimsServiceGenerateMessageForClaimSignatureAction,\n ClaimsServiceGetClaimByIdAction,\n ClaimsServiceGetClaimsAction,\n ClaimsServiceGetClaimsApiUrlAction,\n ClaimsServiceGetRequestHeadersAction,\n ClaimsServiceVerifyClaimSignatureAction,\n} from './ClaimsService';\nimport {\n CONTROLLER_NAME,\n HttpContentTypeHeader,\n SERVICE_NAME,\n} from './constants';\nimport type {\n Claim,\n ClaimsControllerState,\n CreateClaimRequest,\n SubmitClaimConfig,\n} from './types';\n\nexport type ClaimsControllerGetStateAction = ControllerGetStateAction<\n typeof CONTROLLER_NAME,\n ClaimsControllerState\n>;\n\nexport type ClaimsControllerActions = ClaimsControllerGetStateAction;\n\nexport type AllowedActions =\n | ClaimsServiceGetClaimsAction\n | ClaimsServiceGetClaimByIdAction\n | ClaimsServiceGetRequestHeadersAction\n | ClaimsServiceGetClaimsApiUrlAction\n | ClaimsServiceGenerateMessageForClaimSignatureAction\n | ClaimsServiceVerifyClaimSignatureAction\n | ClaimsServiceGetClaimsAction\n | KeyringControllerSignPersonalMessageAction;\n\nexport type ClaimsControllerStateChangeEvent = ControllerStateChangeEvent<\n typeof CONTROLLER_NAME,\n ClaimsControllerState\n>;\n\nexport type ClaimsControllerMessenger = Messenger<\n typeof CONTROLLER_NAME,\n ClaimsControllerActions | AllowedActions,\n ClaimsControllerStateChangeEvent\n>;\n\nexport type ClaimsControllerOptions = {\n messenger: ClaimsControllerMessenger;\n state?: Partial<ClaimsControllerState>;\n};\n\nconst ClaimsControllerStateMetadata: StateMetadata<ClaimsControllerState> = {\n claims: {\n includeInStateLogs: true,\n persist: true,\n includeInDebugSnapshot: true,\n usedInUi: true,\n },\n};\n\n/**\n * Get an initial default state for the controller.\n *\n * @returns The initial default controller state.\n */\nexport function getDefaultClaimsControllerState(): ClaimsControllerState {\n return {\n claims: [],\n };\n}\n\nexport class ClaimsController extends BaseController<\n typeof CONTROLLER_NAME,\n ClaimsControllerState,\n ClaimsControllerMessenger\n> {\n constructor({ messenger, state }: ClaimsControllerOptions) {\n super({\n messenger,\n metadata: ClaimsControllerStateMetadata,\n name: CONTROLLER_NAME,\n state: { ...getDefaultClaimsControllerState(), ...state },\n });\n }\n\n /**\n * Get required config for submitting a claim.\n *\n * @param claim - The claim request to get the required config for.\n * @returns The required config for submitting the claim.\n */\n async getSubmitClaimConfig(\n claim: CreateClaimRequest,\n ): Promise<SubmitClaimConfig> {\n // Validate the claim before submitting it.\n this.#validateSubmitClaimRequest(claim);\n\n const headers = await this.messenger.call(\n `${SERVICE_NAME}:getRequestHeaders`,\n HttpContentTypeHeader.MULTIPART_FORM_DATA,\n );\n const baseUrl = this.messenger.call(`${SERVICE_NAME}:getClaimsApiUrl`);\n const url = `${baseUrl}/claims`;\n\n return {\n data: claim,\n headers,\n method: 'POST',\n url,\n };\n }\n\n /**\n * Generate a signature for a claim.\n *\n * @param chainId - The chain id of the claim.\n * @param walletAddress - The impacted wallet address of the claim.\n * @returns The signature for the claim.\n */\n async generateClaimSignature(\n chainId: number,\n walletAddress: `0x${string}`,\n ): Promise<string> {\n // generate the message to be signed\n const { message } = await this.messenger.call(\n `${SERVICE_NAME}:generateMessageForClaimSignature`,\n chainId,\n walletAddress,\n );\n console.log('message', message);\n\n // generate and parse the SIWE message\n const messageHex = textToHex(message);\n const siwe = detectSIWE({ data: messageHex });\n if (!siwe.isSIWEMessage) {\n throw new Error('Invalid Signature message');\n }\n\n // sign the message\n const signature = await this.messenger.call(\n 'KeyringController:signPersonalMessage',\n {\n data: message,\n from: walletAddress,\n siwe,\n },\n );\n console.log('signature', signature);\n\n // verify the signature\n const isSignatureValid = await this.messenger.call(\n `${SERVICE_NAME}:verifyClaimSignature`,\n signature as Hex,\n walletAddress,\n message,\n );\n\n if (!isSignatureValid) {\n throw new Error('Invalid signature');\n }\n\n return signature;\n }\n\n /**\n * Get the list of claims for the current user.\n *\n * @returns The list of claims for the current user.\n */\n async getClaims(): Promise<Claim[]> {\n const claims = await this.messenger.call(`${SERVICE_NAME}:getClaims`);\n this.update((state) => {\n state.claims = claims;\n });\n return claims;\n }\n\n /**\n * Validate the claim before submitting it.\n *\n * @param claim - The claim to validate.\n */\n #validateSubmitClaimRequest(claim: CreateClaimRequest): void {\n const { claims: existingClaims } = this.state;\n const isClaimAlreadySubmitted = existingClaims.some(\n (existingClaim) =>\n existingClaim.email === claim.email &&\n existingClaim.impactedTxHash === claim.impactedTxHash,\n // Question: should we allow users to submit the rejected claim again?\n );\n if (isClaimAlreadySubmitted) {\n throw new Error('Claim already submitted');\n }\n }\n}\n\n/**\n * Converts a text string to its hexadecimal representation.\n *\n * @param text - The input string.\n * @returns The hexadecimal representation of the string's UTF-8 bytes.\n */\nfunction textToHex(text: string): Hex {\n // 1. Encode the string into a Uint8Array (UTF-8 bytes)\n const encoder = new TextEncoder();\n const utf8Bytes = encoder.encode(text);\n\n // 2. Convert bytes to hex string\n let hexString = '';\n for (const byte of utf8Bytes) {\n // Convert the byte (a number 0-255) to a hexadecimal string\n const hex = byte.toString(16);\n\n // Ensure the hex value is always two characters long by padding with a leading zero\n hexString += hex.padStart(2, '0');\n }\n\n return `0x${hexString}`;\n}\n"]}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
|
3
|
+
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
4
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
5
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
6
|
+
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
7
|
+
};
|
|
8
|
+
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
9
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
10
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
11
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
12
|
+
};
|
|
13
|
+
var _ClaimsService_env, _ClaimsService_fetch, _ClaimsService_messenger;
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.ClaimsService = void 0;
|
|
16
|
+
const constants_1 = require("./constants.cjs");
|
|
17
|
+
class ClaimsService {
|
|
18
|
+
constructor({ env, messenger, fetchFunction }) {
|
|
19
|
+
this.name = constants_1.SERVICE_NAME; // required for Modular Initialization
|
|
20
|
+
_ClaimsService_env.set(this, void 0);
|
|
21
|
+
_ClaimsService_fetch.set(this, void 0);
|
|
22
|
+
_ClaimsService_messenger.set(this, void 0);
|
|
23
|
+
__classPrivateFieldSet(this, _ClaimsService_env, env, "f");
|
|
24
|
+
__classPrivateFieldSet(this, _ClaimsService_messenger, messenger, "f");
|
|
25
|
+
__classPrivateFieldSet(this, _ClaimsService_fetch, fetchFunction, "f");
|
|
26
|
+
__classPrivateFieldGet(this, _ClaimsService_messenger, "f").registerActionHandler(`${constants_1.SERVICE_NAME}:getClaims`, this.getClaims.bind(this));
|
|
27
|
+
__classPrivateFieldGet(this, _ClaimsService_messenger, "f").registerActionHandler(`${constants_1.SERVICE_NAME}:getClaimById`, this.getClaimById.bind(this));
|
|
28
|
+
__classPrivateFieldGet(this, _ClaimsService_messenger, "f").registerActionHandler(`${constants_1.SERVICE_NAME}:getRequestHeaders`, this.getRequestHeaders.bind(this));
|
|
29
|
+
__classPrivateFieldGet(this, _ClaimsService_messenger, "f").registerActionHandler(`${constants_1.SERVICE_NAME}:getClaimsApiUrl`, this.getClaimsApiUrl.bind(this));
|
|
30
|
+
__classPrivateFieldGet(this, _ClaimsService_messenger, "f").registerActionHandler(`${constants_1.SERVICE_NAME}:generateMessageForClaimSignature`, this.generateMessageForClaimSignature.bind(this));
|
|
31
|
+
__classPrivateFieldGet(this, _ClaimsService_messenger, "f").registerActionHandler(`${constants_1.SERVICE_NAME}:verifyClaimSignature`, this.verifyClaimSignature.bind(this));
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Get the claims for the current user.
|
|
35
|
+
*
|
|
36
|
+
* @returns The claims for the current user.
|
|
37
|
+
*/
|
|
38
|
+
async getClaims() {
|
|
39
|
+
const headers = await this.getRequestHeaders();
|
|
40
|
+
const url = `${this.getClaimsApiUrl()}/claims`;
|
|
41
|
+
const response = await __classPrivateFieldGet(this, _ClaimsService_fetch, "f").call(this, url, {
|
|
42
|
+
headers,
|
|
43
|
+
});
|
|
44
|
+
if (!response.ok) {
|
|
45
|
+
throw new Error('Failed to get claims');
|
|
46
|
+
}
|
|
47
|
+
const claims = await response.json();
|
|
48
|
+
return claims;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Get the claim by id.
|
|
52
|
+
*
|
|
53
|
+
* @param id - The id of the claim to get.
|
|
54
|
+
* @returns The claim by id.
|
|
55
|
+
*/
|
|
56
|
+
async getClaimById(id) {
|
|
57
|
+
const headers = await this.getRequestHeaders();
|
|
58
|
+
const url = `${this.getClaimsApiUrl()}/claims/byId/${id}`;
|
|
59
|
+
const response = await __classPrivateFieldGet(this, _ClaimsService_fetch, "f").call(this, url, {
|
|
60
|
+
headers,
|
|
61
|
+
});
|
|
62
|
+
if (!response.ok) {
|
|
63
|
+
throw new Error('Failed to get claim by id');
|
|
64
|
+
}
|
|
65
|
+
const claim = await response.json();
|
|
66
|
+
return claim;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Generate a message to be signed by the user for the claim request.
|
|
70
|
+
*
|
|
71
|
+
* @param chainId - The chain id of the claim.
|
|
72
|
+
* @param walletAddress - The impacted wallet address of the claim.
|
|
73
|
+
* @returns The message for the claim signature.
|
|
74
|
+
*/
|
|
75
|
+
async generateMessageForClaimSignature(chainId, walletAddress) {
|
|
76
|
+
const headers = await this.getRequestHeaders();
|
|
77
|
+
const url = `${this.getClaimsApiUrl()}/signature/generateMessage`;
|
|
78
|
+
const response = await __classPrivateFieldGet(this, _ClaimsService_fetch, "f").call(this, url, {
|
|
79
|
+
headers,
|
|
80
|
+
method: 'POST',
|
|
81
|
+
body: JSON.stringify({
|
|
82
|
+
chainId,
|
|
83
|
+
walletAddress,
|
|
84
|
+
}),
|
|
85
|
+
});
|
|
86
|
+
if (!response.ok) {
|
|
87
|
+
throw new Error('Failed to generate message for claim signature');
|
|
88
|
+
}
|
|
89
|
+
const message = await response.json();
|
|
90
|
+
return message;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Verify a claim signature.
|
|
94
|
+
*
|
|
95
|
+
* @param signature - The signature which is signed upon the message.
|
|
96
|
+
* @param walletAddress - The impacted wallet address of the claim.
|
|
97
|
+
* @param message - The message which was signed to generate the signature.
|
|
98
|
+
* @returns The result of the signature verification.
|
|
99
|
+
*/
|
|
100
|
+
async verifyClaimSignature(signature, walletAddress, message) {
|
|
101
|
+
const headers = await this.getRequestHeaders();
|
|
102
|
+
const url = `${this.getClaimsApiUrl()}/signature/verify`;
|
|
103
|
+
const response = await __classPrivateFieldGet(this, _ClaimsService_fetch, "f").call(this, url, {
|
|
104
|
+
headers,
|
|
105
|
+
method: 'POST',
|
|
106
|
+
body: JSON.stringify({
|
|
107
|
+
signature,
|
|
108
|
+
walletAddress,
|
|
109
|
+
message,
|
|
110
|
+
}),
|
|
111
|
+
});
|
|
112
|
+
if (!response.ok) {
|
|
113
|
+
throw new Error('Failed to verify claim signature');
|
|
114
|
+
}
|
|
115
|
+
const result = await response.json();
|
|
116
|
+
return Boolean(result.success);
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Create the headers for the current request.
|
|
120
|
+
*
|
|
121
|
+
* @param contentType - The content type of the request. Defaults to 'application/json'.
|
|
122
|
+
* @returns The headers for the current request.
|
|
123
|
+
*/
|
|
124
|
+
async getRequestHeaders(contentType = constants_1.HttpContentTypeHeader.APPLICATION_JSON) {
|
|
125
|
+
const bearerToken = await __classPrivateFieldGet(this, _ClaimsService_messenger, "f").call('AuthenticationController:getBearerToken');
|
|
126
|
+
return {
|
|
127
|
+
Authorization: `Bearer ${bearerToken}`,
|
|
128
|
+
'Content-Type': contentType,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Get the URL for the claims API for the current environment.
|
|
133
|
+
*
|
|
134
|
+
* @returns The URL for the claims API for the current environment.
|
|
135
|
+
*/
|
|
136
|
+
getClaimsApiUrl() {
|
|
137
|
+
return `${constants_1.CLAIMS_API_URL[__classPrivateFieldGet(this, _ClaimsService_env, "f")]}`;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
exports.ClaimsService = ClaimsService;
|
|
141
|
+
_ClaimsService_env = new WeakMap(), _ClaimsService_fetch = new WeakMap(), _ClaimsService_messenger = new WeakMap();
|
|
142
|
+
//# sourceMappingURL=ClaimsService.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ClaimsService.cjs","sourceRoot":"","sources":["../src/ClaimsService.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Messenger } from '@metamask/messenger';\nimport type { AuthenticationController } from '@metamask/profile-sync-controller';\nimport type { Hex } from '@metamask/utils';\n\nimport {\n CLAIMS_API_URL,\n type Env,\n HttpContentTypeHeader,\n SERVICE_NAME,\n} from './constants';\nimport type { Claim, GenerateSignatureMessageResponse } from './types';\n\nexport type ClaimsServiceGetClaimsAction = {\n type: `${typeof SERVICE_NAME}:getClaims`;\n handler: ClaimsService['getClaims'];\n};\n\nexport type ClaimsServiceGetClaimByIdAction = {\n type: `${typeof SERVICE_NAME}:getClaimById`;\n handler: ClaimsService['getClaimById'];\n};\n\nexport type ClaimsServiceGetRequestHeadersAction = {\n type: `${typeof SERVICE_NAME}:getRequestHeaders`;\n handler: ClaimsService['getRequestHeaders'];\n};\n\nexport type ClaimsServiceGetClaimsApiUrlAction = {\n type: `${typeof SERVICE_NAME}:getClaimsApiUrl`;\n handler: ClaimsService['getClaimsApiUrl'];\n};\n\nexport type ClaimsServiceGenerateMessageForClaimSignatureAction = {\n type: `${typeof SERVICE_NAME}:generateMessageForClaimSignature`;\n handler: ClaimsService['generateMessageForClaimSignature'];\n};\n\nexport type ClaimsServiceVerifyClaimSignatureAction = {\n type: `${typeof SERVICE_NAME}:verifyClaimSignature`;\n handler: ClaimsService['verifyClaimSignature'];\n};\n\nexport type ClaimsServiceActions =\n | ClaimsServiceGetClaimsAction\n | ClaimsServiceGetClaimByIdAction\n | ClaimsServiceGetRequestHeadersAction\n | ClaimsServiceGetClaimsApiUrlAction\n | ClaimsServiceGenerateMessageForClaimSignatureAction\n | ClaimsServiceVerifyClaimSignatureAction;\n\nexport type AllowedActions =\n AuthenticationController.AuthenticationControllerGetBearerToken;\n\nexport type ClaimsServiceEvents = never;\n\nexport type ClaimsServiceMessenger = Messenger<\n typeof SERVICE_NAME,\n ClaimsServiceActions | AllowedActions\n>;\n\nexport type ClaimsServiceConfig = {\n env: Env;\n messenger: ClaimsServiceMessenger;\n fetchFunction: typeof fetch;\n};\n\nexport class ClaimsService {\n name = SERVICE_NAME; // required for Modular Initialization\n\n readonly #env: Env;\n\n readonly #fetch: typeof fetch;\n\n readonly #messenger: ClaimsServiceMessenger;\n\n constructor({ env, messenger, fetchFunction }: ClaimsServiceConfig) {\n this.#env = env;\n this.#messenger = messenger;\n this.#fetch = fetchFunction;\n\n this.#messenger.registerActionHandler(\n `${SERVICE_NAME}:getClaims`,\n this.getClaims.bind(this),\n );\n this.#messenger.registerActionHandler(\n `${SERVICE_NAME}:getClaimById`,\n this.getClaimById.bind(this),\n );\n this.#messenger.registerActionHandler(\n `${SERVICE_NAME}:getRequestHeaders`,\n this.getRequestHeaders.bind(this),\n );\n this.#messenger.registerActionHandler(\n `${SERVICE_NAME}:getClaimsApiUrl`,\n this.getClaimsApiUrl.bind(this),\n );\n this.#messenger.registerActionHandler(\n `${SERVICE_NAME}:generateMessageForClaimSignature`,\n this.generateMessageForClaimSignature.bind(this),\n );\n this.#messenger.registerActionHandler(\n `${SERVICE_NAME}:verifyClaimSignature`,\n this.verifyClaimSignature.bind(this),\n );\n }\n\n /**\n * Get the claims for the current user.\n *\n * @returns The claims for the current user.\n */\n async getClaims(): Promise<Claim[]> {\n const headers = await this.getRequestHeaders();\n const url = `${this.getClaimsApiUrl()}/claims`;\n const response = await this.#fetch(url, {\n headers,\n });\n\n if (!response.ok) {\n throw new Error('Failed to get claims');\n }\n\n const claims = await response.json();\n return claims;\n }\n\n /**\n * Get the claim by id.\n *\n * @param id - The id of the claim to get.\n * @returns The claim by id.\n */\n async getClaimById(id: string): Promise<Claim> {\n const headers = await this.getRequestHeaders();\n const url = `${this.getClaimsApiUrl()}/claims/byId/${id}`;\n const response = await this.#fetch(url, {\n headers,\n });\n\n if (!response.ok) {\n throw new Error('Failed to get claim by id');\n }\n\n const claim = await response.json();\n return claim;\n }\n\n /**\n * Generate a message to be signed by the user for the claim request.\n *\n * @param chainId - The chain id of the claim.\n * @param walletAddress - The impacted wallet address of the claim.\n * @returns The message for the claim signature.\n */\n async generateMessageForClaimSignature(\n chainId: number,\n walletAddress: Hex,\n ): Promise<GenerateSignatureMessageResponse> {\n const headers = await this.getRequestHeaders();\n const url = `${this.getClaimsApiUrl()}/signature/generateMessage`;\n const response = await this.#fetch(url, {\n headers,\n method: 'POST',\n body: JSON.stringify({\n chainId,\n walletAddress,\n }),\n });\n\n if (!response.ok) {\n throw new Error('Failed to generate message for claim signature');\n }\n\n const message = await response.json();\n return message;\n }\n\n /**\n * Verify a claim signature.\n *\n * @param signature - The signature which is signed upon the message.\n * @param walletAddress - The impacted wallet address of the claim.\n * @param message - The message which was signed to generate the signature.\n * @returns The result of the signature verification.\n */\n async verifyClaimSignature(\n signature: `0x${string}`,\n walletAddress: `0x${string}`,\n message: string,\n ): Promise<boolean> {\n const headers = await this.getRequestHeaders();\n const url = `${this.getClaimsApiUrl()}/signature/verify`;\n const response = await this.#fetch(url, {\n headers,\n method: 'POST',\n body: JSON.stringify({\n signature,\n walletAddress,\n message,\n }),\n });\n\n if (!response.ok) {\n throw new Error('Failed to verify claim signature');\n }\n\n const result = await response.json();\n return Boolean(result.success);\n }\n\n /**\n * Create the headers for the current request.\n *\n * @param contentType - The content type of the request. Defaults to 'application/json'.\n * @returns The headers for the current request.\n */\n async getRequestHeaders(\n contentType: HttpContentTypeHeader = HttpContentTypeHeader.APPLICATION_JSON,\n ): Promise<Record<string, string>> {\n const bearerToken = await this.#messenger.call(\n 'AuthenticationController:getBearerToken',\n );\n return {\n Authorization: `Bearer ${bearerToken}`,\n 'Content-Type': contentType,\n };\n }\n\n /**\n * Get the URL for the claims API for the current environment.\n *\n * @returns The URL for the claims API for the current environment.\n */\n getClaimsApiUrl(): string {\n return `${CLAIMS_API_URL[this.#env]}`;\n }\n}\n"]}
|