@swapkit/wallets 4.8.0 → 4.8.1

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.
@@ -0,0 +1,89 @@
1
+ import { type AssetValue, Chain, SwapKitError } from "@swapkit/helpers";
2
+ import { match } from "ts-pattern";
3
+ import type { Xumm } from "xumm";
4
+ import { sendXamanTransaction, sendXamanTrustSet, submitXamanPayload } from "./walletMethods";
5
+
6
+ interface GetWalletForChainParams {
7
+ chain: Chain;
8
+ address: string;
9
+ xumm: Xumm;
10
+ }
11
+
12
+ export function getWalletForChain({ xumm, chain, address }: GetWalletForChainParams) {
13
+ return match(chain)
14
+ .with(Chain.Ripple, async () => {
15
+ const { getRippleToolbox } = await import("@swapkit/toolboxes/ripple");
16
+
17
+ const signer = {
18
+ getAddress: () => address,
19
+ signTransaction: async (jsonTx: Record<string, unknown>) => {
20
+ const txjson = { ...jsonTx, Account: jsonTx.Account ?? address };
21
+ const submitted = await submitXamanPayload(xumm, txjson, { submit: false });
22
+
23
+ if (!submitted.result.hex) {
24
+ throw new SwapKitError("wallet_xaman_transaction_failed");
25
+ }
26
+
27
+ return { hash: submitted.result.transactionId, tx_blob: submitted.result.hex };
28
+ },
29
+ };
30
+
31
+ const toolbox = await getRippleToolbox({ signer });
32
+
33
+ const transfer = async ({
34
+ assetValue,
35
+ recipient,
36
+ memo,
37
+ destinationTag,
38
+ }: {
39
+ assetValue: AssetValue;
40
+ recipient: string;
41
+ memo?: string;
42
+ destinationTag?: number;
43
+ }) => {
44
+ const isTokenTransfer = !assetValue.isGasAsset;
45
+
46
+ if (isTokenTransfer && (!assetValue.ticker || !assetValue.address)) {
47
+ throw new SwapKitError("wallet_xaman_transaction_failed");
48
+ }
49
+
50
+ const paymentResult = await sendXamanTransaction(xumm, {
51
+ amount: assetValue.getValue("string"),
52
+ destination: recipient,
53
+ destinationTag,
54
+ from: address,
55
+ memo,
56
+ ...(isTokenTransfer && { currency: assetValue.ticker, issuer: assetValue.address }),
57
+ });
58
+
59
+ if (!(paymentResult.result.success && paymentResult.result.transactionId)) {
60
+ throw new SwapKitError("wallet_xaman_transaction_failed");
61
+ }
62
+
63
+ return paymentResult.result.transactionId;
64
+ };
65
+
66
+ const setTrustLine = async (params: { currency: string; issuer: string; limit: string }) => {
67
+ const trustSetResult = await sendXamanTrustSet(xumm, { ...params, from: address });
68
+
69
+ if (!(trustSetResult.result.success && trustSetResult.result.transactionId)) {
70
+ throw new SwapKitError("wallet_xaman_transaction_failed");
71
+ }
72
+
73
+ return trustSetResult.result.transactionId;
74
+ };
75
+
76
+ return {
77
+ ...toolbox,
78
+ address,
79
+ createAndSubscribePayment: sendXamanTransaction,
80
+ disconnect: xumm.logout,
81
+ getAddress: () => address,
82
+ setTrustLine,
83
+ transfer,
84
+ };
85
+ })
86
+ .otherwise(() => {
87
+ throw new SwapKitError("wallet_chain_not_supported", { chain, wallet: "Xaman" });
88
+ });
89
+ }
@@ -0,0 +1,63 @@
1
+ import { Chain, filterSupportedChains, SKConfig, SwapKitError, WalletOption } from "@swapkit/helpers";
2
+ import { createWallet, getWalletSupportedChains } from "@swapkit/wallet-core";
3
+ import { Xumm } from "xumm";
4
+ import { getWalletForChain } from "./helpers";
5
+ import type { XamanConfig } from "./types";
6
+ import { connectXamanWallet as connectXamanWalletMethod } from "./walletMethods";
7
+
8
+ export const xamanWallet = createWallet({
9
+ connect: ({ addChain, supportedChains: walletSupportedChains, walletType }) =>
10
+ function connectXamanWallet(chains: Chain[], xamanConfigOverwrite?: XamanConfig) {
11
+ const supportedChains = filterSupportedChains({ chains, supportedChains: walletSupportedChains, walletType });
12
+
13
+ const { xaman: xamanApiKey } = SKConfig.get("apiKeys");
14
+ const apiKey = xamanConfigOverwrite?.apiKey || xamanApiKey;
15
+
16
+ if (!apiKey) {
17
+ throw new SwapKitError("wallet_missing_api_key", { wallet: "Xaman" });
18
+ }
19
+
20
+ const xumm = new Xumm(apiKey);
21
+
22
+ return new Promise<boolean>((resolve, reject) => {
23
+ xumm.on("success", async () => {
24
+ try {
25
+ const address = await connectXamanWalletMethod(xumm);
26
+
27
+ const promises = supportedChains.map(async (chain) => {
28
+ const walletMethods = await getWalletForChain({ address, chain, xumm });
29
+
30
+ addChain({
31
+ ...walletMethods,
32
+ address,
33
+ balance: [],
34
+ chain,
35
+ disconnect: xumm.logout,
36
+ walletType: WalletOption.XAMAN,
37
+ });
38
+ });
39
+
40
+ await Promise.all(promises);
41
+ resolve(true);
42
+ } catch (error) {
43
+ reject(error);
44
+ }
45
+ });
46
+
47
+ xumm.on("error", (error) => {
48
+ reject(error);
49
+ });
50
+
51
+ xumm.authorize();
52
+ });
53
+ },
54
+ directSigningSupport: { [Chain.Ripple]: true },
55
+ name: "connectXaman",
56
+ supportedChains: [Chain.Ripple],
57
+ walletType: WalletOption.XAMAN,
58
+ });
59
+
60
+ export const XAMAN_SUPPORTED_CHAINS = getWalletSupportedChains(xamanWallet);
61
+ export type XamanSupportedChain = (typeof XAMAN_SUPPORTED_CHAINS)[number];
62
+
63
+ export type { XamanConfig, XamanPaymentParams, XamanTrustSetParams } from "./types";
@@ -0,0 +1,35 @@
1
+ export interface XamanConfig {
2
+ apiKey: string;
3
+ }
4
+
5
+ export interface XamanPaymentParams {
6
+ destination: string;
7
+ from: string;
8
+ amount: string;
9
+ memo?: string;
10
+ destinationTag?: number;
11
+ currency?: string;
12
+ issuer?: string;
13
+ }
14
+
15
+ export interface XamanTrustSetParams {
16
+ from: string;
17
+ currency: string;
18
+ issuer: string;
19
+ limit: string;
20
+ }
21
+
22
+ export interface XamanPaymentResult {
23
+ payloadId: string;
24
+ qrCode: string;
25
+ deepLink: string;
26
+ websocketUrl: string;
27
+ result: XamanTransactionResult;
28
+ }
29
+
30
+ export interface XamanTransactionResult {
31
+ success: boolean;
32
+ transactionId?: string;
33
+ account?: string;
34
+ reason?: string;
35
+ }
@@ -0,0 +1,117 @@
1
+ import { SwapKitError } from "@swapkit/helpers";
2
+ import type { Xumm } from "xumm";
3
+ import type { XamanPaymentParams, XamanTrustSetParams } from "./types";
4
+
5
+ export const connectXamanWallet = async (xumm: Xumm) => {
6
+ if (!xumm) {
7
+ throw new SwapKitError("wallet_xaman_not_configured");
8
+ }
9
+
10
+ try {
11
+ const user = await xumm.user;
12
+ const account = await user?.account;
13
+
14
+ if (account) {
15
+ return account;
16
+ }
17
+
18
+ throw new SwapKitError("wallet_xaman_auth_failed");
19
+ } catch {
20
+ throw new SwapKitError("wallet_xaman_connection_failed");
21
+ }
22
+ };
23
+
24
+ export async function submitXamanPayload(
25
+ xumm: Xumm,
26
+ txjson: Record<string, unknown>,
27
+ { submit = true }: { submit?: boolean } = {},
28
+ ) {
29
+ const payload = (submit ? txjson : { options: { submit: false }, txjson }) as Parameters<
30
+ NonNullable<Xumm["payload"]>["createAndSubscribe"]
31
+ >[0];
32
+
33
+ const subscription = await xumm.payload?.createAndSubscribe(payload, (event) => {
34
+ if ("signed" in event.data) return event.data;
35
+ return undefined;
36
+ });
37
+
38
+ if (!subscription) {
39
+ throw new SwapKitError("wallet_xaman_transaction_failed");
40
+ }
41
+
42
+ const { created } = subscription;
43
+
44
+ if (xumm.runtime?.xapp) {
45
+ xumm.xapp?.openSignRequest(created);
46
+ } else if (typeof window !== "undefined") {
47
+ const url =
48
+ created.pushed && created.next?.no_push_msg_received ? created.next.no_push_msg_received : created.next?.always;
49
+ if (url) window.open(url);
50
+ }
51
+
52
+ const resolved = await subscription.resolved;
53
+
54
+ if (!resolved || typeof resolved !== "object" || !("signed" in resolved) || !resolved.signed) {
55
+ throw new SwapKitError("wallet_xaman_transaction_failed");
56
+ }
57
+
58
+ const payloadDetails = await xumm.payload?.get((resolved as any).payload_uuidv4);
59
+
60
+ if (!payloadDetails) {
61
+ throw new SwapKitError("wallet_xaman_monitoring_failed");
62
+ }
63
+
64
+ const transactionId = payloadDetails.response?.txid || "";
65
+ const account = payloadDetails.response?.account || "";
66
+ const hex = payloadDetails.response?.hex || "";
67
+
68
+ if (!transactionId) {
69
+ throw new SwapKitError("wallet_xaman_transaction_failed");
70
+ }
71
+
72
+ return {
73
+ deepLink: created.next?.always || "",
74
+ payloadId: created.uuid || "",
75
+ qrCode: created.refs?.qr_png || "",
76
+ result: { account, hex, reason: undefined, success: true, transactionId },
77
+ websocketUrl: created.refs?.websocket_status || "",
78
+ };
79
+ }
80
+
81
+ export async function sendXamanTransaction(xumm: Xumm, params: XamanPaymentParams) {
82
+ if (!(params.destination && params.amount && params.from)) {
83
+ throw new SwapKitError("wallet_xaman_connection_failed");
84
+ }
85
+
86
+ const isTokenTransfer = params.currency && params.issuer;
87
+ const amount = isTokenTransfer
88
+ ? { currency: params.currency, issuer: params.issuer, value: params.amount }
89
+ : (Number.parseFloat(params.amount) * 1000000).toString();
90
+
91
+ const transaction = {
92
+ Account: params.from,
93
+ Amount: amount,
94
+ Destination: params.destination,
95
+ TransactionType: "Payment" as const,
96
+ ...(params.destinationTag !== undefined && { DestinationTag: params.destinationTag }),
97
+ ...(params.memo && {
98
+ Memos: [{ Memo: { MemoData: Buffer.from(params.memo, "utf8").toString("hex").toUpperCase() } }],
99
+ }),
100
+ };
101
+
102
+ return await submitXamanPayload(xumm, transaction);
103
+ }
104
+
105
+ export async function sendXamanTrustSet(xumm: Xumm, params: XamanTrustSetParams) {
106
+ if (!(params.from && params.currency && params.issuer && params.limit !== undefined)) {
107
+ throw new SwapKitError("wallet_xaman_connection_failed");
108
+ }
109
+
110
+ const transaction = {
111
+ Account: params.from,
112
+ LimitAmount: { currency: params.currency, issuer: params.issuer, value: params.limit },
113
+ TransactionType: "TrustSet" as const,
114
+ };
115
+
116
+ return await submitXamanPayload(xumm, transaction);
117
+ }