@aurora-is-near/intents-swap-widget-stellar 7.1.0
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/dist/constants.d.ts +3 -0
- package/dist/fetchNativeBalances.d.ts +4 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +134 -0
- package/dist/index.js.map +1 -0
- package/dist/makeTransfer.d.ts +5 -0
- package/dist/plugin.d.ts +2 -0
- package/dist/types.d.ts +5 -0
- package/package.json +38 -0
- package/src/constants.ts +12 -0
- package/src/fetchNativeBalances.ts +74 -0
- package/src/index.ts +3 -0
- package/src/makeTransfer.ts +183 -0
- package/src/plugin.ts +23 -0
- package/src/types.ts +6 -0
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { Asset as T, xdr as o, StrKey as K, rpc as x, Operation as A, TransactionBuilder as P, Networks as m, BASE_FEE as X, Memo as d } from "@stellar/stellar-sdk";
|
|
2
|
+
import C from "axios";
|
|
3
|
+
const S = [
|
|
4
|
+
"https://sorobanrpc.stellar.org",
|
|
5
|
+
"https://rpc.ankr.com/stellar_soroban",
|
|
6
|
+
"https://stellar-soroban-public.nodies.app"
|
|
7
|
+
], E = new T(
|
|
8
|
+
"USDC",
|
|
9
|
+
"GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN"
|
|
10
|
+
), D = async (t) => {
|
|
11
|
+
const n = o.PublicKey.publicKeyTypeEd25519(
|
|
12
|
+
K.decodeEd25519PublicKey(t)
|
|
13
|
+
), b = o.LedgerKey.account(
|
|
14
|
+
new o.LedgerKeyAccount({ accountId: n })
|
|
15
|
+
).toXDR("base64"), a = o.LedgerKey.trustline(
|
|
16
|
+
new o.LedgerKeyTrustLine({
|
|
17
|
+
accountId: n,
|
|
18
|
+
asset: E.toTrustLineXDRObject()
|
|
19
|
+
})
|
|
20
|
+
).toXDR("base64"), c = {
|
|
21
|
+
id: 1,
|
|
22
|
+
jsonrpc: "2.0",
|
|
23
|
+
method: "getLedgerEntries",
|
|
24
|
+
params: { keys: [b, a] }
|
|
25
|
+
};
|
|
26
|
+
for (const p of S)
|
|
27
|
+
try {
|
|
28
|
+
const i = (await C.post(p, c, {
|
|
29
|
+
headers: { "Content-Type": "application/json" },
|
|
30
|
+
timeout: 3e3
|
|
31
|
+
})).data?.result?.entries;
|
|
32
|
+
if (!i || i.length === 0)
|
|
33
|
+
continue;
|
|
34
|
+
let u = "0", f = "0";
|
|
35
|
+
return i.forEach((l) => {
|
|
36
|
+
if (!l.xdr)
|
|
37
|
+
return;
|
|
38
|
+
const r = o.LedgerEntryData.fromXDR(l.xdr, "base64");
|
|
39
|
+
r.switch().name === "account" && (u = r.account().balance().toString()), r.switch().name === "trustline" && (f = r.trustLine().balance().toString());
|
|
40
|
+
}), { xlmStroops: u, usdcStroops: f };
|
|
41
|
+
} catch {
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
return { xlmStroops: "0", usdcStroops: "0" };
|
|
45
|
+
}, $ = "https://stellar.expert/explorer/public/tx/", B = (t) => {
|
|
46
|
+
if (!t)
|
|
47
|
+
return d.none();
|
|
48
|
+
if (/^\d+$/.test(t))
|
|
49
|
+
return d.id(t);
|
|
50
|
+
if (Buffer.from(t).length <= 28)
|
|
51
|
+
return d.text(t);
|
|
52
|
+
if (/^g[0-7a-z]{55}$/.test(t)) {
|
|
53
|
+
const n = K.decodeEd25519PublicKey(
|
|
54
|
+
t.toUpperCase()
|
|
55
|
+
);
|
|
56
|
+
return d.hash(n);
|
|
57
|
+
}
|
|
58
|
+
if (/^[0-9a-fA-F]{64}$/.test(t))
|
|
59
|
+
return d.hash(t);
|
|
60
|
+
throw new Error(`Unsupported Stellar memo format: ${t}`);
|
|
61
|
+
}, U = async (t, {
|
|
62
|
+
provider: n,
|
|
63
|
+
explorerBaseUrl: b = $
|
|
64
|
+
}) => {
|
|
65
|
+
if (!n.publicKey)
|
|
66
|
+
throw new Error("No public key found in Stellar provider.");
|
|
67
|
+
if (!t.memo)
|
|
68
|
+
throw new Error("No memo provided.");
|
|
69
|
+
let a = null, c = null;
|
|
70
|
+
for (const e of S)
|
|
71
|
+
try {
|
|
72
|
+
const y = new x.Server(e);
|
|
73
|
+
c = await y.getAccount(n.publicKey), a = y;
|
|
74
|
+
break;
|
|
75
|
+
} catch {
|
|
76
|
+
}
|
|
77
|
+
if (!a || !c)
|
|
78
|
+
throw new Error("Could not connect to Stellar RPC to load account data.");
|
|
79
|
+
const p = BigInt(t.amount), R = p / 10000000n, i = (p % 10000000n).toString().padStart(7, "0"), u = `${R}.${i}`.replace(/\.?0+$/, ""), f = t.tokenAddress === E.issuer ? A.payment({
|
|
80
|
+
destination: t.address,
|
|
81
|
+
asset: E,
|
|
82
|
+
amount: u
|
|
83
|
+
}) : A.payment({
|
|
84
|
+
destination: t.address,
|
|
85
|
+
asset: T.native(),
|
|
86
|
+
amount: u
|
|
87
|
+
}), l = new P(c, {
|
|
88
|
+
fee: X,
|
|
89
|
+
networkPassphrase: m.PUBLIC,
|
|
90
|
+
memo: B(t.memo)
|
|
91
|
+
}).addOperation(f).setTimeout(30).build();
|
|
92
|
+
let r;
|
|
93
|
+
try {
|
|
94
|
+
const e = await n.signTransaction(l.toXDR(), {
|
|
95
|
+
networkPassphrase: m.PUBLIC,
|
|
96
|
+
address: n.publicKey
|
|
97
|
+
});
|
|
98
|
+
r = typeof e == "string" ? e : e.signedTxXdr;
|
|
99
|
+
} catch (e) {
|
|
100
|
+
const y = e instanceof Error ? e.message : String(e ?? ""), L = e && typeof e == "object" && "code" in e ? String(e.code) : "", h = `${y} ${L}`.toLowerCase();
|
|
101
|
+
if (h.includes("unsupported") || h.includes("arity") || h.includes("number of arguments") || h.includes("arguments")) {
|
|
102
|
+
const w = await n.signTransaction(l.toXDR());
|
|
103
|
+
r = typeof w == "string" ? w : w.signedTxXdr;
|
|
104
|
+
} else
|
|
105
|
+
throw e;
|
|
106
|
+
}
|
|
107
|
+
if (!r)
|
|
108
|
+
throw new Error("Transaction signing failed.");
|
|
109
|
+
const g = P.fromXDR(
|
|
110
|
+
r,
|
|
111
|
+
m.PUBLIC
|
|
112
|
+
), s = await a.sendTransaction(g);
|
|
113
|
+
if (s.status === "ERROR" || s.status === "TRY_AGAIN_LATER")
|
|
114
|
+
throw new Error(
|
|
115
|
+
`Stellar transaction failed to submit with status ${s.status}. Hash: ${s.hash}`
|
|
116
|
+
);
|
|
117
|
+
return {
|
|
118
|
+
hash: s.hash,
|
|
119
|
+
transactionLink: `${b}${s.hash}`
|
|
120
|
+
};
|
|
121
|
+
}, O = {
|
|
122
|
+
makeTransfer: U,
|
|
123
|
+
decodePublicKey: (t) => {
|
|
124
|
+
if (!t.publicKey)
|
|
125
|
+
throw new Error("No public key found in Stellar provider.");
|
|
126
|
+
return K.decodeEd25519PublicKey(t.publicKey);
|
|
127
|
+
},
|
|
128
|
+
getNativeBalances: (t) => t.publicKey ? D(t.publicKey) : Promise.resolve({ xlmStroops: "0", usdcStroops: "0" })
|
|
129
|
+
};
|
|
130
|
+
export {
|
|
131
|
+
U as makeTransfer,
|
|
132
|
+
O as stellar
|
|
133
|
+
};
|
|
134
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/constants.ts","../src/fetchNativeBalances.ts","../src/makeTransfer.ts","../src/plugin.ts"],"sourcesContent":["import { Asset } from '@stellar/stellar-sdk';\n\nexport const RPC_ENDPOINTS = [\n 'https://sorobanrpc.stellar.org',\n 'https://rpc.ankr.com/stellar_soroban',\n 'https://stellar-soroban-public.nodies.app',\n];\n\nexport const USDC_ASSET = new Asset(\n 'USDC',\n 'GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN',\n);\n","import { StrKey, xdr } from '@stellar/stellar-sdk';\nimport axios from 'axios';\n\nimport { RPC_ENDPOINTS, USDC_ASSET } from './constants';\n\nexport const fetchNativeBalances = async (publicKey: string) => {\n const accountPubKey = xdr.PublicKey.publicKeyTypeEd25519(\n StrKey.decodeEd25519PublicKey(publicKey),\n );\n\n const accountKeyXdr = xdr.LedgerKey.account(\n new xdr.LedgerKeyAccount({ accountId: accountPubKey }),\n ).toXDR('base64');\n\n const trustlineKeyXdr = xdr.LedgerKey.trustline(\n new xdr.LedgerKeyTrustLine({\n accountId: accountPubKey,\n asset: USDC_ASSET.toTrustLineXDRObject(),\n }),\n ).toXDR('base64');\n\n const requestPayload = {\n id: 1,\n jsonrpc: '2.0',\n method: 'getLedgerEntries',\n params: { keys: [accountKeyXdr, trustlineKeyXdr] },\n };\n\n // eslint-disable-next-line no-restricted-syntax\n for (const baseURL of RPC_ENDPOINTS) {\n try {\n // eslint-disable-next-line no-await-in-loop\n const response = await axios.post<{\n result: { entries: { xdr: string }[] };\n }>(baseURL, requestPayload, {\n headers: { 'Content-Type': 'application/json' },\n timeout: 3000,\n });\n\n const entries = response.data?.result?.entries;\n\n if (!entries || entries.length === 0) {\n // eslint-disable-next-line no-continue\n continue;\n }\n\n let xlmStroops = '0';\n let usdcStroops = '0';\n\n entries.forEach((entry) => {\n if (!entry.xdr) {\n return;\n }\n\n const entryData = xdr.LedgerEntryData.fromXDR(entry.xdr, 'base64');\n\n if (entryData.switch().name === 'account') {\n xlmStroops = entryData.account().balance().toString();\n }\n\n if (entryData.switch().name === 'trustline') {\n usdcStroops = entryData.trustLine().balance().toString();\n }\n });\n\n return { xlmStroops, usdcStroops };\n } catch {\n // eslint-disable-next-line no-continue\n continue;\n }\n }\n\n return { xlmStroops: '0', usdcStroops: '0' };\n};\n","import {\n Asset,\n BASE_FEE,\n Memo,\n Networks,\n Operation,\n rpc,\n StrKey,\n Transaction,\n TransactionBuilder,\n} from '@stellar/stellar-sdk';\nimport type {\n MakeTransferArgs,\n TransferResult,\n} from '@aurora-is-near/intents-swap-widget';\n\nimport { RPC_ENDPOINTS, USDC_ASSET } from './constants';\nimport type { MakeTransferOptions } from './types';\n\nconst DEFAULT_EXPLORER_BASE_URL = 'https://stellar.expert/explorer/public/tx/';\n\nconst createMemo = (memoString: string): Memo => {\n if (!memoString) {\n return Memo.none();\n }\n\n // 1. If it's a numeric ID\n if (/^\\d+$/.test(memoString)) {\n return Memo.id(memoString);\n }\n\n // 2. If it's a standard text memo (28 chars or less)\n if (Buffer.from(memoString).length <= 28) {\n return Memo.text(memoString);\n }\n\n // 3. If the memo is a lowercase Stellar public key (56 chars starting with g)\n // We must convert it back to uppercase to decode it, then use the 32-byte raw public key as a MemoHash\n if (/^g[0-7a-z]{55}$/.test(memoString)) {\n const rawPublicKeyBytes = StrKey.decodeEd25519PublicKey(\n memoString.toUpperCase(),\n );\n\n return Memo.hash(rawPublicKeyBytes);\n }\n\n // 4. If the memo is a 64-character hex string\n if (/^[0-9a-fA-F]{64}$/.test(memoString)) {\n return Memo.hash(memoString);\n }\n\n throw new Error(`Unsupported Stellar memo format: ${memoString}`);\n};\n\nexport const makeTransfer = async (\n args: MakeTransferArgs & { memo?: string },\n {\n provider,\n explorerBaseUrl = DEFAULT_EXPLORER_BASE_URL,\n }: MakeTransferOptions,\n): Promise<TransferResult> => {\n if (!provider.publicKey) {\n throw new Error('No public key found in Stellar provider.');\n }\n\n if (!args.memo) {\n throw new Error('No memo provided.');\n }\n\n // 1. Init RPC Server with failover logic\n let rpcServer: rpc.Server | null = null;\n let sourceAccount = null;\n\n // eslint-disable-next-line no-restricted-syntax\n for (const url of RPC_ENDPOINTS) {\n try {\n const tempServer = new rpc.Server(url);\n\n // eslint-disable-next-line no-await-in-loop\n sourceAccount = await tempServer.getAccount(provider.publicKey);\n rpcServer = tempServer;\n break;\n } catch {\n // just continue on error\n }\n }\n\n if (!rpcServer || !sourceAccount) {\n throw new Error('Could not connect to Stellar RPC to load account data.');\n }\n\n const rawAmount = BigInt(args.amount);\n const whole = rawAmount / 10_000_000n;\n const fraction = (rawAmount % 10_000_000n).toString().padStart(7, '0');\n const txAmount = `${whole}.${fraction}`.replace(/\\.?0+$/, '');\n\n // 2. Build the payment operation\n const paymentOp =\n args.tokenAddress === USDC_ASSET.issuer\n ? Operation.payment({\n destination: args.address,\n asset: USDC_ASSET,\n amount: txAmount,\n })\n : Operation.payment({\n destination: args.address,\n asset: Asset.native(),\n amount: txAmount,\n });\n\n // 3. Build Transaction\n const transaction = new TransactionBuilder(sourceAccount, {\n fee: BASE_FEE,\n networkPassphrase: Networks.PUBLIC,\n memo: createMemo(args.memo),\n })\n .addOperation(paymentOp)\n .setTimeout(30)\n .build();\n\n // 4. Request Signature from Wallet\n let signedTxXdr: string;\n\n try {\n // Try the standard Wallets Kit signature (2 arguments)\n const result = await provider.signTransaction(transaction.toXDR(), {\n networkPassphrase: Networks.PUBLIC,\n address: provider.publicKey,\n });\n\n signedTxXdr = typeof result === 'string' ? result : result.signedTxXdr;\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err ?? '');\n const code =\n err && typeof err === 'object' && 'code' in err\n ? String((err as { code: unknown }).code)\n : '';\n\n const combined = `${msg} ${code}`.toLowerCase();\n\n const isUnsupportedArity =\n combined.includes('unsupported') ||\n combined.includes('arity') ||\n combined.includes('number of arguments') ||\n combined.includes('arguments');\n\n if (isUnsupportedArity) {\n // Fallback: provider strictly expects 1 argument (e.g. Freighter direct API)\n const result = await provider.signTransaction(transaction.toXDR());\n\n signedTxXdr = typeof result === 'string' ? result : result.signedTxXdr;\n } else {\n throw err;\n }\n }\n\n if (!signedTxXdr) {\n throw new Error('Transaction signing failed.');\n }\n\n // 5. Reconstruct signed transaction from XDR\n const signedTx = TransactionBuilder.fromXDR(\n signedTxXdr,\n Networks.PUBLIC,\n ) as Transaction;\n\n // 6. Submit Transaction to RPC\n const submitResult = await rpcServer.sendTransaction(signedTx);\n\n if (\n submitResult.status === 'ERROR' ||\n submitResult.status === 'TRY_AGAIN_LATER'\n ) {\n throw new Error(\n `Stellar transaction failed to submit with status ${submitResult.status}. Hash: ${submitResult.hash}`,\n );\n }\n\n return {\n hash: submitResult.hash,\n transactionLink: `${explorerBaseUrl}${submitResult.hash}`,\n };\n};\n","import { StrKey } from '@stellar/stellar-sdk';\nimport type { StellarNetworkPlugin } from '@aurora-is-near/intents-swap-widget';\n\nimport { fetchNativeBalances } from './fetchNativeBalances';\nimport { makeTransfer } from './makeTransfer';\n\nexport const stellar: StellarNetworkPlugin = {\n makeTransfer,\n decodePublicKey: (provider) => {\n if (!provider.publicKey) {\n throw new Error('No public key found in Stellar provider.');\n }\n\n return StrKey.decodeEd25519PublicKey(provider.publicKey);\n },\n getNativeBalances: (provider) => {\n if (!provider.publicKey) {\n return Promise.resolve({ xlmStroops: '0', usdcStroops: '0' });\n }\n\n return fetchNativeBalances(provider.publicKey);\n },\n};\n"],"names":["RPC_ENDPOINTS","USDC_ASSET","Asset","fetchNativeBalances","publicKey","accountPubKey","xdr","StrKey","accountKeyXdr","trustlineKeyXdr","requestPayload","baseURL","entries","axios","xlmStroops","usdcStroops","entry","entryData","DEFAULT_EXPLORER_BASE_URL","createMemo","memoString","Memo","rawPublicKeyBytes","makeTransfer","args","provider","explorerBaseUrl","rpcServer","sourceAccount","url","tempServer","rpc","rawAmount","whole","fraction","txAmount","paymentOp","Operation","transaction","TransactionBuilder","BASE_FEE","Networks","signedTxXdr","result","err","msg","code","combined","signedTx","submitResult","stellar"],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { MakeTransferArgs, TransferResult } from '@aurora-is-near/intents-swap-widget';
|
|
2
|
+
import { MakeTransferOptions } from './types';
|
|
3
|
+
export declare const makeTransfer: (args: MakeTransferArgs & {
|
|
4
|
+
memo?: string;
|
|
5
|
+
}, { provider, explorerBaseUrl, }: MakeTransferOptions) => Promise<TransferResult>;
|
package/dist/plugin.d.ts
ADDED
package/dist/types.d.ts
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@aurora-is-near/intents-swap-widget-stellar",
|
|
3
|
+
"version": "7.1.0",
|
|
4
|
+
"description": "Stellar connector for the Intents swap widget",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"module": "./dist/index.js",
|
|
9
|
+
"type": "module",
|
|
10
|
+
"scripts": {
|
|
11
|
+
"typecheck": "tsc --noEmit",
|
|
12
|
+
"lint": "eslint . --ext .js,.ts,.tsx",
|
|
13
|
+
"clean": "rimraf dist",
|
|
14
|
+
"prebuild": "yarn clean",
|
|
15
|
+
"build": "vite build"
|
|
16
|
+
},
|
|
17
|
+
"publishConfig": {
|
|
18
|
+
"access": "public",
|
|
19
|
+
"registry": "https://registry.npmjs.org/"
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"src",
|
|
23
|
+
"dist"
|
|
24
|
+
],
|
|
25
|
+
"exports": {
|
|
26
|
+
".": "./dist/index.js"
|
|
27
|
+
},
|
|
28
|
+
"peerDependencies": {
|
|
29
|
+
"@aurora-is-near/intents-swap-widget": "^7.1.0"
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"@aurora-is-near/intents-swap-widget": "^7.1.0"
|
|
33
|
+
},
|
|
34
|
+
"dependencies": {
|
|
35
|
+
"@stellar/stellar-sdk": "^14.6.1",
|
|
36
|
+
"axios": "^1.10.0"
|
|
37
|
+
}
|
|
38
|
+
}
|
package/src/constants.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Asset } from '@stellar/stellar-sdk';
|
|
2
|
+
|
|
3
|
+
export const RPC_ENDPOINTS = [
|
|
4
|
+
'https://sorobanrpc.stellar.org',
|
|
5
|
+
'https://rpc.ankr.com/stellar_soroban',
|
|
6
|
+
'https://stellar-soroban-public.nodies.app',
|
|
7
|
+
];
|
|
8
|
+
|
|
9
|
+
export const USDC_ASSET = new Asset(
|
|
10
|
+
'USDC',
|
|
11
|
+
'GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN',
|
|
12
|
+
);
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { StrKey, xdr } from '@stellar/stellar-sdk';
|
|
2
|
+
import axios from 'axios';
|
|
3
|
+
|
|
4
|
+
import { RPC_ENDPOINTS, USDC_ASSET } from './constants';
|
|
5
|
+
|
|
6
|
+
export const fetchNativeBalances = async (publicKey: string) => {
|
|
7
|
+
const accountPubKey = xdr.PublicKey.publicKeyTypeEd25519(
|
|
8
|
+
StrKey.decodeEd25519PublicKey(publicKey),
|
|
9
|
+
);
|
|
10
|
+
|
|
11
|
+
const accountKeyXdr = xdr.LedgerKey.account(
|
|
12
|
+
new xdr.LedgerKeyAccount({ accountId: accountPubKey }),
|
|
13
|
+
).toXDR('base64');
|
|
14
|
+
|
|
15
|
+
const trustlineKeyXdr = xdr.LedgerKey.trustline(
|
|
16
|
+
new xdr.LedgerKeyTrustLine({
|
|
17
|
+
accountId: accountPubKey,
|
|
18
|
+
asset: USDC_ASSET.toTrustLineXDRObject(),
|
|
19
|
+
}),
|
|
20
|
+
).toXDR('base64');
|
|
21
|
+
|
|
22
|
+
const requestPayload = {
|
|
23
|
+
id: 1,
|
|
24
|
+
jsonrpc: '2.0',
|
|
25
|
+
method: 'getLedgerEntries',
|
|
26
|
+
params: { keys: [accountKeyXdr, trustlineKeyXdr] },
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
// eslint-disable-next-line no-restricted-syntax
|
|
30
|
+
for (const baseURL of RPC_ENDPOINTS) {
|
|
31
|
+
try {
|
|
32
|
+
// eslint-disable-next-line no-await-in-loop
|
|
33
|
+
const response = await axios.post<{
|
|
34
|
+
result: { entries: { xdr: string }[] };
|
|
35
|
+
}>(baseURL, requestPayload, {
|
|
36
|
+
headers: { 'Content-Type': 'application/json' },
|
|
37
|
+
timeout: 3000,
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
const entries = response.data?.result?.entries;
|
|
41
|
+
|
|
42
|
+
if (!entries || entries.length === 0) {
|
|
43
|
+
// eslint-disable-next-line no-continue
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
let xlmStroops = '0';
|
|
48
|
+
let usdcStroops = '0';
|
|
49
|
+
|
|
50
|
+
entries.forEach((entry) => {
|
|
51
|
+
if (!entry.xdr) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const entryData = xdr.LedgerEntryData.fromXDR(entry.xdr, 'base64');
|
|
56
|
+
|
|
57
|
+
if (entryData.switch().name === 'account') {
|
|
58
|
+
xlmStroops = entryData.account().balance().toString();
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (entryData.switch().name === 'trustline') {
|
|
62
|
+
usdcStroops = entryData.trustLine().balance().toString();
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
return { xlmStroops, usdcStroops };
|
|
67
|
+
} catch {
|
|
68
|
+
// eslint-disable-next-line no-continue
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return { xlmStroops: '0', usdcStroops: '0' };
|
|
74
|
+
};
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Asset,
|
|
3
|
+
BASE_FEE,
|
|
4
|
+
Memo,
|
|
5
|
+
Networks,
|
|
6
|
+
Operation,
|
|
7
|
+
rpc,
|
|
8
|
+
StrKey,
|
|
9
|
+
Transaction,
|
|
10
|
+
TransactionBuilder,
|
|
11
|
+
} from '@stellar/stellar-sdk';
|
|
12
|
+
import type {
|
|
13
|
+
MakeTransferArgs,
|
|
14
|
+
TransferResult,
|
|
15
|
+
} from '@aurora-is-near/intents-swap-widget';
|
|
16
|
+
|
|
17
|
+
import { RPC_ENDPOINTS, USDC_ASSET } from './constants';
|
|
18
|
+
import type { MakeTransferOptions } from './types';
|
|
19
|
+
|
|
20
|
+
const DEFAULT_EXPLORER_BASE_URL = 'https://stellar.expert/explorer/public/tx/';
|
|
21
|
+
|
|
22
|
+
const createMemo = (memoString: string): Memo => {
|
|
23
|
+
if (!memoString) {
|
|
24
|
+
return Memo.none();
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// 1. If it's a numeric ID
|
|
28
|
+
if (/^\d+$/.test(memoString)) {
|
|
29
|
+
return Memo.id(memoString);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// 2. If it's a standard text memo (28 chars or less)
|
|
33
|
+
if (Buffer.from(memoString).length <= 28) {
|
|
34
|
+
return Memo.text(memoString);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// 3. If the memo is a lowercase Stellar public key (56 chars starting with g)
|
|
38
|
+
// We must convert it back to uppercase to decode it, then use the 32-byte raw public key as a MemoHash
|
|
39
|
+
if (/^g[0-7a-z]{55}$/.test(memoString)) {
|
|
40
|
+
const rawPublicKeyBytes = StrKey.decodeEd25519PublicKey(
|
|
41
|
+
memoString.toUpperCase(),
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
return Memo.hash(rawPublicKeyBytes);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// 4. If the memo is a 64-character hex string
|
|
48
|
+
if (/^[0-9a-fA-F]{64}$/.test(memoString)) {
|
|
49
|
+
return Memo.hash(memoString);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
throw new Error(`Unsupported Stellar memo format: ${memoString}`);
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
export const makeTransfer = async (
|
|
56
|
+
args: MakeTransferArgs & { memo?: string },
|
|
57
|
+
{
|
|
58
|
+
provider,
|
|
59
|
+
explorerBaseUrl = DEFAULT_EXPLORER_BASE_URL,
|
|
60
|
+
}: MakeTransferOptions,
|
|
61
|
+
): Promise<TransferResult> => {
|
|
62
|
+
if (!provider.publicKey) {
|
|
63
|
+
throw new Error('No public key found in Stellar provider.');
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (!args.memo) {
|
|
67
|
+
throw new Error('No memo provided.');
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// 1. Init RPC Server with failover logic
|
|
71
|
+
let rpcServer: rpc.Server | null = null;
|
|
72
|
+
let sourceAccount = null;
|
|
73
|
+
|
|
74
|
+
// eslint-disable-next-line no-restricted-syntax
|
|
75
|
+
for (const url of RPC_ENDPOINTS) {
|
|
76
|
+
try {
|
|
77
|
+
const tempServer = new rpc.Server(url);
|
|
78
|
+
|
|
79
|
+
// eslint-disable-next-line no-await-in-loop
|
|
80
|
+
sourceAccount = await tempServer.getAccount(provider.publicKey);
|
|
81
|
+
rpcServer = tempServer;
|
|
82
|
+
break;
|
|
83
|
+
} catch {
|
|
84
|
+
// just continue on error
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (!rpcServer || !sourceAccount) {
|
|
89
|
+
throw new Error('Could not connect to Stellar RPC to load account data.');
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const rawAmount = BigInt(args.amount);
|
|
93
|
+
const whole = rawAmount / 10_000_000n;
|
|
94
|
+
const fraction = (rawAmount % 10_000_000n).toString().padStart(7, '0');
|
|
95
|
+
const txAmount = `${whole}.${fraction}`.replace(/\.?0+$/, '');
|
|
96
|
+
|
|
97
|
+
// 2. Build the payment operation
|
|
98
|
+
const paymentOp =
|
|
99
|
+
args.tokenAddress === USDC_ASSET.issuer
|
|
100
|
+
? Operation.payment({
|
|
101
|
+
destination: args.address,
|
|
102
|
+
asset: USDC_ASSET,
|
|
103
|
+
amount: txAmount,
|
|
104
|
+
})
|
|
105
|
+
: Operation.payment({
|
|
106
|
+
destination: args.address,
|
|
107
|
+
asset: Asset.native(),
|
|
108
|
+
amount: txAmount,
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
// 3. Build Transaction
|
|
112
|
+
const transaction = new TransactionBuilder(sourceAccount, {
|
|
113
|
+
fee: BASE_FEE,
|
|
114
|
+
networkPassphrase: Networks.PUBLIC,
|
|
115
|
+
memo: createMemo(args.memo),
|
|
116
|
+
})
|
|
117
|
+
.addOperation(paymentOp)
|
|
118
|
+
.setTimeout(30)
|
|
119
|
+
.build();
|
|
120
|
+
|
|
121
|
+
// 4. Request Signature from Wallet
|
|
122
|
+
let signedTxXdr: string;
|
|
123
|
+
|
|
124
|
+
try {
|
|
125
|
+
// Try the standard Wallets Kit signature (2 arguments)
|
|
126
|
+
const result = await provider.signTransaction(transaction.toXDR(), {
|
|
127
|
+
networkPassphrase: Networks.PUBLIC,
|
|
128
|
+
address: provider.publicKey,
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
signedTxXdr = typeof result === 'string' ? result : result.signedTxXdr;
|
|
132
|
+
} catch (err) {
|
|
133
|
+
const msg = err instanceof Error ? err.message : String(err ?? '');
|
|
134
|
+
const code =
|
|
135
|
+
err && typeof err === 'object' && 'code' in err
|
|
136
|
+
? String((err as { code: unknown }).code)
|
|
137
|
+
: '';
|
|
138
|
+
|
|
139
|
+
const combined = `${msg} ${code}`.toLowerCase();
|
|
140
|
+
|
|
141
|
+
const isUnsupportedArity =
|
|
142
|
+
combined.includes('unsupported') ||
|
|
143
|
+
combined.includes('arity') ||
|
|
144
|
+
combined.includes('number of arguments') ||
|
|
145
|
+
combined.includes('arguments');
|
|
146
|
+
|
|
147
|
+
if (isUnsupportedArity) {
|
|
148
|
+
// Fallback: provider strictly expects 1 argument (e.g. Freighter direct API)
|
|
149
|
+
const result = await provider.signTransaction(transaction.toXDR());
|
|
150
|
+
|
|
151
|
+
signedTxXdr = typeof result === 'string' ? result : result.signedTxXdr;
|
|
152
|
+
} else {
|
|
153
|
+
throw err;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if (!signedTxXdr) {
|
|
158
|
+
throw new Error('Transaction signing failed.');
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// 5. Reconstruct signed transaction from XDR
|
|
162
|
+
const signedTx = TransactionBuilder.fromXDR(
|
|
163
|
+
signedTxXdr,
|
|
164
|
+
Networks.PUBLIC,
|
|
165
|
+
) as Transaction;
|
|
166
|
+
|
|
167
|
+
// 6. Submit Transaction to RPC
|
|
168
|
+
const submitResult = await rpcServer.sendTransaction(signedTx);
|
|
169
|
+
|
|
170
|
+
if (
|
|
171
|
+
submitResult.status === 'ERROR' ||
|
|
172
|
+
submitResult.status === 'TRY_AGAIN_LATER'
|
|
173
|
+
) {
|
|
174
|
+
throw new Error(
|
|
175
|
+
`Stellar transaction failed to submit with status ${submitResult.status}. Hash: ${submitResult.hash}`,
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
return {
|
|
180
|
+
hash: submitResult.hash,
|
|
181
|
+
transactionLink: `${explorerBaseUrl}${submitResult.hash}`,
|
|
182
|
+
};
|
|
183
|
+
};
|
package/src/plugin.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { StrKey } from '@stellar/stellar-sdk';
|
|
2
|
+
import type { StellarNetworkPlugin } from '@aurora-is-near/intents-swap-widget';
|
|
3
|
+
|
|
4
|
+
import { fetchNativeBalances } from './fetchNativeBalances';
|
|
5
|
+
import { makeTransfer } from './makeTransfer';
|
|
6
|
+
|
|
7
|
+
export const stellar: StellarNetworkPlugin = {
|
|
8
|
+
makeTransfer,
|
|
9
|
+
decodePublicKey: (provider) => {
|
|
10
|
+
if (!provider.publicKey) {
|
|
11
|
+
throw new Error('No public key found in Stellar provider.');
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
return StrKey.decodeEd25519PublicKey(provider.publicKey);
|
|
15
|
+
},
|
|
16
|
+
getNativeBalances: (provider) => {
|
|
17
|
+
if (!provider.publicKey) {
|
|
18
|
+
return Promise.resolve({ xlmStroops: '0', usdcStroops: '0' });
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return fetchNativeBalances(provider.publicKey);
|
|
22
|
+
},
|
|
23
|
+
};
|