Skip to content

Commit 5a0786f

Browse files
authored
Merge pull request #88 from mycactus/cactuslink-wallet-module
Feat: Add Cactus Link wallet module
2 parents 5c6fafb + f501f0c commit 5a0786f

4 files changed

Lines changed: 158 additions & 0 deletions

File tree

src/build_npm.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,10 +76,15 @@ await build({
7676
name: "./modules/xbull",
7777
path: "./sdk/modules/xbull.module.ts",
7878
},
79+
{
80+
name: "./modules/cactuslink",
81+
path: "./sdk/modules/cactuslink.module.ts",
82+
},
7983
{
8084
name: "./modules/utils",
8185
path: "./sdk/modules/utils.ts",
8286
},
87+
8388
],
8489
outDir: "./dist",
8590
shims: {

src/deno.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
"./modules/trezor": "./sdk/modules/trezor.module.ts",
5252
"./modules/wallet-connect": "./sdk/modules/wallet-connect.module.ts",
5353
"./modules/xbull": "./sdk/modules/xbull.module.ts",
54+
"./modules/cactuslink": "./sdk/modules/cactuslink.module.ts",
5455
"./modules/utils": "./sdk/modules/utils.ts"
5556
},
5657
"fmt": {
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
import { type ModuleInterface, ModuleType } from "../../types/mod.ts";
2+
import { parseError } from "../utils.ts";
3+
4+
declare const window: {
5+
cactuslink_stellar?: {
6+
isConnected(): Promise<{ isConnected: boolean; error?: string }>;
7+
getAddress(): Promise<{ address: string; error?: string }>;
8+
requestAccess(): Promise<{ error?: string }>;
9+
signTransaction(
10+
xdr: string,
11+
opts?: { address?: string; networkPassphrase?: string },
12+
): Promise<{ signedTxXdr: string}>;
13+
signAuthEntry(
14+
authEntry: string,
15+
opts?: { address?: string; networkPassphrase?: string },
16+
): Promise<{ signedAuthEntry: string }>;
17+
signMessage(
18+
message: string,
19+
opts?: { address?: string; networkPassphrase?: string },
20+
): Promise<{ signedMessage: string }>;
21+
getNetwork(): Promise<{ network: string; networkPassphrase: string; error?: string }>;
22+
};
23+
};
24+
25+
export const CACTUSLINK_ID: string = "cactuslink";
26+
27+
export class CactusLinkModule implements ModuleInterface {
28+
moduleType: ModuleType = ModuleType.HOT_WALLET;
29+
30+
productId: string = CACTUSLINK_ID;
31+
productName: string = "Cactus Link";
32+
productUrl: string = "https://www.mycactus.com";
33+
productIcon: string = "https://stellar.creit.tech/wallet-icons/cactuslink.png";
34+
35+
async runChecks(): Promise<void> {
36+
if (!(await this.isAvailable())) {
37+
throw new Error("Cactus Link is not installed");
38+
}
39+
}
40+
41+
async isAvailable(): Promise<boolean> {
42+
return typeof window !== "undefined" && !!window.cactuslink_stellar;
43+
}
44+
45+
async getAddress(): Promise<{ address: string }> {
46+
try {
47+
await this.runChecks();
48+
49+
const { address } = await window.cactuslink_stellar!.getAddress();
50+
if (!address) {
51+
return Promise.reject({
52+
code: -3,
53+
message: "Getting the address from Cactus Link is not allowed, please request access first.",
54+
});
55+
}
56+
57+
return { address };
58+
} catch (e) {
59+
throw parseError(e);
60+
}
61+
}
62+
63+
async signTransaction(
64+
xdr: string,
65+
opts?: {
66+
networkPassphrase?: string;
67+
address?: string;
68+
path?: string;
69+
},
70+
): Promise<{ signedTxXdr: string; signerAddress?: string }> {
71+
try {
72+
await this.runChecks();
73+
74+
const { signedTxXdr } = await window.cactuslink_stellar!.signTransaction(xdr, opts);
75+
76+
return { signedTxXdr };
77+
} catch (e) {
78+
throw parseError(e);
79+
}
80+
}
81+
82+
async signAuthEntry(
83+
authEntry: string,
84+
opts?: {
85+
networkPassphrase?: string;
86+
address?: string;
87+
path?: string;
88+
},
89+
): Promise<{ signedAuthEntry: string; signerAddress?: string }> {
90+
try {
91+
await this.runChecks();
92+
93+
const { signedAuthEntry } = await window.cactuslink_stellar!.signAuthEntry(authEntry, opts);
94+
95+
if (!signedAuthEntry) {
96+
return Promise.reject({
97+
code: -3,
98+
message: "signedAuthEntry returned from Cactus Link is undefined.",
99+
});
100+
}
101+
102+
return {
103+
signedAuthEntry
104+
};
105+
} catch (e) {
106+
throw parseError(e);
107+
}
108+
}
109+
110+
async signMessage(
111+
message: string,
112+
opts?: {
113+
networkPassphrase?: string;
114+
address?: string;
115+
path?: string;
116+
},
117+
): Promise<{ signedMessage: string; signerAddress?: string }> {
118+
try {
119+
await this.runChecks();
120+
const { signedMessage } = await window.cactuslink_stellar!.signMessage(message, opts);
121+
122+
if (!signedMessage) {
123+
return Promise.reject({
124+
code: -3,
125+
message: "signedMessage returned from Cactus Link is undefined.",
126+
});
127+
}
128+
129+
return {
130+
signedMessage
131+
};
132+
} catch (e) {
133+
throw parseError(e);
134+
}
135+
}
136+
137+
async getNetwork(): Promise<{ network: string; networkPassphrase: string }> {
138+
try {
139+
await this.runChecks();
140+
141+
const { network, networkPassphrase, error } = await window.cactuslink_stellar!.getNetwork();
142+
143+
if (error) return Promise.reject(error);
144+
145+
return { network, networkPassphrase };
146+
} catch (e) {
147+
throw parseError(e);
148+
}
149+
}
150+
}

src/sdk/modules/utils.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { HanaModule } from "./hana.module.ts";
88
import { KleverModule } from "./klever.module.ts";
99
import { OneKeyModule } from "./onekey.module.ts";
1010
import { BitgetModule } from "./bitget.module.ts";
11+
import { CactusLinkModule } from "./cactuslink.module.ts";
1112

1213
/**
1314
* This method returns all modules that don't require extra configuration before they can be loaded
@@ -29,6 +30,7 @@ export function defaultModules(opts?: {
2930
new KleverModule(),
3031
new OneKeyModule(),
3132
new BitgetModule(),
33+
new CactusLinkModule(),
3234
];
3335
return opts?.filterBy ? modules.filter(opts.filterBy) : modules;
3436
}

0 commit comments

Comments
 (0)