@cartridge/controller 0.5.0 → 0.5.2
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/.turbo/turbo-build$colon$deps.log +116 -115
- package/.turbo/turbo-build.log +120 -0
- package/.turbo/turbo-format.log +25 -0
- package/dist/account.d.ts +2 -2
- package/dist/account.js +19 -4
- package/dist/account.js.map +1 -1
- package/dist/constants.d.ts +2 -1
- package/dist/constants.js +2 -0
- package/dist/constants.js.map +1 -1
- package/dist/controller.d.ts +2 -2
- package/dist/controller.js +28 -188
- package/dist/controller.js.map +1 -1
- package/dist/iframe/base.d.ts +2 -2
- package/dist/iframe/base.js +3 -177
- package/dist/iframe/base.js.map +1 -1
- package/dist/iframe/index.d.ts +2 -2
- package/dist/iframe/index.js +8 -180
- package/dist/iframe/index.js.map +1 -1
- package/dist/iframe/keychain.d.ts +2 -2
- package/dist/iframe/keychain.js +3 -177
- package/dist/iframe/keychain.js.map +1 -1
- package/dist/iframe/profile.d.ts +2 -2
- package/dist/iframe/profile.js +8 -180
- package/dist/iframe/profile.js.map +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.js +167 -189
- package/dist/index.js.map +1 -1
- package/dist/lookup.d.ts +4 -0
- package/dist/lookup.js +56 -0
- package/dist/lookup.js.map +1 -0
- package/dist/provider.d.ts +2 -2
- package/dist/session/account.d.ts +2 -3
- package/dist/session/account.js +13 -171
- package/dist/session/account.js.map +1 -1
- package/dist/session/index.d.ts +2 -3
- package/dist/session/index.js +40 -172
- package/dist/session/index.js.map +1 -1
- package/dist/session/provider.d.ts +4 -4
- package/dist/session/provider.js +39 -3
- package/dist/session/provider.js.map +1 -1
- package/dist/telegram/provider.d.ts +7 -4
- package/dist/telegram/provider.js +39 -3
- package/dist/telegram/provider.js.map +1 -1
- package/dist/{types-BkXOAuzX.d.ts → types-1WsOoNO2.d.ts} +17 -30
- package/dist/types.d.ts +2 -2
- package/dist/types.js.map +1 -1
- package/dist/utils.d.ts +6 -1
- package/dist/utils.js +101 -3
- package/dist/utils.js.map +1 -1
- package/package.json +5 -4
- package/src/account.ts +2 -1
- package/src/constants.ts +1 -0
- package/src/controller.ts +2 -3
- package/src/iframe/base.ts +3 -9
- package/src/iframe/profile.ts +5 -3
- package/src/index.ts +3 -1
- package/src/lookup.ts +68 -0
- package/src/session/account.ts +0 -1
- package/src/session/index.ts +0 -2
- package/src/session/provider.ts +5 -4
- package/src/telegram/provider.ts +8 -7
- package/src/types.ts +25 -34
- package/src/utils.ts +122 -2
- package/dist/presets.d.ts +0 -9
- package/dist/presets.js +0 -170
- package/dist/presets.js.map +0 -1
- package/src/presets.ts +0 -167
package/dist/utils.js
CHANGED
|
@@ -1,7 +1,34 @@
|
|
|
1
1
|
// src/utils.ts
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
addAddressPadding,
|
|
4
|
+
CallData,
|
|
5
|
+
getChecksumAddress,
|
|
6
|
+
hash,
|
|
7
|
+
typedData,
|
|
8
|
+
TypedDataRevision
|
|
9
|
+
} from "starknet";
|
|
10
|
+
var ALLOWED_PROPERTIES = /* @__PURE__ */ new Set([
|
|
11
|
+
"contracts",
|
|
12
|
+
"messages",
|
|
13
|
+
"target",
|
|
14
|
+
"method",
|
|
15
|
+
"name",
|
|
16
|
+
"description",
|
|
17
|
+
"types",
|
|
18
|
+
"domain",
|
|
19
|
+
"primaryType"
|
|
20
|
+
]);
|
|
21
|
+
function validatePropertyName(prop) {
|
|
22
|
+
if (!ALLOWED_PROPERTIES.has(prop)) {
|
|
23
|
+
throw new Error(`Invalid property name: ${prop}`);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
function safeObjectAccess(obj, prop) {
|
|
27
|
+
validatePropertyName(prop);
|
|
28
|
+
return obj[prop];
|
|
29
|
+
}
|
|
3
30
|
function normalizeCalls(calls) {
|
|
4
|
-
return (
|
|
31
|
+
return toArray(calls).map((call) => {
|
|
5
32
|
return {
|
|
6
33
|
entrypoint: call.entrypoint,
|
|
7
34
|
contractAddress: addAddressPadding(call.contractAddress),
|
|
@@ -9,7 +36,78 @@ function normalizeCalls(calls) {
|
|
|
9
36
|
};
|
|
10
37
|
});
|
|
11
38
|
}
|
|
39
|
+
function toSessionPolicies(policies) {
|
|
40
|
+
return Array.isArray(policies) ? policies.reduce(
|
|
41
|
+
(prev, p) => {
|
|
42
|
+
if (safeObjectAccess(p, "target")) {
|
|
43
|
+
const target = getChecksumAddress(
|
|
44
|
+
safeObjectAccess(p, "target")
|
|
45
|
+
);
|
|
46
|
+
const entrypoint = safeObjectAccess(p, "method");
|
|
47
|
+
const contracts = safeObjectAccess(
|
|
48
|
+
prev,
|
|
49
|
+
"contracts"
|
|
50
|
+
);
|
|
51
|
+
const item = {
|
|
52
|
+
name: humanizeString(entrypoint),
|
|
53
|
+
entrypoint,
|
|
54
|
+
description: safeObjectAccess(p, "description")
|
|
55
|
+
};
|
|
56
|
+
if (target in contracts) {
|
|
57
|
+
const methods = toArray(contracts[target].methods);
|
|
58
|
+
contracts[target] = {
|
|
59
|
+
methods: [...methods, item]
|
|
60
|
+
};
|
|
61
|
+
} else {
|
|
62
|
+
contracts[target] = {
|
|
63
|
+
methods: [item]
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
} else {
|
|
67
|
+
const messages = safeObjectAccess(prev, "messages");
|
|
68
|
+
messages.push(p);
|
|
69
|
+
}
|
|
70
|
+
return prev;
|
|
71
|
+
},
|
|
72
|
+
{ contracts: {}, messages: [] }
|
|
73
|
+
) : policies;
|
|
74
|
+
}
|
|
75
|
+
function toWasmPolicies(policies) {
|
|
76
|
+
return [
|
|
77
|
+
...Object.entries(policies.contracts ?? {}).flatMap(
|
|
78
|
+
([target, { methods }]) => toArray(methods).map((m) => ({
|
|
79
|
+
target,
|
|
80
|
+
method: m.entrypoint
|
|
81
|
+
}))
|
|
82
|
+
),
|
|
83
|
+
...(policies.messages ?? []).map((p) => {
|
|
84
|
+
const domainHash = typedData.getStructHash(
|
|
85
|
+
p.types,
|
|
86
|
+
"StarknetDomain",
|
|
87
|
+
p.domain,
|
|
88
|
+
TypedDataRevision.ACTIVE
|
|
89
|
+
);
|
|
90
|
+
const typeHash = typedData.getTypeHash(
|
|
91
|
+
p.types,
|
|
92
|
+
p.primaryType,
|
|
93
|
+
TypedDataRevision.ACTIVE
|
|
94
|
+
);
|
|
95
|
+
return {
|
|
96
|
+
scope_hash: hash.computePoseidonHash(domainHash, typeHash)
|
|
97
|
+
};
|
|
98
|
+
})
|
|
99
|
+
];
|
|
100
|
+
}
|
|
101
|
+
function toArray(val) {
|
|
102
|
+
return Array.isArray(val) ? val : [val];
|
|
103
|
+
}
|
|
104
|
+
function humanizeString(str) {
|
|
105
|
+
return str.replace(/([a-z])([A-Z])/g, "$1 $2").replace(/_/g, " ").toLowerCase().replace(/^\w/, (c) => c.toUpperCase());
|
|
106
|
+
}
|
|
12
107
|
export {
|
|
13
|
-
normalizeCalls
|
|
108
|
+
normalizeCalls,
|
|
109
|
+
toArray,
|
|
110
|
+
toSessionPolicies,
|
|
111
|
+
toWasmPolicies
|
|
14
112
|
};
|
|
15
113
|
//# sourceMappingURL=utils.js.map
|
package/dist/utils.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/utils.ts"],"sourcesContent":["import {
|
|
1
|
+
{"version":3,"sources":["../src/utils.ts"],"sourcesContent":["import {\n addAddressPadding,\n Call,\n CallData,\n getChecksumAddress,\n hash,\n typedData,\n TypedDataRevision,\n} from \"starknet\";\nimport wasm from \"@cartridge/account-wasm/controller\";\nimport { Policies, SessionPolicies } from \"@cartridge/presets\";\n\n// Whitelist of allowed property names to prevent prototype pollution\nconst ALLOWED_PROPERTIES = new Set([\n \"contracts\",\n \"messages\",\n \"target\",\n \"method\",\n \"name\",\n \"description\",\n \"types\",\n \"domain\",\n \"primaryType\",\n]);\n\nfunction validatePropertyName(prop: string): void {\n if (!ALLOWED_PROPERTIES.has(prop)) {\n throw new Error(`Invalid property name: ${prop}`);\n }\n}\n\nfunction safeObjectAccess<T>(obj: any, prop: string): T {\n validatePropertyName(prop);\n return obj[prop];\n}\n\nexport function normalizeCalls(calls: Call | Call[]) {\n return toArray(calls).map((call) => {\n return {\n entrypoint: call.entrypoint,\n contractAddress: addAddressPadding(call.contractAddress),\n calldata: CallData.toHex(call.calldata),\n };\n });\n}\n\nexport function toSessionPolicies(policies: Policies): SessionPolicies {\n return Array.isArray(policies)\n ? policies.reduce<SessionPolicies>(\n (prev, p) => {\n if (safeObjectAccess<string>(p, \"target\")) {\n const target = getChecksumAddress(\n safeObjectAccess<string>(p, \"target\"),\n );\n const entrypoint = safeObjectAccess<string>(p, \"method\");\n const contracts = safeObjectAccess<Record<string, any>>(\n prev,\n \"contracts\",\n );\n const item = {\n name: humanizeString(entrypoint),\n entrypoint: entrypoint,\n description: safeObjectAccess<string>(p, \"description\"),\n };\n\n if (target in contracts) {\n const methods = toArray(contracts[target].methods);\n contracts[target] = {\n methods: [...methods, item],\n };\n } else {\n contracts[target] = {\n methods: [item],\n };\n }\n } else {\n const messages = safeObjectAccess<any[]>(prev, \"messages\");\n messages.push(p);\n }\n\n return prev;\n },\n { contracts: {}, messages: [] },\n )\n : policies;\n}\n\nexport function toWasmPolicies(policies: SessionPolicies): wasm.Policy[] {\n return [\n ...Object.entries(policies.contracts ?? {}).flatMap(\n ([target, { methods }]) =>\n toArray(methods).map((m) => ({\n target,\n method: m.entrypoint,\n })),\n ),\n ...(policies.messages ?? []).map((p) => {\n const domainHash = typedData.getStructHash(\n p.types,\n \"StarknetDomain\",\n p.domain,\n TypedDataRevision.ACTIVE,\n );\n const typeHash = typedData.getTypeHash(\n p.types,\n p.primaryType,\n TypedDataRevision.ACTIVE,\n );\n\n return {\n scope_hash: hash.computePoseidonHash(domainHash, typeHash),\n };\n }),\n ];\n}\n\nexport function toArray<T>(val: T | T[]): T[] {\n return Array.isArray(val) ? val : [val];\n}\n\nfunction humanizeString(str: string): string {\n return (\n str\n // Convert from camelCase or snake_case\n .replace(/([a-z])([A-Z])/g, \"$1 $2\") // camelCase to spaces\n .replace(/_/g, \" \") // snake_case to spaces\n .toLowerCase()\n // Capitalize first letter\n .replace(/^\\w/, (c) => c.toUpperCase())\n );\n}\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cartridge/controller",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.2",
|
|
4
4
|
"description": "Cartridge Controller",
|
|
5
5
|
"module": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -31,16 +31,17 @@
|
|
|
31
31
|
"fast-deep-equal": "^3.1.3",
|
|
32
32
|
"query-string": "^7.1.1",
|
|
33
33
|
"starknet": "^6.11.0",
|
|
34
|
-
"@cartridge/account-wasm": "
|
|
35
|
-
"@cartridge/
|
|
34
|
+
"@cartridge/account-wasm": "0.5.2",
|
|
35
|
+
"@cartridge/presets": "0.5.2"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
38
|
"@types/node": "^20.6.0",
|
|
39
39
|
"typescript": "^5.4.5",
|
|
40
|
-
"@cartridge/tsconfig": "
|
|
40
|
+
"@cartridge/tsconfig": "0.5.2"
|
|
41
41
|
},
|
|
42
42
|
"scripts": {
|
|
43
43
|
"build:deps": "tsup --dts-resolve",
|
|
44
|
+
"build": "pnpm build:deps",
|
|
44
45
|
"format": "prettier --write \"src/**/*.ts\"",
|
|
45
46
|
"format:check": "prettier --check \"src/**/*.ts\"",
|
|
46
47
|
"version": "pnpm pkg get version"
|
package/src/account.ts
CHANGED
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
} from "./types";
|
|
18
18
|
import { AsyncMethodReturns } from "@cartridge/penpal";
|
|
19
19
|
import BaseProvider from "./provider";
|
|
20
|
+
import { toArray } from "./utils";
|
|
20
21
|
|
|
21
22
|
class ControllerAccount extends WalletAccount {
|
|
22
23
|
address: string;
|
|
@@ -52,7 +53,7 @@ class ControllerAccount extends WalletAccount {
|
|
|
52
53
|
* @returns response from addTransaction
|
|
53
54
|
*/
|
|
54
55
|
async execute(calls: AllowArray<Call>): Promise<InvokeFunctionResponse> {
|
|
55
|
-
calls =
|
|
56
|
+
calls = toArray(calls);
|
|
56
57
|
|
|
57
58
|
return new Promise(async (resolve, reject) => {
|
|
58
59
|
const sessionExecute = await this.keychain.execute(
|
package/src/constants.ts
CHANGED
package/src/controller.ts
CHANGED
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
import { AsyncMethodReturns } from "@cartridge/penpal";
|
|
2
|
-
import { normalize } from "@cartridge/utils";
|
|
3
2
|
|
|
4
3
|
import ControllerAccount from "./account";
|
|
5
4
|
import { KeychainIFrame, ProfileIFrame } from "./iframe";
|
|
6
5
|
import { NotReadyToConnect } from "./errors";
|
|
7
6
|
import {
|
|
8
7
|
Keychain,
|
|
9
|
-
Policy,
|
|
10
8
|
ResponseCodes,
|
|
11
9
|
ConnectReply,
|
|
12
10
|
ProbeReply,
|
|
@@ -18,6 +16,7 @@ import {
|
|
|
18
16
|
} from "./types";
|
|
19
17
|
import BaseProvider from "./provider";
|
|
20
18
|
import { WalletAccount } from "starknet";
|
|
19
|
+
import { Policy } from "@cartridge/presets";
|
|
21
20
|
|
|
22
21
|
export default class ControllerProvider extends BaseProvider {
|
|
23
22
|
private keychain?: AsyncMethodReturns<Keychain>;
|
|
@@ -82,7 +81,7 @@ export default class ControllerProvider extends BaseProvider {
|
|
|
82
81
|
methods: {
|
|
83
82
|
openSettings: this.openSettings.bind(this),
|
|
84
83
|
openPurchaseCredits: this.openPurchaseCredits.bind(this),
|
|
85
|
-
openExecute:
|
|
84
|
+
openExecute: this.openExecute.bind(this),
|
|
86
85
|
},
|
|
87
86
|
rpcUrl: this.rpc.toString(),
|
|
88
87
|
username,
|
package/src/iframe/base.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { AsyncMethodReturns, connectToChild } from "@cartridge/penpal";
|
|
2
|
-
import { defaultPresets } from "../presets";
|
|
3
2
|
import { ControllerOptions, Modal } from "../types";
|
|
4
3
|
|
|
5
4
|
export type IFrameOptions<CallSender> = Omit<
|
|
@@ -35,14 +34,9 @@ export class IFrame<CallSender extends {}> implements Modal {
|
|
|
35
34
|
return;
|
|
36
35
|
}
|
|
37
36
|
|
|
38
|
-
|
|
39
|
-
"theme",
|
|
40
|
-
|
|
41
|
-
JSON.stringify(
|
|
42
|
-
defaultPresets[theme ?? "cartridge"] ?? defaultPresets.cartridge,
|
|
43
|
-
),
|
|
44
|
-
),
|
|
45
|
-
);
|
|
37
|
+
if (theme) {
|
|
38
|
+
url.searchParams.set("theme", encodeURIComponent(theme));
|
|
39
|
+
}
|
|
46
40
|
|
|
47
41
|
if (colorMode) {
|
|
48
42
|
url.searchParams.set("colorMode", colorMode);
|
package/src/iframe/profile.ts
CHANGED
|
@@ -24,10 +24,12 @@ export class ProfileIFrame extends IFrame<Profile> {
|
|
|
24
24
|
const _url = new URL(
|
|
25
25
|
slot
|
|
26
26
|
? namespace
|
|
27
|
-
? `${_profileUrl}/account/${username}/slot/${slot}?
|
|
28
|
-
|
|
27
|
+
? `${_profileUrl}/account/${username}/slot/${slot}?ps=${encodeURIComponent(
|
|
28
|
+
slot,
|
|
29
|
+
)}&ns=${encodeURIComponent(namespace)}`
|
|
30
|
+
: `${_profileUrl}/account/${username}/slot/${slot}?ps=${encodeURIComponent(
|
|
31
|
+
slot,
|
|
29
32
|
)}`
|
|
30
|
-
: `${_profileUrl}/account/${username}/slot/${slot}`
|
|
31
33
|
: `${_profileUrl}/account/${username}`,
|
|
32
34
|
);
|
|
33
35
|
|
package/src/index.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
export { default } from "./controller";
|
|
2
2
|
export * from "./errors";
|
|
3
3
|
export * from "./types";
|
|
4
|
+
export * from "./lookup";
|
|
4
5
|
|
|
5
|
-
export {
|
|
6
|
+
export { toWasmPolicies, toSessionPolicies, toArray } from "./utils";
|
|
7
|
+
export * from "@cartridge/presets";
|
package/src/lookup.ts
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { LookupRequest, LookupResponse } from "./types";
|
|
2
|
+
import { num } from "starknet";
|
|
3
|
+
import { API_URL } from "./constants";
|
|
4
|
+
|
|
5
|
+
const cache = new Map<string, string>();
|
|
6
|
+
|
|
7
|
+
async function lookup(request: LookupRequest): Promise<LookupResponse> {
|
|
8
|
+
if (!request.addresses?.length && !request.usernames?.length) {
|
|
9
|
+
return { results: [] };
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const response = await fetch(`${API_URL}/lookup`, {
|
|
13
|
+
method: "POST",
|
|
14
|
+
headers: {
|
|
15
|
+
"Content-Type": "application/json",
|
|
16
|
+
},
|
|
17
|
+
body: JSON.stringify(request),
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
if (!response.ok) {
|
|
21
|
+
throw new Error(`HTTP error! status: ${response.status}`);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return response.json();
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export async function lookupUsernames(
|
|
28
|
+
usernames: string[],
|
|
29
|
+
): Promise<Map<string, string>> {
|
|
30
|
+
const uncachedUsernames = usernames.filter((name) => !cache.has(name));
|
|
31
|
+
|
|
32
|
+
if (uncachedUsernames.length > 0) {
|
|
33
|
+
const response = await lookup({ usernames: uncachedUsernames });
|
|
34
|
+
|
|
35
|
+
response.results.forEach((result) => {
|
|
36
|
+
cache.set(result.username, result.addresses[0]); // TODO: handle multiple controller addresses
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return new Map(
|
|
41
|
+
usernames
|
|
42
|
+
.map((name) => [name, cache.get(name)] as [string, string])
|
|
43
|
+
.filter((entry): entry is [string, string] => entry[1] !== undefined),
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export async function lookupAddresses(
|
|
48
|
+
addresses: string[],
|
|
49
|
+
): Promise<Map<string, string>> {
|
|
50
|
+
addresses = addresses.map(num.toHex);
|
|
51
|
+
const uncachedAddresses = addresses.filter((addr) => !cache.has(addr));
|
|
52
|
+
|
|
53
|
+
if (uncachedAddresses.length > 0) {
|
|
54
|
+
const response = await lookup({
|
|
55
|
+
addresses: uncachedAddresses,
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
response.results.forEach((result) => {
|
|
59
|
+
cache.set(result.addresses[0], result.username); // TODO: handle multiple controller addresses
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return new Map(
|
|
64
|
+
addresses
|
|
65
|
+
.map((addr) => [addr, cache.get(addr)] as [string, string])
|
|
66
|
+
.filter((entry): entry is [string, string] => entry[1] !== undefined),
|
|
67
|
+
);
|
|
68
|
+
}
|
package/src/session/account.ts
CHANGED
package/src/session/index.ts
CHANGED
package/src/session/provider.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { Policy } from "../types";
|
|
2
1
|
import { ec, stark, WalletAccount } from "starknet";
|
|
3
2
|
|
|
4
3
|
import SessionAccount from "./account";
|
|
5
4
|
import { KEYCHAIN_URL } from "../constants";
|
|
6
5
|
import BaseProvider from "../provider";
|
|
6
|
+
import { toWasmPolicies } from "../utils";
|
|
7
|
+
import { SessionPolicies } from "@cartridge/presets";
|
|
7
8
|
|
|
8
9
|
interface SessionRegistration {
|
|
9
10
|
username: string;
|
|
@@ -16,7 +17,7 @@ interface SessionRegistration {
|
|
|
16
17
|
export type SessionOptions = {
|
|
17
18
|
rpc: string;
|
|
18
19
|
chainId: string;
|
|
19
|
-
policies:
|
|
20
|
+
policies: SessionPolicies;
|
|
20
21
|
redirectUrl: string;
|
|
21
22
|
};
|
|
22
23
|
|
|
@@ -28,7 +29,7 @@ export default class SessionProvider extends BaseProvider {
|
|
|
28
29
|
|
|
29
30
|
protected _username?: string;
|
|
30
31
|
protected _redirectUrl: string;
|
|
31
|
-
protected _policies:
|
|
32
|
+
protected _policies: SessionPolicies;
|
|
32
33
|
|
|
33
34
|
constructor({ rpc, chainId, policies, redirectUrl }: SessionOptions) {
|
|
34
35
|
super({ rpc });
|
|
@@ -132,7 +133,7 @@ export default class SessionProvider extends BaseProvider {
|
|
|
132
133
|
ownerGuid: sessionRegistration.ownerGuid,
|
|
133
134
|
chainId: this._chainId,
|
|
134
135
|
expiresAt: parseInt(sessionRegistration.expiresAt),
|
|
135
|
-
policies: this._policies,
|
|
136
|
+
policies: toWasmPolicies(this._policies),
|
|
136
137
|
});
|
|
137
138
|
|
|
138
139
|
return this.account;
|
package/src/telegram/provider.ts
CHANGED
|
@@ -6,10 +6,11 @@ import {
|
|
|
6
6
|
} from "@telegram-apps/sdk";
|
|
7
7
|
import { ec, stark, WalletAccount } from "starknet";
|
|
8
8
|
|
|
9
|
-
import { KEYCHAIN_URL } from "
|
|
10
|
-
import
|
|
11
|
-
import
|
|
12
|
-
import
|
|
9
|
+
import { KEYCHAIN_URL } from "../constants";
|
|
10
|
+
import SessionAccount from "../session/account";
|
|
11
|
+
import BaseProvider from "../provider";
|
|
12
|
+
import { toWasmPolicies } from "../utils";
|
|
13
|
+
import { SessionPolicies } from "@cartridge/presets";
|
|
13
14
|
|
|
14
15
|
interface SessionRegistration {
|
|
15
16
|
username: string;
|
|
@@ -23,7 +24,7 @@ export default class TelegramProvider extends BaseProvider {
|
|
|
23
24
|
private _tmaUrl: string;
|
|
24
25
|
protected _chainId: string;
|
|
25
26
|
protected _username?: string;
|
|
26
|
-
protected _policies:
|
|
27
|
+
protected _policies: SessionPolicies;
|
|
27
28
|
|
|
28
29
|
constructor({
|
|
29
30
|
rpc,
|
|
@@ -33,7 +34,7 @@ export default class TelegramProvider extends BaseProvider {
|
|
|
33
34
|
}: {
|
|
34
35
|
rpc: string;
|
|
35
36
|
chainId: string;
|
|
36
|
-
policies:
|
|
37
|
+
policies: SessionPolicies;
|
|
37
38
|
tmaUrl: string;
|
|
38
39
|
}) {
|
|
39
40
|
super({
|
|
@@ -123,7 +124,7 @@ export default class TelegramProvider extends BaseProvider {
|
|
|
123
124
|
ownerGuid: sessionRegistration.ownerGuid,
|
|
124
125
|
chainId: this._chainId,
|
|
125
126
|
expiresAt: parseInt(sessionRegistration.expiresAt),
|
|
126
|
-
policies: this._policies,
|
|
127
|
+
policies: toWasmPolicies(this._policies),
|
|
127
128
|
});
|
|
128
129
|
|
|
129
130
|
return this.account;
|
package/src/types.ts
CHANGED
|
@@ -11,7 +11,12 @@ import {
|
|
|
11
11
|
TypedData,
|
|
12
12
|
} from "@starknet-io/types-js";
|
|
13
13
|
import { KeychainIFrame, ProfileIFrame } from "./iframe";
|
|
14
|
-
import
|
|
14
|
+
import {
|
|
15
|
+
ColorMode,
|
|
16
|
+
Policies,
|
|
17
|
+
Policy,
|
|
18
|
+
SessionPolicies,
|
|
19
|
+
} from "@cartridge/presets";
|
|
15
20
|
|
|
16
21
|
export type Session = {
|
|
17
22
|
chainId: constants.StarknetChainId;
|
|
@@ -24,10 +29,6 @@ export type Session = {
|
|
|
24
29
|
};
|
|
25
30
|
};
|
|
26
31
|
|
|
27
|
-
export type Policy = wasm.Policy & {
|
|
28
|
-
description?: string;
|
|
29
|
-
};
|
|
30
|
-
|
|
31
32
|
export enum ResponseCodes {
|
|
32
33
|
SUCCESS = "SUCCESS",
|
|
33
34
|
NOT_CONNECTED = "NOT_CONNECTED",
|
|
@@ -51,7 +52,7 @@ export type ControllerError = {
|
|
|
51
52
|
export type ConnectReply = {
|
|
52
53
|
code: ResponseCodes.SUCCESS;
|
|
53
54
|
address: string;
|
|
54
|
-
policies:
|
|
55
|
+
policies: SessionPolicies;
|
|
55
56
|
};
|
|
56
57
|
|
|
57
58
|
export type ExecuteReply =
|
|
@@ -77,6 +78,20 @@ export type IFrames = {
|
|
|
77
78
|
profile?: ProfileIFrame;
|
|
78
79
|
};
|
|
79
80
|
|
|
81
|
+
export interface LookupRequest {
|
|
82
|
+
usernames?: string[];
|
|
83
|
+
addresses?: string[];
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export interface LookupResult {
|
|
87
|
+
username: string;
|
|
88
|
+
addresses: string[];
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export interface LookupResponse {
|
|
92
|
+
results: LookupResult[];
|
|
93
|
+
}
|
|
94
|
+
|
|
80
95
|
type ContractAddress = string;
|
|
81
96
|
type CartridgeID = string;
|
|
82
97
|
export type ControllerAccounts = Record<ContractAddress, CartridgeID>;
|
|
@@ -84,7 +99,7 @@ export type ControllerAccounts = Record<ContractAddress, CartridgeID>;
|
|
|
84
99
|
export interface Keychain {
|
|
85
100
|
probe(rpcUrl: string): Promise<ProbeReply | ConnectError>;
|
|
86
101
|
connect(
|
|
87
|
-
policies:
|
|
102
|
+
policies: Policies,
|
|
88
103
|
rpcUrl: string,
|
|
89
104
|
): Promise<ConnectReply | ConnectError>;
|
|
90
105
|
disconnect(): void;
|
|
@@ -149,7 +164,7 @@ export type ProviderOptions = {
|
|
|
149
164
|
};
|
|
150
165
|
|
|
151
166
|
export type KeychainOptions = IFrameOptions & {
|
|
152
|
-
policies?:
|
|
167
|
+
policies?: Policies;
|
|
153
168
|
/** The URL of keychain */
|
|
154
169
|
url?: string;
|
|
155
170
|
/** The origin of keychain */
|
|
@@ -172,32 +187,8 @@ export type ProfileOptions = IFrameOptions & {
|
|
|
172
187
|
export type ProfileContextTypeVariant =
|
|
173
188
|
| "inventory"
|
|
174
189
|
| "trophies"
|
|
175
|
-
| "achievements"
|
|
176
|
-
|
|
177
|
-
export type ColorMode = "light" | "dark";
|
|
178
|
-
|
|
179
|
-
export type ControllerTheme = {
|
|
180
|
-
id: string;
|
|
181
|
-
name: string;
|
|
182
|
-
icon: string;
|
|
183
|
-
cover: ThemeValue<string>;
|
|
184
|
-
colorMode: ColorMode;
|
|
185
|
-
};
|
|
186
|
-
|
|
187
|
-
export type ControllerThemePresets = Record<string, ControllerThemePreset>;
|
|
188
|
-
|
|
189
|
-
export type ControllerThemePreset = Omit<ControllerTheme, "colorMode"> & {
|
|
190
|
-
colors?: ControllerColors;
|
|
191
|
-
};
|
|
192
|
-
|
|
193
|
-
export type ControllerColors = {
|
|
194
|
-
primary?: ControllerColor;
|
|
195
|
-
primaryForeground?: ControllerColor;
|
|
196
|
-
};
|
|
197
|
-
|
|
198
|
-
export type ControllerColor = ThemeValue<string>;
|
|
199
|
-
|
|
200
|
-
export type ThemeValue<T> = T | { dark: T; light: T };
|
|
190
|
+
| "achievements"
|
|
191
|
+
| "activity";
|
|
201
192
|
|
|
202
193
|
export type Prefund = { address: string; min: string };
|
|
203
194
|
|
package/src/utils.ts
CHANGED
|
@@ -1,7 +1,41 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
addAddressPadding,
|
|
3
|
+
Call,
|
|
4
|
+
CallData,
|
|
5
|
+
getChecksumAddress,
|
|
6
|
+
hash,
|
|
7
|
+
typedData,
|
|
8
|
+
TypedDataRevision,
|
|
9
|
+
} from "starknet";
|
|
10
|
+
import wasm from "@cartridge/account-wasm/controller";
|
|
11
|
+
import { Policies, SessionPolicies } from "@cartridge/presets";
|
|
12
|
+
|
|
13
|
+
// Whitelist of allowed property names to prevent prototype pollution
|
|
14
|
+
const ALLOWED_PROPERTIES = new Set([
|
|
15
|
+
"contracts",
|
|
16
|
+
"messages",
|
|
17
|
+
"target",
|
|
18
|
+
"method",
|
|
19
|
+
"name",
|
|
20
|
+
"description",
|
|
21
|
+
"types",
|
|
22
|
+
"domain",
|
|
23
|
+
"primaryType",
|
|
24
|
+
]);
|
|
25
|
+
|
|
26
|
+
function validatePropertyName(prop: string): void {
|
|
27
|
+
if (!ALLOWED_PROPERTIES.has(prop)) {
|
|
28
|
+
throw new Error(`Invalid property name: ${prop}`);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function safeObjectAccess<T>(obj: any, prop: string): T {
|
|
33
|
+
validatePropertyName(prop);
|
|
34
|
+
return obj[prop];
|
|
35
|
+
}
|
|
2
36
|
|
|
3
37
|
export function normalizeCalls(calls: Call | Call[]) {
|
|
4
|
-
return (
|
|
38
|
+
return toArray(calls).map((call) => {
|
|
5
39
|
return {
|
|
6
40
|
entrypoint: call.entrypoint,
|
|
7
41
|
contractAddress: addAddressPadding(call.contractAddress),
|
|
@@ -9,3 +43,89 @@ export function normalizeCalls(calls: Call | Call[]) {
|
|
|
9
43
|
};
|
|
10
44
|
});
|
|
11
45
|
}
|
|
46
|
+
|
|
47
|
+
export function toSessionPolicies(policies: Policies): SessionPolicies {
|
|
48
|
+
return Array.isArray(policies)
|
|
49
|
+
? policies.reduce<SessionPolicies>(
|
|
50
|
+
(prev, p) => {
|
|
51
|
+
if (safeObjectAccess<string>(p, "target")) {
|
|
52
|
+
const target = getChecksumAddress(
|
|
53
|
+
safeObjectAccess<string>(p, "target"),
|
|
54
|
+
);
|
|
55
|
+
const entrypoint = safeObjectAccess<string>(p, "method");
|
|
56
|
+
const contracts = safeObjectAccess<Record<string, any>>(
|
|
57
|
+
prev,
|
|
58
|
+
"contracts",
|
|
59
|
+
);
|
|
60
|
+
const item = {
|
|
61
|
+
name: humanizeString(entrypoint),
|
|
62
|
+
entrypoint: entrypoint,
|
|
63
|
+
description: safeObjectAccess<string>(p, "description"),
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
if (target in contracts) {
|
|
67
|
+
const methods = toArray(contracts[target].methods);
|
|
68
|
+
contracts[target] = {
|
|
69
|
+
methods: [...methods, item],
|
|
70
|
+
};
|
|
71
|
+
} else {
|
|
72
|
+
contracts[target] = {
|
|
73
|
+
methods: [item],
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
} else {
|
|
77
|
+
const messages = safeObjectAccess<any[]>(prev, "messages");
|
|
78
|
+
messages.push(p);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return prev;
|
|
82
|
+
},
|
|
83
|
+
{ contracts: {}, messages: [] },
|
|
84
|
+
)
|
|
85
|
+
: policies;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export function toWasmPolicies(policies: SessionPolicies): wasm.Policy[] {
|
|
89
|
+
return [
|
|
90
|
+
...Object.entries(policies.contracts ?? {}).flatMap(
|
|
91
|
+
([target, { methods }]) =>
|
|
92
|
+
toArray(methods).map((m) => ({
|
|
93
|
+
target,
|
|
94
|
+
method: m.entrypoint,
|
|
95
|
+
})),
|
|
96
|
+
),
|
|
97
|
+
...(policies.messages ?? []).map((p) => {
|
|
98
|
+
const domainHash = typedData.getStructHash(
|
|
99
|
+
p.types,
|
|
100
|
+
"StarknetDomain",
|
|
101
|
+
p.domain,
|
|
102
|
+
TypedDataRevision.ACTIVE,
|
|
103
|
+
);
|
|
104
|
+
const typeHash = typedData.getTypeHash(
|
|
105
|
+
p.types,
|
|
106
|
+
p.primaryType,
|
|
107
|
+
TypedDataRevision.ACTIVE,
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
return {
|
|
111
|
+
scope_hash: hash.computePoseidonHash(domainHash, typeHash),
|
|
112
|
+
};
|
|
113
|
+
}),
|
|
114
|
+
];
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export function toArray<T>(val: T | T[]): T[] {
|
|
118
|
+
return Array.isArray(val) ? val : [val];
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function humanizeString(str: string): string {
|
|
122
|
+
return (
|
|
123
|
+
str
|
|
124
|
+
// Convert from camelCase or snake_case
|
|
125
|
+
.replace(/([a-z])([A-Z])/g, "$1 $2") // camelCase to spaces
|
|
126
|
+
.replace(/_/g, " ") // snake_case to spaces
|
|
127
|
+
.toLowerCase()
|
|
128
|
+
// Capitalize first letter
|
|
129
|
+
.replace(/^\w/, (c) => c.toUpperCase())
|
|
130
|
+
);
|
|
131
|
+
}
|
package/dist/presets.d.ts
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { n as ControllerThemePresets } from './types-BkXOAuzX.js';
|
|
2
|
-
import 'starknet';
|
|
3
|
-
import '@starknet-io/types-js';
|
|
4
|
-
import '@cartridge/penpal';
|
|
5
|
-
import '@cartridge/account-wasm/controller';
|
|
6
|
-
|
|
7
|
-
declare const defaultPresets: ControllerThemePresets;
|
|
8
|
-
|
|
9
|
-
export { defaultPresets };
|