@swapkit/toolboxes 4.2.1 → 4.3.3
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/src/cardano/index.cjs +2 -2
- package/dist/src/cardano/index.cjs.map +3 -3
- package/dist/src/cardano/index.js +2 -2
- package/dist/src/cardano/index.js.map +3 -3
- package/dist/src/evm/index.cjs +2 -2
- package/dist/src/evm/index.cjs.map +8 -8
- package/dist/src/evm/index.js +2 -2
- package/dist/src/evm/index.js.map +8 -8
- package/dist/src/index.cjs +3 -3
- package/dist/src/index.cjs.map +15 -15
- package/dist/src/index.js +3 -3
- package/dist/src/index.js.map +15 -15
- package/dist/src/substrate/index.cjs +2 -2
- package/dist/src/substrate/index.cjs.map +3 -3
- package/dist/src/substrate/index.js +2 -2
- package/dist/src/substrate/index.js.map +3 -3
- package/dist/src/tron/index.cjs +2 -2
- package/dist/src/tron/index.cjs.map +3 -3
- package/dist/src/tron/index.js +2 -2
- package/dist/src/tron/index.js.map +3 -3
- package/dist/src/utxo/index.cjs +3 -3
- package/dist/src/utxo/index.cjs.map +6 -6
- package/dist/src/utxo/index.js +3 -3
- package/dist/src/utxo/index.js.map +6 -6
- package/dist/types/cardano/toolbox.d.ts +1 -1
- package/dist/types/cardano/toolbox.d.ts.map +1 -1
- package/dist/types/evm/api.d.ts +1 -1
- package/dist/types/evm/api.d.ts.map +1 -1
- package/dist/types/evm/helpers.d.ts.map +1 -1
- package/dist/types/evm/toolbox/baseEVMToolbox.d.ts +1 -1
- package/dist/types/evm/toolbox/baseEVMToolbox.d.ts.map +1 -1
- package/dist/types/evm/toolbox/evm.d.ts +97 -17
- package/dist/types/evm/toolbox/evm.d.ts.map +1 -1
- package/dist/types/evm/toolbox/index.d.ts.map +1 -1
- package/dist/types/evm/toolbox/op.d.ts +1 -1
- package/dist/types/evm/toolbox/op.d.ts.map +1 -1
- package/dist/types/evm/types.d.ts +4 -2
- package/dist/types/evm/types.d.ts.map +1 -1
- package/dist/types/substrate/balance.d.ts.map +1 -1
- package/dist/types/tron/toolbox.d.ts.map +1 -1
- package/dist/types/utxo/helpers/api.d.ts +2 -34
- package/dist/types/utxo/helpers/api.d.ts.map +1 -1
- package/dist/types/utxo/toolbox/bitcoinCash.d.ts +1 -1
- package/dist/types/utxo/toolbox/bitcoinCash.d.ts.map +1 -1
- package/dist/types/utxo/toolbox/index.d.ts +3 -27
- package/dist/types/utxo/toolbox/index.d.ts.map +1 -1
- package/dist/types/utxo/toolbox/params.d.ts +32 -0
- package/dist/types/utxo/toolbox/params.d.ts.map +1 -0
- package/dist/types/utxo/toolbox/utxo.d.ts +1 -1
- package/dist/types/utxo/toolbox/utxo.d.ts.map +1 -1
- package/dist/types/utxo/toolbox/zcash.d.ts.map +1 -1
- package/package.json +86 -58
- package/src/__tests__/address-validation-all-chains.test.ts +162 -0
- package/src/__tests__/addressValidator.test.ts +162 -0
- package/src/cardano/__tests__/toolbox.test.ts +48 -0
- package/src/cardano/index.ts +2 -0
- package/src/cardano/toolbox.ts +168 -0
- package/src/cardano/types.ts +10 -0
- package/src/cosmos/__tests__/toolbox.test.ts +91 -0
- package/src/cosmos/index.ts +4 -0
- package/src/cosmos/thorchainUtils/addressFormat.ts +22 -0
- package/src/cosmos/thorchainUtils/index.ts +4 -0
- package/src/cosmos/thorchainUtils/messages.ts +212 -0
- package/src/cosmos/thorchainUtils/registry.ts +43 -0
- package/src/cosmos/thorchainUtils/types/MsgCompiled.ts +2800 -0
- package/src/cosmos/thorchainUtils/types/client-types.ts +54 -0
- package/src/cosmos/thorchainUtils/types/index.ts +1 -0
- package/src/cosmos/toolbox/cosmos.ts +345 -0
- package/src/cosmos/toolbox/index.ts +35 -0
- package/src/cosmos/toolbox/thorchain.ts +249 -0
- package/src/cosmos/types.ts +48 -0
- package/src/cosmos/util.ts +214 -0
- package/src/evm/__tests__/address-validation.test.ts +84 -0
- package/src/evm/__tests__/ethereum.test.ts +137 -0
- package/src/evm/__tests__/signMessage.test.ts +60 -0
- package/src/evm/api.ts +10 -0
- package/src/evm/contracts/eth/multicall.ts +165 -0
- package/src/evm/contracts/op/gasOracle.ts +145 -0
- package/src/evm/helpers.ts +73 -0
- package/src/evm/index.ts +4 -0
- package/src/evm/toolbox/baseEVMToolbox.ts +695 -0
- package/src/evm/toolbox/evm.ts +67 -0
- package/src/evm/toolbox/index.ts +44 -0
- package/src/evm/toolbox/op.ts +163 -0
- package/src/evm/types.ts +146 -0
- package/src/index.ts +260 -0
- package/src/near/__tests__/core.test.ts +70 -0
- package/src/near/helpers/core.ts +85 -0
- package/src/near/helpers/gasEstimation.ts +96 -0
- package/src/near/helpers/nep141.ts +50 -0
- package/src/near/index.ts +21 -0
- package/src/near/toolbox.ts +421 -0
- package/src/near/types/contract.ts +32 -0
- package/src/near/types/nep141.ts +34 -0
- package/src/near/types/toolbox.ts +55 -0
- package/src/near/types.ts +44 -0
- package/src/radix/index.ts +132 -0
- package/src/ripple/index.ts +179 -0
- package/src/solana/index.ts +36 -0
- package/src/solana/toolbox.ts +415 -0
- package/src/substrate/balance.ts +88 -0
- package/src/substrate/index.ts +2 -0
- package/src/substrate/substrate.ts +281 -0
- package/src/substrate/types.ts +115 -0
- package/src/sui/__tests__/toolbox.test.ts +82 -0
- package/src/sui/index.ts +2 -0
- package/src/sui/toolbox.ts +165 -0
- package/src/sui/types.ts +11 -0
- package/src/ton/__tests__/toolbox.test.ts +63 -0
- package/src/ton/index.ts +2 -0
- package/src/ton/toolbox.ts +136 -0
- package/src/ton/types.ts +13 -0
- package/src/tron/__tests__/toolbox.test.ts +221 -0
- package/src/tron/helpers/trc20.abi.ts +107 -0
- package/src/tron/helpers/trongrid.ts +53 -0
- package/src/tron/index.ts +21 -0
- package/src/tron/toolbox.ts +585 -0
- package/src/tron/types.ts +83 -0
- package/src/types.ts +28 -0
- package/src/utils.ts +27 -0
- package/src/utxo/__tests__/zcash-integration.test.ts +97 -0
- package/src/utxo/helpers/api.ts +471 -0
- package/src/utxo/helpers/bchaddrjs.ts +166 -0
- package/src/utxo/helpers/coinselect.ts +92 -0
- package/src/utxo/helpers/index.ts +4 -0
- package/src/utxo/helpers/txSize.ts +137 -0
- package/src/utxo/index.ts +6 -0
- package/src/utxo/toolbox/bitcoinCash.ts +243 -0
- package/src/utxo/toolbox/index.ts +59 -0
- package/src/utxo/toolbox/params.ts +18 -0
- package/src/utxo/toolbox/utxo.ts +439 -0
- package/src/utxo/toolbox/validators.ts +36 -0
- package/src/utxo/toolbox/zcash.ts +245 -0
- package/src/utxo/types.ts +39 -0
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import { AssetValue, Chain, type DerivationPathArray, getChainConfig, SwapKitError } from "@swapkit/helpers";
|
|
2
|
+
import { match, P } from "ts-pattern";
|
|
3
|
+
import type { CardanoProvider } from "./index";
|
|
4
|
+
|
|
5
|
+
type CardanoSigner = CardanoProvider | { address: string };
|
|
6
|
+
|
|
7
|
+
// TODO: this should done on BE side
|
|
8
|
+
async function getProvider() {
|
|
9
|
+
const { BlockfrostProvider } = await import("@meshsdk/core");
|
|
10
|
+
const apiKey = "mainnet3YT7XK6NidLPlkHxxyBB5V0WzXUOTIJS"; // TODO: TEST API KEY
|
|
11
|
+
return new BlockfrostProvider(apiKey);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const ADA_ID = "lovelace";
|
|
15
|
+
|
|
16
|
+
async function getCardanoBalance(address: string) {
|
|
17
|
+
try {
|
|
18
|
+
const { MeshWallet } = await import("@meshsdk/core");
|
|
19
|
+
const provider = await getProvider();
|
|
20
|
+
|
|
21
|
+
const wallet = new MeshWallet({ fetcher: provider, key: { address, type: "address" }, networkId: 1 });
|
|
22
|
+
|
|
23
|
+
await wallet.init();
|
|
24
|
+
const balance = await wallet.getBalance();
|
|
25
|
+
|
|
26
|
+
const balances: AssetValue[] = [];
|
|
27
|
+
|
|
28
|
+
for (const asset of balance) {
|
|
29
|
+
if (asset.unit === ADA_ID) {
|
|
30
|
+
const { baseDecimal } = getChainConfig(Chain.Cardano);
|
|
31
|
+
balances.push(AssetValue.from({ chain: Chain.Cardano, fromBaseDecimal: baseDecimal, value: asset.quantity }));
|
|
32
|
+
} else {
|
|
33
|
+
balances.push(AssetValue.from({ asset: `${Chain.Cardano}.${asset.unit}`, value: asset.quantity }));
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (balances.length === 0) {
|
|
38
|
+
return [AssetValue.from({ chain: Chain.Cardano })];
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return balances;
|
|
42
|
+
} catch (error) {
|
|
43
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
44
|
+
console.error(`Cardano balance fetch error: ${errorMessage}`);
|
|
45
|
+
return [AssetValue.from({ chain: Chain.Cardano })];
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export async function getCardanoAddressValidator() {
|
|
50
|
+
const { deserializeAddress } = await import("@meshsdk/core");
|
|
51
|
+
|
|
52
|
+
return (address: string) => {
|
|
53
|
+
try {
|
|
54
|
+
deserializeAddress(address);
|
|
55
|
+
return true;
|
|
56
|
+
} catch {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export async function getCardanoToolbox(
|
|
63
|
+
toolboxParams?:
|
|
64
|
+
| { signer?: CardanoSigner }
|
|
65
|
+
| { phrase?: string; index?: number; derivationPath?: DerivationPathArray },
|
|
66
|
+
) {
|
|
67
|
+
const validateAddress = await getCardanoAddressValidator();
|
|
68
|
+
const signer = await match(toolboxParams)
|
|
69
|
+
.with({ phrase: P.string }, async ({ phrase }) => {
|
|
70
|
+
const { MeshWallet } = await import("@meshsdk/core");
|
|
71
|
+
const provider = await getProvider();
|
|
72
|
+
|
|
73
|
+
const wallet = new MeshWallet({
|
|
74
|
+
fetcher: provider,
|
|
75
|
+
key: { type: "mnemonic", words: phrase.split(" ") },
|
|
76
|
+
networkId: 1,
|
|
77
|
+
submitter: provider,
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
await wallet.init();
|
|
81
|
+
return wallet;
|
|
82
|
+
})
|
|
83
|
+
.with({ signer: P.any }, ({ signer }) => signer)
|
|
84
|
+
.otherwise(() => undefined);
|
|
85
|
+
|
|
86
|
+
const signerAddress = signer && "getChangeAddress" in signer ? await signer.getChangeAddress() : "";
|
|
87
|
+
|
|
88
|
+
function getAddress() {
|
|
89
|
+
return signerAddress || "";
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function getBalance(addressParam?: string) {
|
|
93
|
+
const address = addressParam || getAddress();
|
|
94
|
+
if (!address) throw new SwapKitError("core_wallet_connection_not_found");
|
|
95
|
+
return getCardanoBalance(address);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function estimateTransactionFee() {
|
|
99
|
+
return Promise.resolve(AssetValue.from({ chain: Chain.Cardano, value: "0.01" }));
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
async function createTransaction({
|
|
103
|
+
recipient,
|
|
104
|
+
assetValue,
|
|
105
|
+
memo,
|
|
106
|
+
}: {
|
|
107
|
+
recipient: string;
|
|
108
|
+
assetValue: AssetValue;
|
|
109
|
+
memo?: string;
|
|
110
|
+
}) {
|
|
111
|
+
if (!signer || !("getChangeAddress" in signer)) {
|
|
112
|
+
throw new SwapKitError("core_wallet_connection_not_found");
|
|
113
|
+
}
|
|
114
|
+
const { Transaction } = await import("@meshsdk/core");
|
|
115
|
+
|
|
116
|
+
const [, policyId] = assetValue.symbol.split("-");
|
|
117
|
+
if (!assetValue.isGasAsset && !policyId) throw new SwapKitError("core_wallet_connection_not_found");
|
|
118
|
+
|
|
119
|
+
const tx = new Transaction({ initiator: signer });
|
|
120
|
+
tx.sendAssets({ address: recipient }, [
|
|
121
|
+
{ quantity: assetValue.getBaseValue("string"), unit: assetValue.isGasAsset ? "lovelace" : assetValue.symbol },
|
|
122
|
+
]);
|
|
123
|
+
|
|
124
|
+
if (memo) tx.setMetadata(0, memo);
|
|
125
|
+
|
|
126
|
+
const unsignedTx = await tx.build();
|
|
127
|
+
return { tx, unsignedTx };
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function signTransaction(txParams: string) {
|
|
131
|
+
if (!signer || !("getChangeAddress" in signer)) {
|
|
132
|
+
throw new SwapKitError("core_wallet_connection_not_found");
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return signer.signTx(txParams);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
async function transfer({
|
|
139
|
+
recipient,
|
|
140
|
+
assetValue,
|
|
141
|
+
memo,
|
|
142
|
+
}: {
|
|
143
|
+
recipient: string;
|
|
144
|
+
assetValue: AssetValue;
|
|
145
|
+
memo?: string;
|
|
146
|
+
}) {
|
|
147
|
+
if (!signer || !("getChangeAddress" in signer)) {
|
|
148
|
+
throw new SwapKitError("core_wallet_connection_not_found");
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const { unsignedTx } = await createTransaction({ assetValue, memo, recipient });
|
|
152
|
+
const signedTx = await signTransaction(unsignedTx);
|
|
153
|
+
const provider = await getProvider();
|
|
154
|
+
const txHash = await provider.submitTx(signedTx);
|
|
155
|
+
|
|
156
|
+
return txHash;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
return {
|
|
160
|
+
createTransaction,
|
|
161
|
+
estimateTransactionFee,
|
|
162
|
+
getAddress,
|
|
163
|
+
getBalance,
|
|
164
|
+
signTransaction,
|
|
165
|
+
transfer,
|
|
166
|
+
validateAddress,
|
|
167
|
+
};
|
|
168
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { getCardanoToolbox } from "./toolbox";
|
|
2
|
+
|
|
3
|
+
export type CardanoWallet = Awaited<ReturnType<typeof getCardanoToolbox>>;
|
|
4
|
+
|
|
5
|
+
export interface CardanoProvider {
|
|
6
|
+
connect: () => Promise<{ address: string }>;
|
|
7
|
+
disconnect: () => Promise<void>;
|
|
8
|
+
address: string | null;
|
|
9
|
+
signTransaction: (transaction: any) => Promise<any>;
|
|
10
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { beforeAll, describe, expect, test } from "bun:test";
|
|
2
|
+
import { AssetValue, Chain } from "@swapkit/helpers";
|
|
3
|
+
import { getCosmosToolbox } from "../toolbox";
|
|
4
|
+
|
|
5
|
+
const TEST_PHRASE = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about";
|
|
6
|
+
const KNOWN_COSMOS_ADDRESS = "cosmos1r5v5srda7xfth3hn2s26txvrcrntldjumt8mhl";
|
|
7
|
+
|
|
8
|
+
const context: { toolbox: Awaited<ReturnType<typeof getCosmosToolbox>> } = {} as any;
|
|
9
|
+
|
|
10
|
+
beforeAll(async () => {
|
|
11
|
+
context.toolbox = await getCosmosToolbox(Chain.Cosmos, { phrase: TEST_PHRASE });
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
describe("Cosmos Toolbox", () => {
|
|
15
|
+
test("should validate valid Cosmos addresses", () => {
|
|
16
|
+
const validAddresses = [
|
|
17
|
+
KNOWN_COSMOS_ADDRESS,
|
|
18
|
+
"cosmos12d7d2rlxp7urkp8z0p8sft2fm07ewyjrfvul3f",
|
|
19
|
+
"cosmos1xv9tklw7d82sezh9haa573wufgy59vmwe6xxe5",
|
|
20
|
+
];
|
|
21
|
+
|
|
22
|
+
for (const address of validAddresses) {
|
|
23
|
+
expect(context.toolbox.validateAddress(address)).toBe(true);
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
test("should reject invalid Cosmos addresses", () => {
|
|
28
|
+
const invalidAddresses = [
|
|
29
|
+
"",
|
|
30
|
+
"invalid",
|
|
31
|
+
"thor1xv9tklw7d82sezh9haa573wufgy59vmwzp5v3k",
|
|
32
|
+
"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
|
|
33
|
+
"1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa",
|
|
34
|
+
"cosmos1invalid",
|
|
35
|
+
];
|
|
36
|
+
|
|
37
|
+
for (const address of invalidAddresses) {
|
|
38
|
+
expect(context.toolbox.validateAddress(address)).toBe(false);
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
test("should generate valid Cosmos address from phrase", async () => {
|
|
43
|
+
const address = await context.toolbox.getAddress();
|
|
44
|
+
if (address) {
|
|
45
|
+
expect(address.startsWith("cosmos1")).toBe(true);
|
|
46
|
+
expect(context.toolbox.validateAddress(address)).toBe(true);
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
test("should use 6 decimals for ATOM", () => {
|
|
51
|
+
const atomValue = AssetValue.from({ chain: Chain.Cosmos, value: 3.2 });
|
|
52
|
+
|
|
53
|
+
expect(atomValue.decimal).toBe(6);
|
|
54
|
+
expect(atomValue.getBaseValue("string")).toBe("3200000");
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
test("should convert ATOM amounts correctly with 6 decimals", () => {
|
|
58
|
+
const testCases = [
|
|
59
|
+
{ amount: 0.1, expectedBase: "100000" },
|
|
60
|
+
{ amount: 1, expectedBase: "1000000" },
|
|
61
|
+
{ amount: 3.2, expectedBase: "3200000" },
|
|
62
|
+
{ amount: 10.5, expectedBase: "10500000" },
|
|
63
|
+
{ amount: 100, expectedBase: "100000000" },
|
|
64
|
+
{ amount: 0.000001, expectedBase: "1" },
|
|
65
|
+
];
|
|
66
|
+
|
|
67
|
+
for (const { amount, expectedBase } of testCases) {
|
|
68
|
+
const atomValue = AssetValue.from({ chain: Chain.Cosmos, value: amount });
|
|
69
|
+
expect(atomValue).toMatchObject({ decimal: 6 });
|
|
70
|
+
expect(atomValue.getBaseValue("string")).toBe(expectedBase);
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
test("should fetch balance for known address", async () => {
|
|
75
|
+
const balances = await context.toolbox.getBalance(KNOWN_COSMOS_ADDRESS);
|
|
76
|
+
expect(balances[0]).toMatchObject({ chain: Chain.Cosmos, decimal: 6, symbol: "ATOM" });
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
test("should not have 8 decimal bug (would be 100x too much)", () => {
|
|
80
|
+
const atomValue = AssetValue.from({ chain: Chain.Cosmos, value: 3.2 });
|
|
81
|
+
expect(Number.parseInt(atomValue.getBaseValue("string"), 10)).toBe(3200000);
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
test("should have minimum fee of 1000 uatom to meet network requirements", async () => {
|
|
85
|
+
const fees = await context.toolbox.getFees();
|
|
86
|
+
|
|
87
|
+
expect(fees.average.getBaseValue("number")).toBeGreaterThanOrEqual(1000);
|
|
88
|
+
expect(fees.fast.getBaseValue("number")).toBeGreaterThanOrEqual(1000);
|
|
89
|
+
expect(fees.fastest.getBaseValue("number")).toBeGreaterThanOrEqual(1000);
|
|
90
|
+
});
|
|
91
|
+
});
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { base64, bech32 } from "@scure/base";
|
|
2
|
+
import { SwapKitError } from "@swapkit/helpers";
|
|
3
|
+
import { fromByteArray, toByteArray } from "base64-js";
|
|
4
|
+
|
|
5
|
+
export function bech32ToBase64(address: string) {
|
|
6
|
+
return base64.encode(Uint8Array.from(bech32.fromWords(bech32.decode(address as `${string}1${string}`).words)));
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function base64ToBech32(address: string, prefix = "thor") {
|
|
10
|
+
return bech32.encode(prefix, bech32.toWords(base64.decode(address)));
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function toBase64(data: Uint8Array) {
|
|
14
|
+
return fromByteArray(data);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function fromBase64(base64String: string) {
|
|
18
|
+
if (!base64String.match(/^[a-zA-Z0-9+/]*={0,2}$/)) {
|
|
19
|
+
throw new SwapKitError("toolbox_cosmos_invalid_params", { error: "Invalid base64 string format" });
|
|
20
|
+
}
|
|
21
|
+
return toByteArray(base64String);
|
|
22
|
+
}
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import type { TxBodyEncodeObject } from "@cosmjs/proto-signing";
|
|
2
|
+
import { AssetValue, Chain, getChainConfig, SwapKitError, type TCLikeChain } from "@swapkit/helpers";
|
|
3
|
+
|
|
4
|
+
import { createStargateClient, getDefaultChainFee, getDenomWithChain, getMsgSendDenom } from "../util";
|
|
5
|
+
|
|
6
|
+
import { createDefaultAminoTypes, createDefaultRegistry } from "./registry";
|
|
7
|
+
import type { ThorchainCreateTransactionParams } from "./types";
|
|
8
|
+
|
|
9
|
+
type MsgSend = ReturnType<typeof transferMsgAmino>;
|
|
10
|
+
type MsgDeposit = ReturnType<typeof depositMsgAmino>;
|
|
11
|
+
type DirectMsgSendForBroadcast = ReturnType<typeof parseAminoMessageForDirectSigning<MsgSend>>;
|
|
12
|
+
type DirectMsgDepositForBroadcast = ReturnType<typeof parseAminoMessageForDirectSigning<MsgDeposit>>;
|
|
13
|
+
|
|
14
|
+
export const THORCHAIN_GAS_VALUE = getDefaultChainFee(Chain.THORChain).gas;
|
|
15
|
+
export const MAYA_GAS_VALUE = getDefaultChainFee(Chain.Maya).gas;
|
|
16
|
+
|
|
17
|
+
export const transferMsgAmino = ({
|
|
18
|
+
sender,
|
|
19
|
+
recipient,
|
|
20
|
+
assetValue,
|
|
21
|
+
}: {
|
|
22
|
+
sender: string;
|
|
23
|
+
recipient?: string;
|
|
24
|
+
assetValue: AssetValue;
|
|
25
|
+
}) => {
|
|
26
|
+
const chain = assetValue.chain as typeof Chain.THORChain | typeof Chain.Maya;
|
|
27
|
+
return {
|
|
28
|
+
type: `${chain === Chain.Maya ? "mayachain" : "thorchain"}/MsgSend` as const,
|
|
29
|
+
value: {
|
|
30
|
+
amount: [{ amount: assetValue.getBaseValue("string"), denom: getMsgSendDenom(assetValue.symbol, true) }],
|
|
31
|
+
from_address: sender,
|
|
32
|
+
to_address: recipient,
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export const depositMsgAmino = ({
|
|
38
|
+
sender,
|
|
39
|
+
assetValue,
|
|
40
|
+
memo = "",
|
|
41
|
+
}: {
|
|
42
|
+
sender: string;
|
|
43
|
+
assetValue: AssetValue;
|
|
44
|
+
memo?: string;
|
|
45
|
+
}) => {
|
|
46
|
+
const chain = assetValue.chain as TCLikeChain;
|
|
47
|
+
return {
|
|
48
|
+
type: `${chain === Chain.Maya ? "mayachain" : "thorchain"}/MsgDeposit` as const,
|
|
49
|
+
value: {
|
|
50
|
+
coins: [{ amount: assetValue.getBaseValue("string"), asset: getDenomWithChain(assetValue) }],
|
|
51
|
+
memo,
|
|
52
|
+
signer: sender,
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
export const buildAminoMsg = ({
|
|
58
|
+
sender,
|
|
59
|
+
recipient,
|
|
60
|
+
assetValue,
|
|
61
|
+
memo,
|
|
62
|
+
}: {
|
|
63
|
+
sender: string;
|
|
64
|
+
recipient?: string;
|
|
65
|
+
assetValue: AssetValue;
|
|
66
|
+
memo?: string;
|
|
67
|
+
}) => {
|
|
68
|
+
const isDeposit = !recipient;
|
|
69
|
+
const msg = isDeposit
|
|
70
|
+
? depositMsgAmino({ assetValue, memo, sender })
|
|
71
|
+
: transferMsgAmino({ assetValue, recipient, sender });
|
|
72
|
+
|
|
73
|
+
return msg;
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
export const convertToSignable = async (msg: MsgSend | MsgDeposit, chain: TCLikeChain) => {
|
|
77
|
+
const aminoTypes = await createDefaultAminoTypes(chain);
|
|
78
|
+
|
|
79
|
+
return aminoTypes.fromAmino(msg);
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
const getAccount = async ({ rpcUrl, sender }: { sender: string; rpcUrl: string }) => {
|
|
83
|
+
const client = await createStargateClient(rpcUrl);
|
|
84
|
+
const account = await client.getAccount(sender);
|
|
85
|
+
|
|
86
|
+
if (!account) {
|
|
87
|
+
throw new SwapKitError("toolbox_cosmos_account_not_found", { sender });
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return account;
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
export function getCreateTransaction(rpcUrl: string) {
|
|
94
|
+
return function createTransaction(params: ThorchainCreateTransactionParams) {
|
|
95
|
+
const { assetValue, recipient, memo, sender, asSignable, asAminoMessage } = params;
|
|
96
|
+
|
|
97
|
+
if (recipient) {
|
|
98
|
+
return buildTransferTx(rpcUrl)({ asAminoMessage, asSignable, assetValue, memo, recipient, sender });
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return buildDepositTx(rpcUrl)({ asAminoMessage, asSignable, assetValue, memo, sender });
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export const buildTransferTx =
|
|
106
|
+
(rpcUrl: string) =>
|
|
107
|
+
async ({
|
|
108
|
+
sender,
|
|
109
|
+
recipient,
|
|
110
|
+
assetValue,
|
|
111
|
+
memo = "",
|
|
112
|
+
asSignable = true,
|
|
113
|
+
asAminoMessage = false,
|
|
114
|
+
sequence,
|
|
115
|
+
accountNumber,
|
|
116
|
+
}: ThorchainCreateTransactionParams) => {
|
|
117
|
+
const account = await getAccount({ rpcUrl, sender });
|
|
118
|
+
const chain = assetValue.chain as TCLikeChain;
|
|
119
|
+
const { chainId } = getChainConfig(chain);
|
|
120
|
+
|
|
121
|
+
const transferMsg = transferMsgAmino({ assetValue, recipient, sender });
|
|
122
|
+
|
|
123
|
+
const msg = asSignable
|
|
124
|
+
? await convertToSignable(asAminoMessage ? transferMsg : parseAminoMessageForDirectSigning(transferMsg), chain)
|
|
125
|
+
: transferMsg;
|
|
126
|
+
|
|
127
|
+
const transaction = {
|
|
128
|
+
accountNumber: accountNumber || account.accountNumber,
|
|
129
|
+
chainId,
|
|
130
|
+
fee: getDefaultChainFee(chain),
|
|
131
|
+
memo,
|
|
132
|
+
msgs: [msg],
|
|
133
|
+
sequence: sequence || account.sequence,
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
return transaction;
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
export const buildDepositTx =
|
|
140
|
+
(rpcUrl: string) =>
|
|
141
|
+
async ({
|
|
142
|
+
sender,
|
|
143
|
+
assetValue,
|
|
144
|
+
memo = "",
|
|
145
|
+
asSignable = true,
|
|
146
|
+
asAminoMessage = false,
|
|
147
|
+
sequence,
|
|
148
|
+
accountNumber,
|
|
149
|
+
}: ThorchainCreateTransactionParams) => {
|
|
150
|
+
const account = await getAccount({ rpcUrl, sender });
|
|
151
|
+
const chain = assetValue.chain as TCLikeChain;
|
|
152
|
+
const { chainId } = getChainConfig(chain);
|
|
153
|
+
|
|
154
|
+
const depositMsg = depositMsgAmino({ assetValue, memo, sender });
|
|
155
|
+
|
|
156
|
+
const msg = asSignable
|
|
157
|
+
? await convertToSignable(
|
|
158
|
+
asAminoMessage ? depositMsg : parseAminoMessageForDirectSigning<MsgDeposit>(depositMsg),
|
|
159
|
+
chain,
|
|
160
|
+
)
|
|
161
|
+
: depositMsg;
|
|
162
|
+
|
|
163
|
+
const transaction = {
|
|
164
|
+
accountNumber: accountNumber || account.accountNumber,
|
|
165
|
+
chainId,
|
|
166
|
+
fee: getDefaultChainFee(chain),
|
|
167
|
+
memo,
|
|
168
|
+
msgs: [msg],
|
|
169
|
+
sequence: sequence || account.sequence,
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
return transaction;
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
export function parseAminoMessageForDirectSigning<T extends MsgDeposit | MsgSend>(msg: T) {
|
|
176
|
+
if (msg.type === "thorchain/MsgSend" || msg.type === "mayachain/MsgSend") return msg as MsgSend;
|
|
177
|
+
|
|
178
|
+
return {
|
|
179
|
+
...msg,
|
|
180
|
+
value: {
|
|
181
|
+
...msg.value,
|
|
182
|
+
coins: (msg as MsgDeposit).value.coins.map((coin: { asset: string; amount: string }) => {
|
|
183
|
+
const assetValue = AssetValue.from({ asset: coin.asset });
|
|
184
|
+
|
|
185
|
+
const symbol = (assetValue.isSynthetic ? assetValue.symbol.split("/")?.[1] : assetValue.symbol)?.toUpperCase();
|
|
186
|
+
const chain = (assetValue.isSynthetic ? assetValue.symbol.split("/")?.[0] : assetValue.chain)?.toUpperCase();
|
|
187
|
+
|
|
188
|
+
return { ...coin, asset: { chain, symbol, synth: assetValue.isSynthetic, ticker: assetValue.ticker } };
|
|
189
|
+
}),
|
|
190
|
+
},
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
export async function buildEncodedTxBody({
|
|
195
|
+
chain,
|
|
196
|
+
memo,
|
|
197
|
+
msgs,
|
|
198
|
+
}: {
|
|
199
|
+
msgs: DirectMsgDepositForBroadcast[] | DirectMsgSendForBroadcast[];
|
|
200
|
+
memo: string;
|
|
201
|
+
chain: TCLikeChain;
|
|
202
|
+
}) {
|
|
203
|
+
const registry = await createDefaultRegistry();
|
|
204
|
+
const aminoTypes = await createDefaultAminoTypes(chain);
|
|
205
|
+
|
|
206
|
+
const signedTxBody: TxBodyEncodeObject = {
|
|
207
|
+
typeUrl: "/cosmos.tx.v1beta1.TxBody",
|
|
208
|
+
value: { memo, messages: msgs.map((msg) => aminoTypes.fromAmino(msg)) },
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
return registry.encode(signedTxBody);
|
|
212
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { Chain, type TCLikeChain } from "@swapkit/helpers";
|
|
2
|
+
import { base64ToBech32, bech32ToBase64 } from "./addressFormat";
|
|
3
|
+
|
|
4
|
+
export async function createDefaultRegistry() {
|
|
5
|
+
const { $root } = await import("./types/MsgCompiled");
|
|
6
|
+
const importedProtoSigning = await import("@cosmjs/proto-signing");
|
|
7
|
+
const Registry = importedProtoSigning.Registry ?? importedProtoSigning.default?.Registry;
|
|
8
|
+
const importedStargate = await import("@cosmjs/stargate");
|
|
9
|
+
const defaultRegistryTypes = importedStargate.defaultRegistryTypes ?? importedStargate.default?.defaultRegistryTypes;
|
|
10
|
+
|
|
11
|
+
return new Registry([
|
|
12
|
+
...defaultRegistryTypes,
|
|
13
|
+
["/types.MsgSend", $root.types.MsgSend],
|
|
14
|
+
["/types.MsgDeposit", $root.types.MsgDeposit],
|
|
15
|
+
]);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export async function createDefaultAminoTypes(chain: TCLikeChain) {
|
|
19
|
+
const imported = await import("@cosmjs/stargate");
|
|
20
|
+
const AminoTypes = imported.AminoTypes ?? imported.default?.AminoTypes;
|
|
21
|
+
const aminoTypePrefix = chain === Chain.THORChain ? "thorchain" : ("mayachain" as const);
|
|
22
|
+
|
|
23
|
+
return new AminoTypes({
|
|
24
|
+
"/types.MsgDeposit": {
|
|
25
|
+
aminoType: `${aminoTypePrefix}/MsgDeposit`,
|
|
26
|
+
fromAmino: ({ signer, ...rest }: any) => ({ ...rest, signer: bech32ToBase64(signer) }),
|
|
27
|
+
toAmino: ({ signer, ...rest }: any) => ({ ...rest, signer: base64ToBech32(signer) }),
|
|
28
|
+
},
|
|
29
|
+
"/types.MsgSend": {
|
|
30
|
+
aminoType: `${aminoTypePrefix}/MsgSend`,
|
|
31
|
+
fromAmino: ({ from_address, to_address, ...rest }: any) => ({
|
|
32
|
+
...rest,
|
|
33
|
+
fromAddress: bech32ToBase64(from_address),
|
|
34
|
+
toAddress: bech32ToBase64(to_address),
|
|
35
|
+
}),
|
|
36
|
+
toAmino: ({ fromAddress, toAddress, ...rest }: any) => ({
|
|
37
|
+
...rest,
|
|
38
|
+
from_address: base64ToBech32(fromAddress),
|
|
39
|
+
to_address: base64ToBech32(toAddress),
|
|
40
|
+
}),
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
}
|