@cartridge/controller 0.5.7 → 0.5.9
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 +72 -67
- package/.turbo/turbo-build.log +73 -68
- package/dist/__tests__/parseChainId.test.d.ts +2 -0
- package/dist/__tests__/parseChainId.test.js +89 -0
- package/dist/__tests__/parseChainId.test.js.map +1 -0
- package/dist/account.d.ts +2 -2
- package/dist/account.js +4 -2
- package/dist/account.js.map +1 -1
- package/dist/controller.d.ts +8 -3
- package/dist/controller.js +111 -36
- package/dist/controller.js.map +1 -1
- package/dist/iframe/base.d.ts +1 -1
- package/dist/iframe/index.d.ts +1 -1
- package/dist/iframe/keychain.d.ts +1 -1
- package/dist/iframe/profile.d.ts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +128 -37
- package/dist/index.js.map +1 -1
- package/dist/provider.d.ts +5 -6
- package/dist/provider.js +28 -19
- package/dist/provider.js.map +1 -1
- package/dist/session/account.d.ts +1 -1
- package/dist/session/account.js +2 -0
- package/dist/session/account.js.map +1 -1
- package/dist/session/index.d.ts +1 -1
- package/dist/session/index.js +40 -22
- package/dist/session/index.js.map +1 -1
- package/dist/session/provider.d.ts +4 -3
- package/dist/session/provider.js +40 -22
- package/dist/session/provider.js.map +1 -1
- package/dist/telegram/provider.d.ts +4 -3
- package/dist/telegram/provider.js +40 -24
- package/dist/telegram/provider.js.map +1 -1
- package/dist/{types-BReKRAuh.d.ts → types-CVnDQVqD.d.ts} +10 -11
- package/dist/types.d.ts +1 -1
- package/dist/types.js.map +1 -1
- package/dist/utils.d.ts +3 -2
- package/dist/utils.js +25 -0
- package/dist/utils.js.map +1 -1
- package/jest.config.ts +13 -0
- package/package.json +7 -3
- package/src/__tests__/parseChainId.test.ts +60 -0
- package/src/account.ts +2 -1
- package/src/controller.ts +85 -15
- package/src/provider.ts +37 -23
- package/src/session/provider.ts +14 -4
- package/src/telegram/provider.ts +14 -5
- package/src/types.ts +11 -12
- package/src/utils.ts +28 -0
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { constants, shortString } from "starknet";
|
|
2
|
+
import { parseChainId } from "../utils";
|
|
3
|
+
|
|
4
|
+
describe("parseChainId", () => {
|
|
5
|
+
describe("Starknet chains", () => {
|
|
6
|
+
test("identifies mainnet", () => {
|
|
7
|
+
expect(
|
|
8
|
+
parseChainId(new URL("https://api.cartridge.gg/x/starknet/mainnet")),
|
|
9
|
+
).toBe(constants.StarknetChainId.SN_MAIN);
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
test("identifies sepolia", () => {
|
|
13
|
+
expect(
|
|
14
|
+
parseChainId(new URL("https://api.cartridge.gg/x/starknet/sepolia")),
|
|
15
|
+
).toBe(constants.StarknetChainId.SN_SEPOLIA);
|
|
16
|
+
});
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
describe("Project-specific chains", () => {
|
|
20
|
+
test("identifies slot chain", () => {
|
|
21
|
+
expect(
|
|
22
|
+
parseChainId(new URL("https://api.cartridge.gg/x/slot/katana")),
|
|
23
|
+
).toBe(shortString.encodeShortString("WP_SLOT"));
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
test("identifies slot chain on localhost", () => {
|
|
27
|
+
expect(parseChainId(new URL("http://localhost:8001/x/slot/katana"))).toBe(
|
|
28
|
+
shortString.encodeShortString("WP_SLOT"),
|
|
29
|
+
);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
test("identifies slot chain with hyphenated name", () => {
|
|
33
|
+
expect(
|
|
34
|
+
parseChainId(
|
|
35
|
+
new URL("https://api.cartridge.gg/x/my-slot-chain/katana"),
|
|
36
|
+
),
|
|
37
|
+
).toBe(shortString.encodeShortString("WP_MY_SLOT_CHAIN"));
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
test("identifies slot mainnet chain", () => {
|
|
41
|
+
expect(
|
|
42
|
+
parseChainId(new URL("https://api.cartridge.gg/x/slot/mainnet")),
|
|
43
|
+
).toBe(shortString.encodeShortString("GG_SLOT"));
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
describe("Error cases", () => {
|
|
48
|
+
test("throws error for unsupported URL format", () => {
|
|
49
|
+
expect(() =>
|
|
50
|
+
parseChainId(new URL("https://api.example.com/unsupported")),
|
|
51
|
+
).toThrow("Chain https://api.example.com/unsupported not supported");
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
test("throws error for URLs without proper chain identifiers", () => {
|
|
55
|
+
expect(() =>
|
|
56
|
+
parseChainId(new URL("https://api.example.com/v1/starknet")),
|
|
57
|
+
).toThrow("Chain https://api.example.com/v1/starknet not supported");
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
});
|
package/src/account.ts
CHANGED
|
@@ -27,12 +27,13 @@ class ControllerAccount extends WalletAccount {
|
|
|
27
27
|
|
|
28
28
|
constructor(
|
|
29
29
|
provider: BaseProvider,
|
|
30
|
+
rpcUrl: string,
|
|
30
31
|
address: string,
|
|
31
32
|
keychain: AsyncMethodReturns<Keychain>,
|
|
32
33
|
options: KeychainOptions,
|
|
33
34
|
modal: Modal,
|
|
34
35
|
) {
|
|
35
|
-
super({ nodeUrl:
|
|
36
|
+
super({ nodeUrl: rpcUrl }, provider);
|
|
36
37
|
|
|
37
38
|
this.address = address;
|
|
38
39
|
this.keychain = keychain;
|
package/src/controller.ts
CHANGED
|
@@ -13,20 +13,52 @@ import {
|
|
|
13
13
|
Profile,
|
|
14
14
|
IFrames,
|
|
15
15
|
ProfileContextTypeVariant,
|
|
16
|
+
Chain,
|
|
16
17
|
} from "./types";
|
|
17
18
|
import BaseProvider from "./provider";
|
|
18
19
|
import { WalletAccount } from "starknet";
|
|
19
20
|
import { Policy } from "@cartridge/presets";
|
|
21
|
+
import { AddStarknetChainParameters, ChainId } from "@starknet-io/types-js";
|
|
22
|
+
import { parseChainId } from "./utils";
|
|
20
23
|
|
|
21
24
|
export default class ControllerProvider extends BaseProvider {
|
|
22
25
|
private keychain?: AsyncMethodReturns<Keychain>;
|
|
23
26
|
private profile?: AsyncMethodReturns<Profile>;
|
|
24
27
|
private options: ControllerOptions;
|
|
25
28
|
private iframes: IFrames;
|
|
29
|
+
private selectedChain: ChainId;
|
|
30
|
+
private chains: Map<ChainId, Chain>;
|
|
26
31
|
|
|
27
32
|
constructor(options: ControllerOptions) {
|
|
28
|
-
|
|
29
|
-
|
|
33
|
+
super();
|
|
34
|
+
|
|
35
|
+
const chains = new Map<ChainId, Chain>();
|
|
36
|
+
|
|
37
|
+
for (const chain of options.chains) {
|
|
38
|
+
const url = new URL(chain.rpcUrl);
|
|
39
|
+
const chainId = parseChainId(url);
|
|
40
|
+
chains.set(chainId, chain);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (
|
|
44
|
+
options.policies?.messages?.length &&
|
|
45
|
+
options.policies.messages.length !== chains.size
|
|
46
|
+
) {
|
|
47
|
+
console.warn(
|
|
48
|
+
"Each message policy is associated with a specific chain. " +
|
|
49
|
+
"The number of message policies does not match the number of chains specified - " +
|
|
50
|
+
"session message signing may not work on some chains.",
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
this.chains = chains;
|
|
55
|
+
this.selectedChain = options.defaultChainId;
|
|
56
|
+
|
|
57
|
+
if (!this.chains.has(this.selectedChain)) {
|
|
58
|
+
throw new Error(
|
|
59
|
+
`Chain ${this.selectedChain} not found in configured chains`,
|
|
60
|
+
);
|
|
61
|
+
}
|
|
30
62
|
|
|
31
63
|
this.iframes = {
|
|
32
64
|
keychain: new KeychainIFrame({
|
|
@@ -54,12 +86,11 @@ export default class ControllerProvider extends BaseProvider {
|
|
|
54
86
|
return;
|
|
55
87
|
}
|
|
56
88
|
|
|
57
|
-
const response = (await this.keychain.probe(
|
|
58
|
-
this.rpc.toString(),
|
|
59
|
-
)) as ProbeReply;
|
|
89
|
+
const response = (await this.keychain.probe(this.rpcUrl())) as ProbeReply;
|
|
60
90
|
|
|
61
91
|
this.account = new ControllerAccount(
|
|
62
92
|
this,
|
|
93
|
+
this.rpcUrl(),
|
|
63
94
|
response.address,
|
|
64
95
|
this.keychain,
|
|
65
96
|
this.options,
|
|
@@ -83,7 +114,7 @@ export default class ControllerProvider extends BaseProvider {
|
|
|
83
114
|
openPurchaseCredits: () => this.openPurchaseCredits.bind(this),
|
|
84
115
|
openExecute: () => this.openExecute.bind(this),
|
|
85
116
|
},
|
|
86
|
-
rpcUrl: this.
|
|
117
|
+
rpcUrl: this.rpcUrl(),
|
|
87
118
|
username,
|
|
88
119
|
version: this.version,
|
|
89
120
|
});
|
|
@@ -113,8 +144,8 @@ export default class ControllerProvider extends BaseProvider {
|
|
|
113
144
|
|
|
114
145
|
try {
|
|
115
146
|
let response = await this.keychain.connect(
|
|
116
|
-
this.options.policies ||
|
|
117
|
-
this.
|
|
147
|
+
this.options.policies || {},
|
|
148
|
+
this.rpcUrl(),
|
|
118
149
|
);
|
|
119
150
|
if (response.code !== ResponseCodes.SUCCESS) {
|
|
120
151
|
throw new Error(response.message);
|
|
@@ -123,6 +154,7 @@ export default class ControllerProvider extends BaseProvider {
|
|
|
123
154
|
response = response as ConnectReply;
|
|
124
155
|
this.account = new ControllerAccount(
|
|
125
156
|
this,
|
|
157
|
+
this.rpcUrl(),
|
|
126
158
|
response.address,
|
|
127
159
|
this.keychain,
|
|
128
160
|
this.options,
|
|
@@ -137,6 +169,26 @@ export default class ControllerProvider extends BaseProvider {
|
|
|
137
169
|
}
|
|
138
170
|
}
|
|
139
171
|
|
|
172
|
+
async switchStarknetChain(chainId: string): Promise<boolean> {
|
|
173
|
+
try {
|
|
174
|
+
this.selectedChain = chainId;
|
|
175
|
+
this.account = await this.probe();
|
|
176
|
+
if (!this.account) {
|
|
177
|
+
this.account = await this.connect();
|
|
178
|
+
}
|
|
179
|
+
} catch (e) {
|
|
180
|
+
console.error(e);
|
|
181
|
+
return false;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
this.emitNetworkChanged(chainId);
|
|
185
|
+
return true;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
addStarknetChain(_chain: AddStarknetChainParameters): Promise<boolean> {
|
|
189
|
+
return Promise.resolve(true);
|
|
190
|
+
}
|
|
191
|
+
|
|
140
192
|
async disconnect() {
|
|
141
193
|
if (!this.keychain) {
|
|
142
194
|
console.error(new NotReadyToConnect().message);
|
|
@@ -197,6 +249,10 @@ export default class ControllerProvider extends BaseProvider {
|
|
|
197
249
|
return this.keychain.revoke(origin);
|
|
198
250
|
}
|
|
199
251
|
|
|
252
|
+
rpcUrl(): string {
|
|
253
|
+
return this.chains.get(this.selectedChain)!.rpcUrl;
|
|
254
|
+
}
|
|
255
|
+
|
|
200
256
|
username() {
|
|
201
257
|
if (!this.keychain) {
|
|
202
258
|
console.error(new NotReadyToConnect().message);
|
|
@@ -230,7 +286,7 @@ export default class ControllerProvider extends BaseProvider {
|
|
|
230
286
|
this.keychain.openPurchaseCredits();
|
|
231
287
|
}
|
|
232
288
|
|
|
233
|
-
async openExecute(calls: any) {
|
|
289
|
+
async openExecute(calls: any, chainId?: string) {
|
|
234
290
|
if (!this.keychain || !this.iframes.keychain) {
|
|
235
291
|
console.error(new NotReadyToConnect().message);
|
|
236
292
|
return;
|
|
@@ -239,16 +295,30 @@ export default class ControllerProvider extends BaseProvider {
|
|
|
239
295
|
console.error("Profile is not ready");
|
|
240
296
|
return;
|
|
241
297
|
}
|
|
242
|
-
if
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
this.
|
|
298
|
+
// Switch to the chain if provided
|
|
299
|
+
let currentChainId = this.selectedChain;
|
|
300
|
+
if (chainId) {
|
|
301
|
+
this.switchStarknetChain(chainId);
|
|
246
302
|
}
|
|
303
|
+
// Switch iframes
|
|
304
|
+
this.iframes.profile?.sendBackward();
|
|
247
305
|
this.iframes.keychain.open();
|
|
306
|
+
this.iframes.profile?.close();
|
|
307
|
+
// Invoke execute
|
|
248
308
|
const res = await this.keychain.execute(calls, undefined, undefined, true);
|
|
309
|
+
// Switch back iframes
|
|
310
|
+
this.iframes.profile?.open();
|
|
249
311
|
this.iframes.keychain.close();
|
|
250
|
-
this.iframes.profile?.sendForward
|
|
251
|
-
|
|
312
|
+
this.iframes.profile?.sendForward();
|
|
313
|
+
// Switch back to the original chain
|
|
314
|
+
if (chainId) {
|
|
315
|
+
this.switchStarknetChain(currentChainId);
|
|
316
|
+
}
|
|
317
|
+
return !(
|
|
318
|
+
res &&
|
|
319
|
+
((res as ConnectError).code === ResponseCodes.NOT_CONNECTED ||
|
|
320
|
+
(res as ConnectError).code === ResponseCodes.CANCELED)
|
|
321
|
+
);
|
|
252
322
|
}
|
|
253
323
|
|
|
254
324
|
async delegateAccount() {
|
package/src/provider.ts
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import { WalletAccount } from "starknet";
|
|
2
2
|
import {
|
|
3
3
|
AddInvokeTransactionParameters,
|
|
4
|
+
AddStarknetChainParameters,
|
|
4
5
|
Errors,
|
|
5
6
|
Permission,
|
|
7
|
+
RequestAccountsParameters,
|
|
6
8
|
RequestFn,
|
|
7
9
|
StarknetWindowObject,
|
|
10
|
+
SwitchStarknetChainParameters,
|
|
8
11
|
TypedData,
|
|
9
12
|
WalletEventHandlers,
|
|
10
13
|
WalletEventListener,
|
|
@@ -13,7 +16,6 @@ import {
|
|
|
13
16
|
import manifest from "../package.json";
|
|
14
17
|
|
|
15
18
|
import { icon } from "./icon";
|
|
16
|
-
import { ProviderOptions } from "./types";
|
|
17
19
|
|
|
18
20
|
export default abstract class BaseProvider implements StarknetWindowObject {
|
|
19
21
|
public id = "controller";
|
|
@@ -21,16 +23,9 @@ export default abstract class BaseProvider implements StarknetWindowObject {
|
|
|
21
23
|
public version = manifest.version;
|
|
22
24
|
public icon = icon;
|
|
23
25
|
|
|
24
|
-
public rpc: URL;
|
|
25
26
|
public account?: WalletAccount;
|
|
26
27
|
public subscriptions: WalletEvents[] = [];
|
|
27
28
|
|
|
28
|
-
constructor(options: ProviderOptions) {
|
|
29
|
-
const { rpc } = options;
|
|
30
|
-
|
|
31
|
-
this.rpc = new URL(rpc);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
29
|
request: RequestFn = async (call) => {
|
|
35
30
|
switch (call.type) {
|
|
36
31
|
case "wallet_getPermissions":
|
|
@@ -47,8 +42,11 @@ export default abstract class BaseProvider implements StarknetWindowObject {
|
|
|
47
42
|
return [this.account.address];
|
|
48
43
|
}
|
|
49
44
|
|
|
45
|
+
const silentMode =
|
|
46
|
+
call.params && (call.params as RequestAccountsParameters).silent_mode;
|
|
47
|
+
|
|
50
48
|
this.account = await this.probe();
|
|
51
|
-
if (!this.account) {
|
|
49
|
+
if (!this.account && !silentMode) {
|
|
52
50
|
this.account = await this.connect();
|
|
53
51
|
}
|
|
54
52
|
|
|
@@ -66,26 +64,22 @@ export default abstract class BaseProvider implements StarknetWindowObject {
|
|
|
66
64
|
data: "wallet_watchAsset not implemented",
|
|
67
65
|
} as Errors.UNEXPECTED_ERROR;
|
|
68
66
|
|
|
69
|
-
case "wallet_addStarknetChain":
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
data: "wallet_addStarknetChain not implemented",
|
|
74
|
-
} as Errors.UNEXPECTED_ERROR;
|
|
67
|
+
case "wallet_addStarknetChain": {
|
|
68
|
+
let params = call.params as AddStarknetChainParameters;
|
|
69
|
+
return this.addStarknetChain(params);
|
|
70
|
+
}
|
|
75
71
|
|
|
76
|
-
case "wallet_switchStarknetChain":
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
data: "wallet_switchStarknetChain not implemented",
|
|
81
|
-
} as Errors.UNEXPECTED_ERROR;
|
|
72
|
+
case "wallet_switchStarknetChain": {
|
|
73
|
+
let params = call.params as SwitchStarknetChainParameters;
|
|
74
|
+
return this.switchStarknetChain(params.chainId);
|
|
75
|
+
}
|
|
82
76
|
|
|
83
77
|
case "wallet_requestChainId":
|
|
84
78
|
if (!this.account) {
|
|
85
79
|
throw {
|
|
86
80
|
code: 63,
|
|
87
81
|
message: "An unexpected error occurred",
|
|
88
|
-
data: "
|
|
82
|
+
data: "Account not initialized",
|
|
89
83
|
} as Errors.UNEXPECTED_ERROR;
|
|
90
84
|
}
|
|
91
85
|
|
|
@@ -103,7 +97,7 @@ export default abstract class BaseProvider implements StarknetWindowObject {
|
|
|
103
97
|
throw {
|
|
104
98
|
code: 63,
|
|
105
99
|
message: "An unexpected error occurred",
|
|
106
|
-
data: "
|
|
100
|
+
data: "Account not initialized",
|
|
107
101
|
} as Errors.UNEXPECTED_ERROR;
|
|
108
102
|
}
|
|
109
103
|
|
|
@@ -173,6 +167,26 @@ export default abstract class BaseProvider implements StarknetWindowObject {
|
|
|
173
167
|
}
|
|
174
168
|
};
|
|
175
169
|
|
|
170
|
+
protected emitNetworkChanged(chainId: string) {
|
|
171
|
+
this.subscriptions
|
|
172
|
+
.filter((sub) => sub.type === "networkChanged")
|
|
173
|
+
.forEach((sub) => {
|
|
174
|
+
(sub.handler as WalletEventHandlers["networkChanged"])(chainId);
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
protected emitAccountsChanged(accounts: string[]) {
|
|
179
|
+
this.subscriptions
|
|
180
|
+
.filter((sub) => sub.type === "accountsChanged")
|
|
181
|
+
.forEach((sub) => {
|
|
182
|
+
(sub.handler as WalletEventHandlers["accountsChanged"])(accounts);
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
|
|
176
186
|
abstract probe(): Promise<WalletAccount | undefined>;
|
|
177
187
|
abstract connect(): Promise<WalletAccount | undefined>;
|
|
188
|
+
abstract switchStarknetChain(chainId: string): Promise<boolean>;
|
|
189
|
+
abstract addStarknetChain(
|
|
190
|
+
chain: AddStarknetChainParameters,
|
|
191
|
+
): Promise<boolean>;
|
|
178
192
|
}
|
package/src/session/provider.ts
CHANGED
|
@@ -5,6 +5,7 @@ import { KEYCHAIN_URL } from "../constants";
|
|
|
5
5
|
import BaseProvider from "../provider";
|
|
6
6
|
import { toWasmPolicies } from "../utils";
|
|
7
7
|
import { SessionPolicies } from "@cartridge/presets";
|
|
8
|
+
import { AddStarknetChainParameters } from "@starknet-io/types-js";
|
|
8
9
|
|
|
9
10
|
interface SessionRegistration {
|
|
10
11
|
username: string;
|
|
@@ -26,14 +27,15 @@ export default class SessionProvider extends BaseProvider {
|
|
|
26
27
|
public name = "Controller Session";
|
|
27
28
|
|
|
28
29
|
protected _chainId: string;
|
|
29
|
-
|
|
30
|
+
protected _rpcUrl: string;
|
|
30
31
|
protected _username?: string;
|
|
31
32
|
protected _redirectUrl: string;
|
|
32
33
|
protected _policies: SessionPolicies;
|
|
33
34
|
|
|
34
35
|
constructor({ rpc, chainId, policies, redirectUrl }: SessionOptions) {
|
|
35
|
-
super(
|
|
36
|
+
super();
|
|
36
37
|
|
|
38
|
+
this._rpcUrl = rpc;
|
|
37
39
|
this._chainId = chainId;
|
|
38
40
|
this._redirectUrl = redirectUrl;
|
|
39
41
|
this._policies = policies;
|
|
@@ -76,7 +78,7 @@ export default class SessionProvider extends BaseProvider {
|
|
|
76
78
|
this._redirectUrl
|
|
77
79
|
}&redirect_query_name=startapp&policies=${JSON.stringify(
|
|
78
80
|
this._policies,
|
|
79
|
-
)}&rpc_url=${this.
|
|
81
|
+
)}&rpc_url=${this._rpcUrl}`;
|
|
80
82
|
|
|
81
83
|
localStorage.setItem("lastUsedConnector", this.id);
|
|
82
84
|
window.open(url, "_blank");
|
|
@@ -84,6 +86,14 @@ export default class SessionProvider extends BaseProvider {
|
|
|
84
86
|
return;
|
|
85
87
|
}
|
|
86
88
|
|
|
89
|
+
switchStarknetChain(_chainId: string): Promise<boolean> {
|
|
90
|
+
throw new Error("switchStarknetChain not implemented");
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
addStarknetChain(_chain: AddStarknetChainParameters): Promise<boolean> {
|
|
94
|
+
throw new Error("addStarknetChain not implemented");
|
|
95
|
+
}
|
|
96
|
+
|
|
87
97
|
disconnect(): Promise<void> {
|
|
88
98
|
localStorage.removeItem("sessionSigner");
|
|
89
99
|
localStorage.removeItem("session");
|
|
@@ -127,7 +137,7 @@ export default class SessionProvider extends BaseProvider {
|
|
|
127
137
|
|
|
128
138
|
this._username = sessionRegistration.username;
|
|
129
139
|
this.account = new SessionAccount(this, {
|
|
130
|
-
rpcUrl: this.
|
|
140
|
+
rpcUrl: this._rpcUrl,
|
|
131
141
|
privateKey: signer.privKey,
|
|
132
142
|
address: sessionRegistration.address,
|
|
133
143
|
ownerGuid: sessionRegistration.ownerGuid,
|
package/src/telegram/provider.ts
CHANGED
|
@@ -11,6 +11,7 @@ import SessionAccount from "../session/account";
|
|
|
11
11
|
import BaseProvider from "../provider";
|
|
12
12
|
import { toWasmPolicies } from "../utils";
|
|
13
13
|
import { SessionPolicies } from "@cartridge/presets";
|
|
14
|
+
import { AddStarknetChainParameters } from "@starknet-io/types-js";
|
|
14
15
|
|
|
15
16
|
interface SessionRegistration {
|
|
16
17
|
username: string;
|
|
@@ -25,6 +26,7 @@ export default class TelegramProvider extends BaseProvider {
|
|
|
25
26
|
protected _chainId: string;
|
|
26
27
|
protected _username?: string;
|
|
27
28
|
protected _policies: SessionPolicies;
|
|
29
|
+
private _rpcUrl: string;
|
|
28
30
|
|
|
29
31
|
constructor({
|
|
30
32
|
rpc,
|
|
@@ -37,10 +39,9 @@ export default class TelegramProvider extends BaseProvider {
|
|
|
37
39
|
policies: SessionPolicies;
|
|
38
40
|
tmaUrl: string;
|
|
39
41
|
}) {
|
|
40
|
-
super(
|
|
41
|
-
rpc,
|
|
42
|
-
});
|
|
42
|
+
super();
|
|
43
43
|
|
|
44
|
+
this._rpcUrl = rpc;
|
|
44
45
|
this._tmaUrl = tmaUrl;
|
|
45
46
|
this._chainId = chainId;
|
|
46
47
|
this._policies = policies;
|
|
@@ -77,7 +78,7 @@ export default class TelegramProvider extends BaseProvider {
|
|
|
77
78
|
this._tmaUrl
|
|
78
79
|
}&redirect_query_name=startapp&policies=${JSON.stringify(
|
|
79
80
|
this._policies,
|
|
80
|
-
)}&rpc_url=${this.
|
|
81
|
+
)}&rpc_url=${this._rpcUrl}`;
|
|
81
82
|
|
|
82
83
|
localStorage.setItem("lastUsedConnector", this.id);
|
|
83
84
|
openLink(url);
|
|
@@ -86,6 +87,14 @@ export default class TelegramProvider extends BaseProvider {
|
|
|
86
87
|
return;
|
|
87
88
|
}
|
|
88
89
|
|
|
90
|
+
switchStarknetChain(_chainId: string): Promise<boolean> {
|
|
91
|
+
throw new Error("switchStarknetChain not implemented");
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
addStarknetChain(_chain: AddStarknetChainParameters): Promise<boolean> {
|
|
95
|
+
throw new Error("addStarknetChain not implemented");
|
|
96
|
+
}
|
|
97
|
+
|
|
89
98
|
disconnect(): Promise<void> {
|
|
90
99
|
cloudStorage.deleteItem("sessionSigner");
|
|
91
100
|
cloudStorage.deleteItem("session");
|
|
@@ -118,7 +127,7 @@ export default class TelegramProvider extends BaseProvider {
|
|
|
118
127
|
|
|
119
128
|
this._username = sessionRegistration.username;
|
|
120
129
|
this.account = new SessionAccount(this, {
|
|
121
|
-
rpcUrl: this.
|
|
130
|
+
rpcUrl: this._rpcUrl,
|
|
122
131
|
privateKey: signer.privKey,
|
|
123
132
|
address: sessionRegistration.address,
|
|
124
133
|
ownerGuid: sessionRegistration.ownerGuid,
|
package/src/types.ts
CHANGED
|
@@ -7,16 +7,12 @@ import {
|
|
|
7
7
|
} from "starknet";
|
|
8
8
|
import {
|
|
9
9
|
AddInvokeTransactionResult,
|
|
10
|
+
ChainId,
|
|
10
11
|
Signature,
|
|
11
12
|
TypedData,
|
|
12
13
|
} from "@starknet-io/types-js";
|
|
13
14
|
import { KeychainIFrame, ProfileIFrame } from "./iframe";
|
|
14
|
-
import {
|
|
15
|
-
ColorMode,
|
|
16
|
-
Policies,
|
|
17
|
-
Policy,
|
|
18
|
-
SessionPolicies,
|
|
19
|
-
} from "@cartridge/presets";
|
|
15
|
+
import { ColorMode, Policy, SessionPolicies } from "@cartridge/presets";
|
|
20
16
|
|
|
21
17
|
export type Session = {
|
|
22
18
|
chainId: constants.StarknetChainId;
|
|
@@ -100,7 +96,7 @@ export type ControllerAccounts = Record<ContractAddress, CartridgeID>;
|
|
|
100
96
|
export interface Keychain {
|
|
101
97
|
probe(rpcUrl: string): Promise<ProbeReply | ConnectError>;
|
|
102
98
|
connect(
|
|
103
|
-
policies:
|
|
99
|
+
policies: SessionPolicies,
|
|
104
100
|
rpcUrl: string,
|
|
105
101
|
): Promise<ConnectReply | ConnectError>;
|
|
106
102
|
disconnect(): void;
|
|
@@ -134,6 +130,7 @@ export interface Keychain {
|
|
|
134
130
|
openPurchaseCredits(): void;
|
|
135
131
|
openExecute(calls: Call[]): Promise<void>;
|
|
136
132
|
}
|
|
133
|
+
|
|
137
134
|
export interface Profile {
|
|
138
135
|
navigate(path: string): void;
|
|
139
136
|
}
|
|
@@ -161,13 +158,17 @@ export type IFrameOptions = {
|
|
|
161
158
|
colorMode?: ColorMode;
|
|
162
159
|
};
|
|
163
160
|
|
|
161
|
+
export type Chain = {
|
|
162
|
+
rpcUrl: string;
|
|
163
|
+
};
|
|
164
|
+
|
|
164
165
|
export type ProviderOptions = {
|
|
165
|
-
|
|
166
|
-
|
|
166
|
+
defaultChainId: ChainId;
|
|
167
|
+
chains: Chain[];
|
|
167
168
|
};
|
|
168
169
|
|
|
169
170
|
export type KeychainOptions = IFrameOptions & {
|
|
170
|
-
policies?:
|
|
171
|
+
policies?: SessionPolicies;
|
|
171
172
|
/** The URL of keychain */
|
|
172
173
|
url?: string;
|
|
173
174
|
/** The origin of keychain */
|
|
@@ -193,8 +194,6 @@ export type ProfileContextTypeVariant =
|
|
|
193
194
|
| "achievements"
|
|
194
195
|
| "activity";
|
|
195
196
|
|
|
196
|
-
export type Prefund = { address: string; min: string };
|
|
197
|
-
|
|
198
197
|
export type Tokens = {
|
|
199
198
|
erc20?: string[];
|
|
200
199
|
};
|
package/src/utils.ts
CHANGED
|
@@ -2,13 +2,16 @@ import {
|
|
|
2
2
|
addAddressPadding,
|
|
3
3
|
Call,
|
|
4
4
|
CallData,
|
|
5
|
+
constants,
|
|
5
6
|
getChecksumAddress,
|
|
6
7
|
hash,
|
|
8
|
+
shortString,
|
|
7
9
|
typedData,
|
|
8
10
|
TypedDataRevision,
|
|
9
11
|
} from "starknet";
|
|
10
12
|
import wasm from "@cartridge/account-wasm/controller";
|
|
11
13
|
import { Policies, SessionPolicies } from "@cartridge/presets";
|
|
14
|
+
import { ChainId } from "@starknet-io/types-js";
|
|
12
15
|
|
|
13
16
|
// Whitelist of allowed property names to prevent prototype pollution
|
|
14
17
|
const ALLOWED_PROPERTIES = new Set([
|
|
@@ -129,3 +132,28 @@ export function humanizeString(str: string): string {
|
|
|
129
132
|
.replace(/^\w/, (c) => c.toUpperCase())
|
|
130
133
|
);
|
|
131
134
|
}
|
|
135
|
+
|
|
136
|
+
export function parseChainId(url: URL): ChainId {
|
|
137
|
+
const parts = url.pathname.split("/");
|
|
138
|
+
|
|
139
|
+
if (parts.includes("starknet")) {
|
|
140
|
+
if (parts.includes("mainnet")) {
|
|
141
|
+
return constants.StarknetChainId.SN_MAIN;
|
|
142
|
+
} else if (parts.includes("sepolia")) {
|
|
143
|
+
return constants.StarknetChainId.SN_SEPOLIA;
|
|
144
|
+
}
|
|
145
|
+
} else if (parts.length >= 3) {
|
|
146
|
+
const projectName = parts[2];
|
|
147
|
+
if (parts.includes("katana")) {
|
|
148
|
+
return shortString.encodeShortString(
|
|
149
|
+
`WP_${projectName.toUpperCase().replace(/-/g, "_")}`,
|
|
150
|
+
) as ChainId;
|
|
151
|
+
} else if (parts.includes("mainnet")) {
|
|
152
|
+
return shortString.encodeShortString(
|
|
153
|
+
`GG_${projectName.toUpperCase().replace(/-/g, "_")}`,
|
|
154
|
+
) as ChainId;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
throw new Error(`Chain ${url.toString()} not supported`);
|
|
159
|
+
}
|