@getomnichain/omnichain 0.5.1 → 0.6.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.
- package/CHANGELOG.md +123 -0
- package/README.md +5 -3
- package/dist/cjs/address.factory.js +7 -4
- package/dist/cjs/address.factory.js.map +1 -1
- package/dist/cjs/asset_balance.js +7 -0
- package/dist/cjs/asset_balance.js.map +1 -0
- package/dist/cjs/asset_map.js +45 -0
- package/dist/cjs/asset_map.js.map +1 -0
- package/dist/cjs/asset_registry.js +21 -0
- package/dist/cjs/asset_registry.js.map +1 -0
- package/dist/cjs/bip39.js +88 -0
- package/dist/cjs/bip39.js.map +1 -0
- package/dist/cjs/bytes_from_hex.js +34 -0
- package/dist/cjs/bytes_from_hex.js.map +1 -0
- package/dist/cjs/chain_type.js +35 -0
- package/dist/cjs/chain_type.js.map +1 -0
- package/dist/cjs/evm/evm_chain.js +16 -0
- package/dist/cjs/evm/evm_chain.js.map +1 -1
- package/dist/cjs/index.js +12 -0
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/network_type.js +5 -2
- package/dist/cjs/network_type.js.map +1 -1
- package/dist/cjs/python_builtins.js +225 -0
- package/dist/cjs/python_builtins.js.map +1 -0
- package/dist/cjs/python_json.js +120 -0
- package/dist/cjs/python_json.js.map +1 -0
- package/dist/cjs/python_pydantic.js +50 -0
- package/dist/cjs/python_pydantic.js.map +1 -0
- package/dist/cjs/python_repr.js +172 -0
- package/dist/cjs/python_repr.js.map +1 -0
- package/dist/cjs/signed_transaction.js +24 -0
- package/dist/cjs/signed_transaction.js.map +1 -0
- package/dist/cjs/stellar/index.js +26 -0
- package/dist/cjs/stellar/index.js.map +1 -0
- package/dist/cjs/stellar/stellar_address.js +25 -0
- package/dist/cjs/stellar/stellar_address.js.map +1 -0
- package/dist/cjs/stellar/stellar_asset.js +155 -0
- package/dist/cjs/stellar/stellar_asset.js.map +1 -0
- package/dist/cjs/stellar/stellar_assets.js +26 -0
- package/dist/cjs/stellar/stellar_assets.js.map +1 -0
- package/dist/cjs/stellar/stellar_chain.js +1334 -0
- package/dist/cjs/stellar/stellar_chain.js.map +1 -0
- package/dist/cjs/stellar/stellar_chains.js +28 -0
- package/dist/cjs/stellar/stellar_chains.js.map +1 -0
- package/dist/cjs/stellar/stellar_gas_pricing.js +22 -0
- package/dist/cjs/stellar/stellar_gas_pricing.js.map +1 -0
- package/dist/cjs/stellar/stellar_strkey.js +71 -0
- package/dist/cjs/stellar/stellar_strkey.js.map +1 -0
- package/dist/cjs/stellar/stellar_transaction_status.js +72 -0
- package/dist/cjs/stellar/stellar_transaction_status.js.map +1 -0
- package/dist/cjs/stellar/stellar_transactions.js +475 -0
- package/dist/cjs/stellar/stellar_transactions.js.map +1 -0
- package/dist/cjs/stellar/stellar_wallet.js +195 -0
- package/dist/cjs/stellar/stellar_wallet.js.map +1 -0
- package/dist/cjs/token.js +3 -1
- package/dist/cjs/token.js.map +1 -1
- package/dist/cjs/transaction_json.js +85 -0
- package/dist/cjs/transaction_json.js.map +1 -0
- package/dist/cjs/transaction_prerequisite.js +19 -0
- package/dist/cjs/transaction_prerequisite.js.map +1 -0
- package/dist/cjs/transaction_simulation.js +21 -0
- package/dist/cjs/transaction_simulation.js.map +1 -0
- package/dist/cjs/tron/index.js +32 -0
- package/dist/cjs/tron/index.js.map +1 -0
- package/dist/cjs/tron/tron_abi.js +287 -0
- package/dist/cjs/tron/tron_abi.js.map +1 -0
- package/dist/cjs/tron/tron_address.js +38 -0
- package/dist/cjs/tron/tron_address.js.map +1 -0
- package/dist/cjs/tron/tron_asset.js +56 -0
- package/dist/cjs/tron/tron_asset.js.map +1 -0
- package/dist/cjs/tron/tron_assets.js +17 -0
- package/dist/cjs/tron/tron_assets.js.map +1 -0
- package/dist/cjs/tron/tron_base58.js +95 -0
- package/dist/cjs/tron/tron_base58.js.map +1 -0
- package/dist/cjs/tron/tron_canonical_transaction.js +268 -0
- package/dist/cjs/tron/tron_canonical_transaction.js.map +1 -0
- package/dist/cjs/tron/tron_chain.js +809 -0
- package/dist/cjs/tron/tron_chain.js.map +1 -0
- package/dist/cjs/tron/tron_chains.js +19 -0
- package/dist/cjs/tron/tron_chains.js.map +1 -0
- package/dist/cjs/tron/tron_client.js +327 -0
- package/dist/cjs/tron/tron_client.js.map +1 -0
- package/dist/cjs/tron/tron_contract.js +195 -0
- package/dist/cjs/tron/tron_contract.js.map +1 -0
- package/dist/cjs/tron/tron_gas_pricing.js +21 -0
- package/dist/cjs/tron/tron_gas_pricing.js.map +1 -0
- package/dist/cjs/tron/tron_keys.js +251 -0
- package/dist/cjs/tron/tron_keys.js.map +1 -0
- package/dist/cjs/tron/tron_transaction_builder.js +196 -0
- package/dist/cjs/tron/tron_transaction_builder.js.map +1 -0
- package/dist/cjs/tron/tron_transaction_status.js +118 -0
- package/dist/cjs/tron/tron_transaction_status.js.map +1 -0
- package/dist/cjs/tron/tron_transactions.js +192 -0
- package/dist/cjs/tron/tron_transactions.js.map +1 -0
- package/dist/cjs/tron/tron_wallet.js +152 -0
- package/dist/cjs/tron/tron_wallet.js.map +1 -0
- package/dist/cjs/unsigned_transaction.js +12 -0
- package/dist/cjs/unsigned_transaction.js.map +1 -1
- package/dist/cjs/wallet.base.js +29 -0
- package/dist/cjs/wallet.base.js.map +1 -0
- package/dist/esm/address.factory.d.ts.map +1 -1
- package/dist/esm/address.factory.js +7 -4
- package/dist/esm/address.factory.js.map +1 -1
- package/dist/esm/asset_balance.d.ts +5 -0
- package/dist/esm/asset_balance.d.ts.map +1 -0
- package/dist/esm/asset_balance.js +3 -0
- package/dist/esm/asset_balance.js.map +1 -0
- package/dist/esm/asset_map.d.ts +12 -0
- package/dist/esm/asset_map.d.ts.map +1 -0
- package/dist/esm/asset_map.js +40 -0
- package/dist/esm/asset_map.js.map +1 -0
- package/dist/esm/asset_registry.d.ts +6 -0
- package/dist/esm/asset_registry.d.ts.map +1 -0
- package/dist/esm/asset_registry.js +15 -0
- package/dist/esm/asset_registry.js.map +1 -0
- package/dist/esm/bip39.d.ts +4 -0
- package/dist/esm/bip39.d.ts.map +1 -0
- package/dist/esm/bip39.js +83 -0
- package/dist/esm/bip39.js.map +1 -0
- package/dist/esm/bytes_from_hex.d.ts +2 -0
- package/dist/esm/bytes_from_hex.d.ts.map +1 -0
- package/dist/esm/bytes_from_hex.js +31 -0
- package/dist/esm/bytes_from_hex.js.map +1 -0
- package/dist/esm/chain_type.d.ts +29 -0
- package/dist/esm/chain_type.d.ts.map +1 -0
- package/dist/esm/chain_type.js +32 -0
- package/dist/esm/chain_type.js.map +1 -0
- package/dist/esm/evm/evm_chain.d.ts +1 -0
- package/dist/esm/evm/evm_chain.d.ts.map +1 -1
- package/dist/esm/evm/evm_chain.js +17 -1
- package/dist/esm/evm/evm_chain.js.map +1 -1
- package/dist/esm/index.d.ts +12 -0
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +12 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/network_type.d.ts +3 -2
- package/dist/esm/network_type.d.ts.map +1 -1
- package/dist/esm/network_type.js +6 -3
- package/dist/esm/network_type.js.map +1 -1
- package/dist/esm/python_builtins.d.ts +13 -0
- package/dist/esm/python_builtins.d.ts.map +1 -0
- package/dist/esm/python_builtins.js +212 -0
- package/dist/esm/python_builtins.js.map +1 -0
- package/dist/esm/python_json.d.ts +9 -0
- package/dist/esm/python_json.d.ts.map +1 -0
- package/dist/esm/python_json.js +117 -0
- package/dist/esm/python_json.js.map +1 -0
- package/dist/esm/python_pydantic.d.ts +11 -0
- package/dist/esm/python_pydantic.d.ts.map +1 -0
- package/dist/esm/python_pydantic.js +39 -0
- package/dist/esm/python_pydantic.js.map +1 -0
- package/dist/esm/python_repr.d.ts +17 -0
- package/dist/esm/python_repr.d.ts.map +1 -0
- package/dist/esm/python_repr.js +160 -0
- package/dist/esm/python_repr.js.map +1 -0
- package/dist/esm/signed_transaction.d.ts +17 -0
- package/dist/esm/signed_transaction.d.ts.map +1 -0
- package/dist/esm/signed_transaction.js +19 -0
- package/dist/esm/signed_transaction.js.map +1 -0
- package/dist/esm/stellar/index.d.ts +10 -0
- package/dist/esm/stellar/index.d.ts.map +1 -0
- package/dist/esm/stellar/index.js +10 -0
- package/dist/esm/stellar/index.js.map +1 -0
- package/dist/esm/stellar/stellar_address.d.ts +8 -0
- package/dist/esm/stellar/stellar_address.d.ts.map +1 -0
- package/dist/esm/stellar/stellar_address.js +21 -0
- package/dist/esm/stellar/stellar_address.js.map +1 -0
- package/dist/esm/stellar/stellar_asset.d.ts +52 -0
- package/dist/esm/stellar/stellar_asset.d.ts.map +1 -0
- package/dist/esm/stellar/stellar_asset.js +147 -0
- package/dist/esm/stellar/stellar_asset.js.map +1 -0
- package/dist/esm/stellar/stellar_assets.d.ts +11 -0
- package/dist/esm/stellar/stellar_assets.d.ts.map +1 -0
- package/dist/esm/stellar/stellar_assets.js +23 -0
- package/dist/esm/stellar/stellar_assets.js.map +1 -0
- package/dist/esm/stellar/stellar_chain.d.ts +173 -0
- package/dist/esm/stellar/stellar_chain.d.ts.map +1 -0
- package/dist/esm/stellar/stellar_chain.js +1325 -0
- package/dist/esm/stellar/stellar_chain.js.map +1 -0
- package/dist/esm/stellar/stellar_chains.d.ts +5 -0
- package/dist/esm/stellar/stellar_chains.d.ts.map +1 -0
- package/dist/esm/stellar/stellar_chains.js +25 -0
- package/dist/esm/stellar/stellar_chains.js.map +1 -0
- package/dist/esm/stellar/stellar_gas_pricing.d.ts +13 -0
- package/dist/esm/stellar/stellar_gas_pricing.d.ts.map +1 -0
- package/dist/esm/stellar/stellar_gas_pricing.js +18 -0
- package/dist/esm/stellar/stellar_gas_pricing.js.map +1 -0
- package/dist/esm/stellar/stellar_strkey.d.ts +3 -0
- package/dist/esm/stellar/stellar_strkey.d.ts.map +1 -0
- package/dist/esm/stellar/stellar_strkey.js +67 -0
- package/dist/esm/stellar/stellar_strkey.js.map +1 -0
- package/dist/esm/stellar/stellar_transaction_status.d.ts +39 -0
- package/dist/esm/stellar/stellar_transaction_status.d.ts.map +1 -0
- package/dist/esm/stellar/stellar_transaction_status.js +68 -0
- package/dist/esm/stellar/stellar_transaction_status.js.map +1 -0
- package/dist/esm/stellar/stellar_transactions.d.ts +166 -0
- package/dist/esm/stellar/stellar_transactions.d.ts.map +1 -0
- package/dist/esm/stellar/stellar_transactions.js +451 -0
- package/dist/esm/stellar/stellar_transactions.js.map +1 -0
- package/dist/esm/stellar/stellar_wallet.d.ts +43 -0
- package/dist/esm/stellar/stellar_wallet.d.ts.map +1 -0
- package/dist/esm/stellar/stellar_wallet.js +190 -0
- package/dist/esm/stellar/stellar_wallet.js.map +1 -0
- package/dist/esm/token.d.ts +1 -0
- package/dist/esm/token.d.ts.map +1 -1
- package/dist/esm/token.js +3 -1
- package/dist/esm/token.js.map +1 -1
- package/dist/esm/transaction_json.d.ts +21 -0
- package/dist/esm/transaction_json.d.ts.map +1 -0
- package/dist/esm/transaction_json.js +75 -0
- package/dist/esm/transaction_json.js.map +1 -0
- package/dist/esm/transaction_prerequisite.d.ts +17 -0
- package/dist/esm/transaction_prerequisite.d.ts.map +1 -0
- package/dist/esm/transaction_prerequisite.js +13 -0
- package/dist/esm/transaction_prerequisite.js.map +1 -0
- package/dist/esm/transaction_simulation.d.ts +20 -0
- package/dist/esm/transaction_simulation.d.ts.map +1 -0
- package/dist/esm/transaction_simulation.js +17 -0
- package/dist/esm/transaction_simulation.js.map +1 -0
- package/dist/esm/tron/index.d.ts +16 -0
- package/dist/esm/tron/index.d.ts.map +1 -0
- package/dist/esm/tron/index.js +16 -0
- package/dist/esm/tron/index.js.map +1 -0
- package/dist/esm/tron/tron_abi.d.ts +3 -0
- package/dist/esm/tron/tron_abi.d.ts.map +1 -0
- package/dist/esm/tron/tron_abi.js +283 -0
- package/dist/esm/tron/tron_abi.js.map +1 -0
- package/dist/esm/tron/tron_address.d.ts +10 -0
- package/dist/esm/tron/tron_address.d.ts.map +1 -0
- package/dist/esm/tron/tron_address.js +34 -0
- package/dist/esm/tron/tron_address.js.map +1 -0
- package/dist/esm/tron/tron_asset.d.ts +19 -0
- package/dist/esm/tron/tron_asset.d.ts.map +1 -0
- package/dist/esm/tron/tron_asset.js +51 -0
- package/dist/esm/tron/tron_asset.js.map +1 -0
- package/dist/esm/tron/tron_assets.d.ts +10 -0
- package/dist/esm/tron/tron_assets.d.ts.map +1 -0
- package/dist/esm/tron/tron_assets.js +14 -0
- package/dist/esm/tron/tron_assets.js.map +1 -0
- package/dist/esm/tron/tron_base58.d.ts +7 -0
- package/dist/esm/tron/tron_base58.d.ts.map +1 -0
- package/dist/esm/tron/tron_base58.js +84 -0
- package/dist/esm/tron/tron_base58.js.map +1 -0
- package/dist/esm/tron/tron_canonical_transaction.d.ts +164 -0
- package/dist/esm/tron/tron_canonical_transaction.d.ts.map +1 -0
- package/dist/esm/tron/tron_canonical_transaction.js +262 -0
- package/dist/esm/tron/tron_canonical_transaction.js.map +1 -0
- package/dist/esm/tron/tron_chain.d.ts +136 -0
- package/dist/esm/tron/tron_chain.d.ts.map +1 -0
- package/dist/esm/tron/tron_chain.js +801 -0
- package/dist/esm/tron/tron_chain.js.map +1 -0
- package/dist/esm/tron/tron_chains.d.ts +5 -0
- package/dist/esm/tron/tron_chains.d.ts.map +1 -0
- package/dist/esm/tron/tron_chains.js +16 -0
- package/dist/esm/tron/tron_chains.js.map +1 -0
- package/dist/esm/tron/tron_client.d.ts +56 -0
- package/dist/esm/tron/tron_client.d.ts.map +1 -0
- package/dist/esm/tron/tron_client.js +319 -0
- package/dist/esm/tron/tron_client.js.map +1 -0
- package/dist/esm/tron/tron_contract.d.ts +69 -0
- package/dist/esm/tron/tron_contract.d.ts.map +1 -0
- package/dist/esm/tron/tron_contract.js +190 -0
- package/dist/esm/tron/tron_contract.js.map +1 -0
- package/dist/esm/tron/tron_gas_pricing.d.ts +12 -0
- package/dist/esm/tron/tron_gas_pricing.d.ts.map +1 -0
- package/dist/esm/tron/tron_gas_pricing.js +17 -0
- package/dist/esm/tron/tron_gas_pricing.js.map +1 -0
- package/dist/esm/tron/tron_keys.d.ts +61 -0
- package/dist/esm/tron/tron_keys.d.ts.map +1 -0
- package/dist/esm/tron/tron_keys.js +228 -0
- package/dist/esm/tron/tron_keys.js.map +1 -0
- package/dist/esm/tron/tron_transaction_builder.d.ts +56 -0
- package/dist/esm/tron/tron_transaction_builder.d.ts.map +1 -0
- package/dist/esm/tron/tron_transaction_builder.js +188 -0
- package/dist/esm/tron/tron_transaction_builder.js.map +1 -0
- package/dist/esm/tron/tron_transaction_status.d.ts +54 -0
- package/dist/esm/tron/tron_transaction_status.d.ts.map +1 -0
- package/dist/esm/tron/tron_transaction_status.js +113 -0
- package/dist/esm/tron/tron_transaction_status.js.map +1 -0
- package/dist/esm/tron/tron_transactions.d.ts +96 -0
- package/dist/esm/tron/tron_transactions.d.ts.map +1 -0
- package/dist/esm/tron/tron_transactions.js +181 -0
- package/dist/esm/tron/tron_transactions.js.map +1 -0
- package/dist/esm/tron/tron_wallet.d.ts +43 -0
- package/dist/esm/tron/tron_wallet.d.ts.map +1 -0
- package/dist/esm/tron/tron_wallet.js +148 -0
- package/dist/esm/tron/tron_wallet.js.map +1 -0
- package/dist/esm/unsigned_transaction.d.ts +5 -0
- package/dist/esm/unsigned_transaction.d.ts.map +1 -1
- package/dist/esm/unsigned_transaction.js +12 -0
- package/dist/esm/unsigned_transaction.js.map +1 -1
- package/dist/esm/wallet.base.d.ts +32 -0
- package/dist/esm/wallet.base.d.ts.map +1 -0
- package/dist/esm/wallet.base.js +23 -0
- package/dist/esm/wallet.base.js.map +1 -0
- package/docs/CONNECTIONS.md +1 -0
- package/docs/README.md +16 -7
- package/docs/stellar.md +113 -0
- package/docs/tron.md +103 -0
- package/package.json +14 -2
|
@@ -0,0 +1,1334 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.StellarChain = exports.StellarSignedMessage = void 0;
|
|
4
|
+
exports.stellarMessageHash = stellarMessageHash;
|
|
5
|
+
exports.scvalToUint32 = scvalToUint32;
|
|
6
|
+
exports.scvalToUtf8String = scvalToUtf8String;
|
|
7
|
+
exports.scvalToInt128 = scvalToInt128;
|
|
8
|
+
const node_crypto_1 = require("node:crypto");
|
|
9
|
+
const stellar_sdk_1 = require("@stellar/stellar-sdk");
|
|
10
|
+
const decimal_js_1 = require("decimal.js");
|
|
11
|
+
const abstract_gas_pricing_ts_1 = require("../abstract_gas_pricing.js");
|
|
12
|
+
const asset_map_ts_1 = require("../asset_map.js");
|
|
13
|
+
const bytes_from_hex_ts_1 = require("../bytes_from_hex.js");
|
|
14
|
+
const chain_base_ts_1 = require("../chain.base.js");
|
|
15
|
+
const chain_type_ts_1 = require("../chain_type.js");
|
|
16
|
+
const errors_ts_1 = require("../errors.js");
|
|
17
|
+
const python_builtins_ts_1 = require("../python_builtins.js");
|
|
18
|
+
const python_repr_ts_1 = require("../python_repr.js");
|
|
19
|
+
const python_pydantic_ts_1 = require("../python_pydantic.js");
|
|
20
|
+
const network_type_ts_1 = require("../network_type.js");
|
|
21
|
+
const priority_ts_1 = require("../priority.js");
|
|
22
|
+
const transaction_json_ts_1 = require("../transaction_json.js");
|
|
23
|
+
const transaction_prerequisite_ts_1 = require("../transaction_prerequisite.js");
|
|
24
|
+
const transaction_simulation_ts_1 = require("../transaction_simulation.js");
|
|
25
|
+
const transaction_status_ts_1 = require("../transaction_status.js");
|
|
26
|
+
const wallet_base_ts_1 = require("../wallet.base.js");
|
|
27
|
+
const stellar_asset_ts_1 = require("./stellar_asset.js");
|
|
28
|
+
const stellar_gas_pricing_ts_1 = require("./stellar_gas_pricing.js");
|
|
29
|
+
const stellar_transaction_status_ts_1 = require("./stellar_transaction_status.js");
|
|
30
|
+
const stellar_transactions_ts_1 = require("./stellar_transactions.js");
|
|
31
|
+
const STELLAR_MESSAGE_PREFIX = 'Stellar Signed Message:\n';
|
|
32
|
+
const NON_SAC_TOKEN_CACHE_SIZE = 2000;
|
|
33
|
+
const HORIZON_DEFAULT_BASE_FEE_STROOPS = 100;
|
|
34
|
+
const PythonDecimal = decimal_js_1.Decimal.clone({ precision: 28, rounding: decimal_js_1.Decimal.ROUND_HALF_EVEN });
|
|
35
|
+
function stellarMessageHash(message) {
|
|
36
|
+
const messageBytes = typeof message === 'string' ? Buffer.from((0, python_builtins_ts_1.pyEncodeUtf8)(message)) : Buffer.from(message);
|
|
37
|
+
return (0, node_crypto_1.createHash)('sha256').update(Buffer.concat([Buffer.from(STELLAR_MESSAGE_PREFIX, 'utf8'), messageBytes])).digest();
|
|
38
|
+
}
|
|
39
|
+
class StellarSignedMessage extends wallet_base_ts_1.AbstractSignedMessage {
|
|
40
|
+
constructor(signature) {
|
|
41
|
+
super(signature);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
exports.StellarSignedMessage = StellarSignedMessage;
|
|
45
|
+
class StellarChain extends chain_base_ts_1.Chain {
|
|
46
|
+
chainAgnosticNamespace;
|
|
47
|
+
stellarExpertApiUrl;
|
|
48
|
+
networkPassphrase;
|
|
49
|
+
defaultHorizonUrl;
|
|
50
|
+
defaultSorobanRpcUrl;
|
|
51
|
+
horizonUrl;
|
|
52
|
+
sorobanRpcUrl;
|
|
53
|
+
_randomCallAccountId;
|
|
54
|
+
_nativeAsset;
|
|
55
|
+
_horizonServer = null;
|
|
56
|
+
_sorobanServer = null;
|
|
57
|
+
nonSacTokenCache = new Map();
|
|
58
|
+
assetDecimalsByIdentifier = new Map();
|
|
59
|
+
static _FEE_PRIORITY_MULTIPLIERS = {
|
|
60
|
+
[priority_ts_1.FeePriority.SLOW]: 1.0,
|
|
61
|
+
[priority_ts_1.FeePriority.NORMAL]: 1.0,
|
|
62
|
+
[priority_ts_1.FeePriority.FAST]: 2.0,
|
|
63
|
+
};
|
|
64
|
+
constructor(init) {
|
|
65
|
+
super(init.chainId, init.name, network_type_ts_1.NetworkType.STELLAR, 5.0, stellar_asset_ts_1.StellarAsset.NATIVE_CODE, init.explorerUrl);
|
|
66
|
+
this.chainAgnosticNamespace = `stellar:${init.chainAgnosticStellarIdentifier}`;
|
|
67
|
+
this.stellarExpertApiUrl = init.stellarExpertApiUrl;
|
|
68
|
+
this.networkPassphrase = init.networkPassphrase;
|
|
69
|
+
this._randomCallAccountId = stellar_sdk_1.Keypair.random().publicKey();
|
|
70
|
+
this._nativeAsset = new stellar_asset_ts_1.StellarAsset({
|
|
71
|
+
chainId: init.chainId,
|
|
72
|
+
networkPassphrase: init.networkPassphrase,
|
|
73
|
+
code: stellar_asset_ts_1.StellarAsset.NATIVE_CODE,
|
|
74
|
+
issuer: null,
|
|
75
|
+
});
|
|
76
|
+
this.horizonUrl = init.horizonUrl ?? null;
|
|
77
|
+
this.sorobanRpcUrl = init.sorobanRpcUrl ?? null;
|
|
78
|
+
this.defaultHorizonUrl = init.defaultHorizonUrl;
|
|
79
|
+
this.defaultSorobanRpcUrl = init.defaultSorobanRpcUrl;
|
|
80
|
+
}
|
|
81
|
+
get asyncHorizonServer() {
|
|
82
|
+
if (this._horizonServer === null) {
|
|
83
|
+
this.horizonUrl = this.horizonUrl || this._loadHorizonUrl();
|
|
84
|
+
this._horizonServer = new stellar_sdk_1.Horizon.Server(this.horizonUrl, { allowHttp: this.horizonUrl.startsWith('http://') });
|
|
85
|
+
applyAiohttpClientLimits(this._horizonServer.httpClient);
|
|
86
|
+
}
|
|
87
|
+
return this._horizonServer;
|
|
88
|
+
}
|
|
89
|
+
get asyncSorobanServer() {
|
|
90
|
+
if (this._sorobanServer === null) {
|
|
91
|
+
this.sorobanRpcUrl = this.sorobanRpcUrl || this._loadSorobanRpcUrl();
|
|
92
|
+
this._sorobanServer = new stellar_sdk_1.rpc.Server(this.sorobanRpcUrl, { allowHttp: this.sorobanRpcUrl.startsWith('http://') });
|
|
93
|
+
applyAiohttpClientLimits(this._sorobanServer.httpClient);
|
|
94
|
+
}
|
|
95
|
+
return this._sorobanServer;
|
|
96
|
+
}
|
|
97
|
+
static horizonUrlEnvForChainId(chainId) {
|
|
98
|
+
return `STELLAR_${chainId}_HORIZON_URL`;
|
|
99
|
+
}
|
|
100
|
+
static sorobanRpcUrlEnvForChainId(chainId) {
|
|
101
|
+
return `STELLAR_${chainId}_SOROBAN_RPC_URL`;
|
|
102
|
+
}
|
|
103
|
+
_loadHorizonUrl() {
|
|
104
|
+
return this.loadUrlFromEnv([`${this.envName()}_HORIZON_URL`, StellarChain.horizonUrlEnvForChainId(this.chainId)], this.defaultHorizonUrl);
|
|
105
|
+
}
|
|
106
|
+
_loadSorobanRpcUrl() {
|
|
107
|
+
return this.loadUrlFromEnv([`${this.envName()}_SOROBAN_RPC_URL`, StellarChain.sorobanRpcUrlEnvForChainId(this.chainId)], this.defaultSorobanRpcUrl);
|
|
108
|
+
}
|
|
109
|
+
get chainType() {
|
|
110
|
+
return chain_type_ts_1.ChainType.STELLAR;
|
|
111
|
+
}
|
|
112
|
+
get nativeAsset() {
|
|
113
|
+
return this._nativeAsset;
|
|
114
|
+
}
|
|
115
|
+
get nativeToken() {
|
|
116
|
+
return this._nativeAsset;
|
|
117
|
+
}
|
|
118
|
+
toString() {
|
|
119
|
+
return `StellarChain[chain_id:${this.chainId}]`;
|
|
120
|
+
}
|
|
121
|
+
getAssetExplorerUrl(asset) {
|
|
122
|
+
this.assertStellarAsset(asset);
|
|
123
|
+
if (asset.isNative())
|
|
124
|
+
return null;
|
|
125
|
+
if (asset.issuer === null)
|
|
126
|
+
return `${this.explorerBaseUrl}/contract/${asset.identifier}`;
|
|
127
|
+
return `${this.explorerBaseUrl}/asset/${asset.code}-${asset.issuer}`;
|
|
128
|
+
}
|
|
129
|
+
getWalletAddressExplorerUrl(walletAddress) {
|
|
130
|
+
return `${this.explorerBaseUrl}/account/${walletAddress}`;
|
|
131
|
+
}
|
|
132
|
+
getTransactionExplorerUrl(txHash) {
|
|
133
|
+
return `${this.explorerBaseUrl}/tx/${txHash}`;
|
|
134
|
+
}
|
|
135
|
+
getWalletExplorerUrl(address) {
|
|
136
|
+
return this.getWalletAddressExplorerUrl(address);
|
|
137
|
+
}
|
|
138
|
+
getTokenExplorerUrl(tokenIdentifier) {
|
|
139
|
+
if (!tokenIdentifier)
|
|
140
|
+
return this.explorerBaseUrl;
|
|
141
|
+
return `${this.explorerBaseUrl}/contract/${tokenIdentifier}`;
|
|
142
|
+
}
|
|
143
|
+
static formatAssetIdentifier(identifier) {
|
|
144
|
+
return identifier ?? null;
|
|
145
|
+
}
|
|
146
|
+
static validateAssetIdentifier(identifier) {
|
|
147
|
+
if (identifier === null || identifier === undefined)
|
|
148
|
+
return;
|
|
149
|
+
if (!stellar_sdk_1.StrKey.isValidContract(identifier)) {
|
|
150
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidTokenIdentifier, `Invalid stellar asset identifier ${identifier}`, { identifier });
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
static formatWalletAddress(walletAddress) {
|
|
154
|
+
return walletAddress;
|
|
155
|
+
}
|
|
156
|
+
static validateWalletAddress(walletAddress) {
|
|
157
|
+
if (stellar_sdk_1.StrKey.isValidEd25519PublicKey(walletAddress))
|
|
158
|
+
return;
|
|
159
|
+
if (stellar_sdk_1.StrKey.isValidMed25519PublicKey(walletAddress))
|
|
160
|
+
return;
|
|
161
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidAddress, `Invalid Stellar wallet address ${walletAddress}`, { address: walletAddress });
|
|
162
|
+
}
|
|
163
|
+
static toClassicAccountId(address) {
|
|
164
|
+
return (0, stellar_transactions_ts_1.toClassicStellarAccountId)(address);
|
|
165
|
+
}
|
|
166
|
+
validateAddress(raw) {
|
|
167
|
+
try {
|
|
168
|
+
StellarChain.validateWalletAddress(raw);
|
|
169
|
+
return true;
|
|
170
|
+
}
|
|
171
|
+
catch {
|
|
172
|
+
return false;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
validateTokenIdentifier(raw) {
|
|
176
|
+
try {
|
|
177
|
+
StellarChain.validateAssetIdentifier(raw);
|
|
178
|
+
return true;
|
|
179
|
+
}
|
|
180
|
+
catch {
|
|
181
|
+
return false;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
async getBaseFee() {
|
|
185
|
+
let latestLedger;
|
|
186
|
+
try {
|
|
187
|
+
latestLedger = (await this.asyncHorizonServer.ledgers().order('desc').limit(1).call());
|
|
188
|
+
}
|
|
189
|
+
catch (err) {
|
|
190
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.RpcError, (0, errors_ts_1.sanitizeMessage)(err instanceof Error ? err.message : String(err), this.horizonUrl), { chainId: this.chainId }, (0, errors_ts_1.sanitizeCause)(err, this.horizonUrl));
|
|
191
|
+
}
|
|
192
|
+
const embedded = Array.isArray(latestLedger.records) ? { records: latestLedger.records } : (0, python_builtins_ts_1.pyItem)(latestLedger, '_embedded');
|
|
193
|
+
if (!(0, python_builtins_ts_1.pyTruthy)(embedded))
|
|
194
|
+
return HORIZON_DEFAULT_BASE_FEE_STROOPS;
|
|
195
|
+
const records = (0, python_builtins_ts_1.pyItem)(embedded, 'records');
|
|
196
|
+
if (!(0, python_builtins_ts_1.pyTruthy)(records))
|
|
197
|
+
return HORIZON_DEFAULT_BASE_FEE_STROOPS;
|
|
198
|
+
const first = Array.isArray(records) ? records[0] : (0, python_builtins_ts_1.pyItem)(records, '0');
|
|
199
|
+
if (!(0, python_builtins_ts_1.pyTruthy)(first))
|
|
200
|
+
return HORIZON_DEFAULT_BASE_FEE_STROOPS;
|
|
201
|
+
return Number((0, python_builtins_ts_1.pyIntOf)((0, python_builtins_ts_1.pyItem)(first, 'base_fee_in_stroops')));
|
|
202
|
+
}
|
|
203
|
+
async _resolveGasPricing(gasPricing) {
|
|
204
|
+
if ((0, abstract_gas_pricing_ts_1.isAbstractGasPricing)(gasPricing)) {
|
|
205
|
+
if (!(gasPricing instanceof stellar_gas_pricing_ts_1.StellarGasPricing)) {
|
|
206
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidArgument, `Expected StellarGasPricing for a Stellar chain, got ${gasPricing.constructor.name}`, { chainId: this.chainId });
|
|
207
|
+
}
|
|
208
|
+
return Math.max(stellar_gas_pricing_ts_1.STELLAR_MIN_BASE_FEE_STROOPS, gasPricing.baseFeeStroops);
|
|
209
|
+
}
|
|
210
|
+
if (!Object.values(priority_ts_1.FeePriority).includes(gasPricing)) {
|
|
211
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidArgument, `Unsupported gas_pricing ${(0, python_repr_ts_1.pyRepr)(gasPricing)}`, { chainId: this.chainId });
|
|
212
|
+
}
|
|
213
|
+
const baseFee = await this.getBaseFee();
|
|
214
|
+
const scaled = Math.trunc(baseFee * StellarChain._FEE_PRIORITY_MULTIPLIERS[gasPricing]);
|
|
215
|
+
return Math.max(stellar_gas_pricing_ts_1.STELLAR_MIN_BASE_FEE_STROOPS, scaled);
|
|
216
|
+
}
|
|
217
|
+
createNonSacToken(contractId) {
|
|
218
|
+
const cached = this.nonSacTokenCache.get(contractId);
|
|
219
|
+
if (cached !== undefined) {
|
|
220
|
+
this.nonSacTokenCache.delete(contractId);
|
|
221
|
+
this.nonSacTokenCache.set(contractId, cached);
|
|
222
|
+
return cached;
|
|
223
|
+
}
|
|
224
|
+
const pending = (async () => {
|
|
225
|
+
const decimalsResp = await this._callHostFunction({ contractId, functionName: 'decimals', parameters: [] });
|
|
226
|
+
const decimals = scvalToUint32(firstHostFunctionResult(decimalsResp));
|
|
227
|
+
const symbolResp = await this._callHostFunction({ contractId, functionName: 'symbol', parameters: [] });
|
|
228
|
+
const symbol = scvalToUtf8String(firstHostFunctionResult(symbolResp));
|
|
229
|
+
return new stellar_asset_ts_1.StellarAsset({
|
|
230
|
+
chainId: this.chainId,
|
|
231
|
+
networkPassphrase: this.networkPassphrase,
|
|
232
|
+
code: symbol,
|
|
233
|
+
issuer: null,
|
|
234
|
+
contractId,
|
|
235
|
+
decimals,
|
|
236
|
+
});
|
|
237
|
+
})();
|
|
238
|
+
this.nonSacTokenCache.set(contractId, pending);
|
|
239
|
+
if (this.nonSacTokenCache.size > NON_SAC_TOKEN_CACHE_SIZE) {
|
|
240
|
+
const oldest = this.nonSacTokenCache.keys().next().value;
|
|
241
|
+
this.nonSacTokenCache.delete(oldest);
|
|
242
|
+
}
|
|
243
|
+
pending.catch(() => {
|
|
244
|
+
if (this.nonSacTokenCache.get(contractId) === pending)
|
|
245
|
+
this.nonSacTokenCache.delete(contractId);
|
|
246
|
+
});
|
|
247
|
+
return pending;
|
|
248
|
+
}
|
|
249
|
+
createSacToken(code, issuer) {
|
|
250
|
+
return new stellar_asset_ts_1.StellarAsset({
|
|
251
|
+
chainId: this.chainId,
|
|
252
|
+
networkPassphrase: this.networkPassphrase,
|
|
253
|
+
code,
|
|
254
|
+
issuer,
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
async resolveAsset(identifier) {
|
|
258
|
+
if (identifier === null ||
|
|
259
|
+
identifier === undefined ||
|
|
260
|
+
identifier === stellar_asset_ts_1.StellarAsset.PUBLIC_NATIVE_CONTRACT_ID ||
|
|
261
|
+
identifier === stellar_asset_ts_1.StellarAsset.TESTNET_NATIVE_CONTRACT_ID) {
|
|
262
|
+
return this._nativeAsset;
|
|
263
|
+
}
|
|
264
|
+
const decimalsResults = await this._callHostFunction({ contractId: identifier, functionName: 'decimals', parameters: [] });
|
|
265
|
+
const decimals = scvalToUint32(firstHostFunctionResult(decimalsResults));
|
|
266
|
+
const nameResults = await this._callHostFunction({ contractId: identifier, functionName: 'name', parameters: [] });
|
|
267
|
+
const name = scvalToUtf8String(firstHostFunctionResult(nameResults));
|
|
268
|
+
let code;
|
|
269
|
+
let issuer;
|
|
270
|
+
if (name === 'native') {
|
|
271
|
+
return this._nativeAsset;
|
|
272
|
+
}
|
|
273
|
+
else if (!name.includes(':')) {
|
|
274
|
+
const symbolResults = await this._callHostFunction({ contractId: identifier, functionName: 'symbol', parameters: [] });
|
|
275
|
+
code = scvalToUtf8String(firstHostFunctionResult(symbolResults));
|
|
276
|
+
issuer = null;
|
|
277
|
+
}
|
|
278
|
+
else {
|
|
279
|
+
const separator = name.indexOf(':');
|
|
280
|
+
code = name.slice(0, separator);
|
|
281
|
+
issuer = name.slice(separator + 1);
|
|
282
|
+
}
|
|
283
|
+
return new stellar_asset_ts_1.StellarAsset({
|
|
284
|
+
chainId: this.chainId,
|
|
285
|
+
networkPassphrase: this.networkPassphrase,
|
|
286
|
+
code,
|
|
287
|
+
issuer,
|
|
288
|
+
contractId: identifier,
|
|
289
|
+
decimals,
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
createAsset(_symbol, _identifier, _decimals) {
|
|
293
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.FeatureNotSupported, 'Cannot create asset for stellar via create_asset method', {
|
|
294
|
+
chainId: this.chainId,
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
async _callHostFunction(req) {
|
|
298
|
+
if (!stellar_sdk_1.StrKey.isValidContract(req.contractId)) {
|
|
299
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidTokenIdentifier, '`contract_id` is invalid.', {
|
|
300
|
+
chainId: this.chainId,
|
|
301
|
+
identifier: req.contractId,
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
const account = req.accountId === undefined || req.accountId === null
|
|
305
|
+
? new stellar_sdk_1.Account(this._randomCallAccountId, '0')
|
|
306
|
+
: await this.soroban(this.asyncSorobanServer.getAccount(req.accountId));
|
|
307
|
+
const tx = new stellar_sdk_1.TransactionBuilder(account, { fee: '300', networkPassphrase: this.networkPassphrase })
|
|
308
|
+
.addOperation(stellar_sdk_1.Operation.invokeContractFunction({
|
|
309
|
+
contract: req.contractId,
|
|
310
|
+
function: req.functionName,
|
|
311
|
+
args: req.parameters,
|
|
312
|
+
}))
|
|
313
|
+
.setTimeout(300)
|
|
314
|
+
.build();
|
|
315
|
+
return (await (0, stellar_transactions_ts_1.simulateSorobanTransaction)(tx, this)).results;
|
|
316
|
+
}
|
|
317
|
+
async _sorobanRpc(method, params) {
|
|
318
|
+
const soroban = this.asyncSorobanServer;
|
|
319
|
+
const body = { jsonrpc: '2.0', id: (0, node_crypto_1.randomUUID)().replace(/-/g, ''), method, params };
|
|
320
|
+
const config = { validateStatus: () => true, responseType: 'text', transformResponse: [(data) => data] };
|
|
321
|
+
const response = await soroban.httpClient.post(soroban.serverURL.toString(), body, config);
|
|
322
|
+
let reply;
|
|
323
|
+
try {
|
|
324
|
+
reply = JSON.parse(String(response.data));
|
|
325
|
+
}
|
|
326
|
+
catch {
|
|
327
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.RpcError, `Soroban ${method} returned a body that is not valid JSON (HTTP ${response.status})`, {
|
|
328
|
+
chainId: this.chainId,
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
const error = (0, python_pydantic_ts_1.isPydanticDict)(reply) ? reply.error : undefined;
|
|
332
|
+
const validEnvelope = (0, python_pydantic_ts_1.isPydanticDict)(reply) &&
|
|
333
|
+
typeof reply.jsonrpc === 'string' &&
|
|
334
|
+
(typeof reply.id === 'string' || (0, python_pydantic_ts_1.isPydanticLaxInt)(reply.id)) &&
|
|
335
|
+
((0, python_pydantic_ts_1.isPydanticAbsent)(error) ||
|
|
336
|
+
((0, python_pydantic_ts_1.isPydanticDict)(error) && (0, python_pydantic_ts_1.isPydanticLaxInt)(error.code) && (0, python_pydantic_ts_1.isPydanticOptionalStr)(error.message) && (0, python_pydantic_ts_1.isPydanticOptionalStr)(error.data)));
|
|
337
|
+
if (!validEnvelope) {
|
|
338
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.RpcError, `Soroban ${method} reply does not match the JSON-RPC Response model`, { chainId: this.chainId });
|
|
339
|
+
}
|
|
340
|
+
const envelope = reply;
|
|
341
|
+
if ((0, python_pydantic_ts_1.isPydanticDict)(error)) {
|
|
342
|
+
throw new stellar_transactions_ts_1.SorobanRpcErrorResponse(Number((0, python_pydantic_ts_1.pydanticLaxIntValue)(error.code)), error.message, error.data, this.chainId);
|
|
343
|
+
}
|
|
344
|
+
if ((0, python_pydantic_ts_1.isPydanticAbsent)(envelope.result)) {
|
|
345
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.RpcError, '', { chainId: this.chainId });
|
|
346
|
+
}
|
|
347
|
+
return envelope.result;
|
|
348
|
+
}
|
|
349
|
+
async _getAssetDecimalsInternal(_symbol, identifier) {
|
|
350
|
+
try {
|
|
351
|
+
const decimalsResult = await this._callHostFunction({
|
|
352
|
+
contractId: identifier,
|
|
353
|
+
functionName: 'decimals',
|
|
354
|
+
parameters: [],
|
|
355
|
+
});
|
|
356
|
+
return scvalToUint32(firstHostFunctionResult(decimalsResult));
|
|
357
|
+
}
|
|
358
|
+
catch {
|
|
359
|
+
return stellar_asset_ts_1.StellarAsset.DECIMALS;
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
async getCachedAssetDecimals(symbol, identifier) {
|
|
363
|
+
if (identifier === null || identifier === undefined) {
|
|
364
|
+
if (symbol !== this._nativeAsset.symbol) {
|
|
365
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidArgument, `Invalid native asset symbol ${symbol}`, { chainId: this.chainId });
|
|
366
|
+
}
|
|
367
|
+
return this._nativeAsset.decimals;
|
|
368
|
+
}
|
|
369
|
+
let decimals = this.assetDecimalsByIdentifier.get(identifier);
|
|
370
|
+
if (decimals === undefined) {
|
|
371
|
+
decimals = await this._getAssetDecimalsInternal(symbol, identifier);
|
|
372
|
+
this.assetDecimalsByIdentifier.set(identifier, decimals);
|
|
373
|
+
}
|
|
374
|
+
return decimals;
|
|
375
|
+
}
|
|
376
|
+
async _checkMemoRequired(transaction) {
|
|
377
|
+
if (transaction.memo.type !== stellar_sdk_1.MemoNone)
|
|
378
|
+
return;
|
|
379
|
+
const checked = new Set();
|
|
380
|
+
for (const [index, operation] of transaction.operations.entries()) {
|
|
381
|
+
if (!MEMO_REQUIRED_OPERATION_TYPES.has(operation.type))
|
|
382
|
+
continue;
|
|
383
|
+
const destination = StellarChain._muxedToClassic(operation.destination);
|
|
384
|
+
if (checked.has(destination))
|
|
385
|
+
continue;
|
|
386
|
+
checked.add(destination);
|
|
387
|
+
if (destination.startsWith('M'))
|
|
388
|
+
continue;
|
|
389
|
+
let account;
|
|
390
|
+
try {
|
|
391
|
+
account = (await this.asyncHorizonServer.accounts().accountId(destination).call());
|
|
392
|
+
}
|
|
393
|
+
catch (err) {
|
|
394
|
+
if (err instanceof stellar_sdk_1.NotFoundError)
|
|
395
|
+
continue;
|
|
396
|
+
throw err;
|
|
397
|
+
}
|
|
398
|
+
const dataRenamedBySdk = (0, python_pydantic_ts_1.isPydanticDict)(account._links) && 'data' in account._links;
|
|
399
|
+
if (dataRenamedBySdk && !('data_attr' in account))
|
|
400
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidArgument, (0, python_repr_ts_1.pyRepr)('data'));
|
|
401
|
+
const data = dataRenamedBySdk ? account.data_attr : (0, python_builtins_ts_1.pyItem)(account, 'data');
|
|
402
|
+
if (!(0, python_pydantic_ts_1.isPydanticDict)(data)) {
|
|
403
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.RpcError, `'${(0, python_repr_ts_1.pyTypeName)(data)}' object has no attribute 'get'`, { chainId: this.chainId });
|
|
404
|
+
}
|
|
405
|
+
if (data[MEMO_REQUIRED_CONFIG_KEY] === MEMO_REQUIRED_CONFIG_VALUE) {
|
|
406
|
+
throw new stellar_sdk_1.AccountRequiresMemoError('Destination account requires a memo in the transaction.', destination, index);
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
async _submitTransaction(envelope) {
|
|
411
|
+
const horizon = this.asyncHorizonServer;
|
|
412
|
+
await this._checkMemoRequired(envelope);
|
|
413
|
+
const response = await horizon.httpClient.post(horizon.serverURL.clone().segment('transactions').toString(), `tx=${encodeURIComponent(envelope.toEnvelope().toXDR().toString('base64'))}`, { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } });
|
|
414
|
+
return response.data;
|
|
415
|
+
}
|
|
416
|
+
async _loadAccountData(accountId) {
|
|
417
|
+
return this.asyncHorizonServer.accounts().accountId(accountId).call();
|
|
418
|
+
}
|
|
419
|
+
async getAssetBalance(asset, ownerAddress) {
|
|
420
|
+
this.assertStellarAsset(asset);
|
|
421
|
+
StellarChain.validateWalletAddress(ownerAddress);
|
|
422
|
+
const ownerClassicAddress = StellarChain.toClassicAccountId(ownerAddress);
|
|
423
|
+
if (asset.isNative() || asset.isSac()) {
|
|
424
|
+
const accountData = await this._loadAccountData(ownerClassicAddress);
|
|
425
|
+
const balances = (accountData.balances ?? []);
|
|
426
|
+
if (asset.isNative()) {
|
|
427
|
+
const record = accountData;
|
|
428
|
+
const subentryCount = Math.trunc(Number(record.subentry_count ?? 0));
|
|
429
|
+
const numSponsoring = Math.trunc(Number(record.num_sponsoring ?? 0));
|
|
430
|
+
const numSponsored = Math.trunc(Number(record.num_sponsored ?? 0));
|
|
431
|
+
const reserveUnits = 2 + subentryCount + numSponsoring - numSponsored;
|
|
432
|
+
const reservedStroops = BigInt(reserveUnits) * 5000000n;
|
|
433
|
+
for (const b of balances) {
|
|
434
|
+
if (b.asset_type === 'native') {
|
|
435
|
+
const totalStroops = (0, transaction_status_ts_1.hrDecimalToMinorUnits)(new decimal_js_1.Decimal((0, python_builtins_ts_1.pyDecimalString)((0, python_builtins_ts_1.pyItem)(b, 'balance'))), stellar_asset_ts_1.StellarAsset.DECIMALS);
|
|
436
|
+
const availableStroops = totalStroops - reservedStroops;
|
|
437
|
+
return new decimal_js_1.Decimal((0, transaction_status_ts_1.minorUnitsToHrString)(availableStroops < 0n ? 0n : availableStroops, stellar_asset_ts_1.StellarAsset.DECIMALS));
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
return new decimal_js_1.Decimal(0);
|
|
441
|
+
}
|
|
442
|
+
for (const b of balances) {
|
|
443
|
+
if (b.asset_type === 'native')
|
|
444
|
+
continue;
|
|
445
|
+
if (b.asset_code === asset.code && b.asset_issuer === asset.issuer) {
|
|
446
|
+
return new decimal_js_1.Decimal((0, python_builtins_ts_1.pyDecimalString)((0, python_builtins_ts_1.pyItem)(b, 'balance')));
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
return new decimal_js_1.Decimal(0);
|
|
450
|
+
}
|
|
451
|
+
const result = await this._callHostFunction({
|
|
452
|
+
contractId: asset.contractId,
|
|
453
|
+
functionName: 'balance',
|
|
454
|
+
parameters: [new stellar_sdk_1.Address(ownerClassicAddress).toScVal()],
|
|
455
|
+
});
|
|
456
|
+
const balance = scvalToInt128(firstHostFunctionResult(result));
|
|
457
|
+
return new decimal_js_1.Decimal((0, transaction_status_ts_1.minorUnitsToHrString)(balance, asset.decimals));
|
|
458
|
+
}
|
|
459
|
+
async getWalletBalance(ownerAddress) {
|
|
460
|
+
const ownerClassicAddress = StellarChain.toClassicAccountId(ownerAddress);
|
|
461
|
+
const accountData = await this._loadAccountData(ownerClassicAddress);
|
|
462
|
+
const balances = (accountData.balances ?? []);
|
|
463
|
+
const result = new asset_map_ts_1.AssetMap();
|
|
464
|
+
for (const b of balances) {
|
|
465
|
+
if (b.asset_type === 'native') {
|
|
466
|
+
result.set(this._nativeAsset, new decimal_js_1.Decimal((0, python_builtins_ts_1.pyDecimalString)((0, python_builtins_ts_1.pyItem)(b, 'balance'))));
|
|
467
|
+
}
|
|
468
|
+
else {
|
|
469
|
+
const code = b.asset_code;
|
|
470
|
+
const issuer = b.asset_issuer;
|
|
471
|
+
if (code === undefined || code === null || issuer === undefined || issuer === null)
|
|
472
|
+
continue;
|
|
473
|
+
result.set(this.createSacToken(code, issuer), new decimal_js_1.Decimal((0, python_builtins_ts_1.pyDecimalString)((0, python_builtins_ts_1.pyItem)(b, 'balance'))));
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
return result;
|
|
477
|
+
}
|
|
478
|
+
async getTrustLineLimit(walletAddress, asset) {
|
|
479
|
+
this.assertStellarAsset(asset);
|
|
480
|
+
if (asset.isNative()) {
|
|
481
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidArgument, `Cannot get trustline for native XLM asset ${String(asset)}`, { chainId: this.chainId });
|
|
482
|
+
}
|
|
483
|
+
const classicAddress = StellarChain.toClassicAccountId(walletAddress);
|
|
484
|
+
const accountData = await this._loadAccountData(classicAddress);
|
|
485
|
+
const trustLine = { balance: new decimal_js_1.Decimal(0), limit: new decimal_js_1.Decimal(0) };
|
|
486
|
+
for (const b of (accountData.balances ?? [])) {
|
|
487
|
+
if (b.asset_type === 'native')
|
|
488
|
+
continue;
|
|
489
|
+
if (b.asset_code === asset.code && b.asset_issuer === asset.issuer) {
|
|
490
|
+
trustLine.limit = new decimal_js_1.Decimal((0, python_builtins_ts_1.pyDecimalString)('limit' in b ? b.limit : '0'));
|
|
491
|
+
trustLine.balance = new decimal_js_1.Decimal((0, python_builtins_ts_1.pyDecimalString)('balance' in b ? b.balance : '0'));
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
return trustLine;
|
|
495
|
+
}
|
|
496
|
+
createPrerequisiteForReceivableAsset(receiveAsset, receiverAddress) {
|
|
497
|
+
this.assertStellarAsset(receiveAsset);
|
|
498
|
+
if (receiveAsset.chainId !== this.chainId) {
|
|
499
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidArgument, `Invalid chain id ${receiveAsset.chainId} for ${String(receiveAsset)}, expected ${this.chainId}.`, { chainId: this.chainId });
|
|
500
|
+
}
|
|
501
|
+
StellarChain.validateWalletAddress(receiverAddress);
|
|
502
|
+
const receiverClassicAddress = StellarChain.toClassicAccountId(receiverAddress);
|
|
503
|
+
if (receiveAsset.isNative())
|
|
504
|
+
return null;
|
|
505
|
+
if (!receiveAsset.isSac())
|
|
506
|
+
return null;
|
|
507
|
+
return new stellar_transactions_ts_1.StellarChangeTrustLineTransactionPrerequisite({
|
|
508
|
+
chainId: this.chainId,
|
|
509
|
+
code: receiveAsset.code,
|
|
510
|
+
issuer: receiveAsset.issuer,
|
|
511
|
+
limit: new decimal_js_1.Decimal(stellar_asset_ts_1.StellarAsset.TRUST_LINE_MAX_LIMIT),
|
|
512
|
+
walletAddress: receiverClassicAddress,
|
|
513
|
+
});
|
|
514
|
+
}
|
|
515
|
+
buildUnsignedTransaction(req) {
|
|
516
|
+
return new stellar_transactions_ts_1.StellarUnsignedTransaction({
|
|
517
|
+
chainId: this.chainId,
|
|
518
|
+
sourceAccountId: req.sourceAddress,
|
|
519
|
+
operations: req.operations,
|
|
520
|
+
baseFee: req.baseFee ?? null,
|
|
521
|
+
memo: req.memoText ? (0, stellar_transactions_ts_1.stellarTextMemo)(req.memoText) : null,
|
|
522
|
+
});
|
|
523
|
+
}
|
|
524
|
+
buildTokenTransferOperation(req) {
|
|
525
|
+
return stellar_sdk_1.Operation.invokeContractFunction({
|
|
526
|
+
contract: req.asset.contractId,
|
|
527
|
+
function: 'transfer',
|
|
528
|
+
args: [
|
|
529
|
+
new stellar_sdk_1.Address(req.senderAddress).toScVal(),
|
|
530
|
+
new stellar_sdk_1.Address(req.receiverAddress).toScVal(),
|
|
531
|
+
(0, stellar_sdk_1.nativeToScVal)((0, transaction_status_ts_1.hrDecimalToMinorUnits)(new decimal_js_1.Decimal(req.amountHr.toString()), req.asset.decimals), { type: 'i128' }),
|
|
532
|
+
],
|
|
533
|
+
});
|
|
534
|
+
}
|
|
535
|
+
async createTransferTransaction(req) {
|
|
536
|
+
const asset = req.asset;
|
|
537
|
+
this.assertStellarAsset(asset);
|
|
538
|
+
if (asset.chainId !== this.chainId) {
|
|
539
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidArgument, `Invalid chain id ${asset.chainId} for asset ${String(asset)}, expected ${this.chainId}.`, { chainId: this.chainId });
|
|
540
|
+
}
|
|
541
|
+
StellarChain.validateWalletAddress(req.senderAddress);
|
|
542
|
+
const receiverIsContract = stellar_sdk_1.StrKey.isValidContract(req.receiverAddress);
|
|
543
|
+
if (!receiverIsContract) {
|
|
544
|
+
StellarChain.validateWalletAddress(req.receiverAddress);
|
|
545
|
+
}
|
|
546
|
+
const senderClassicAddress = StellarChain.toClassicAccountId(req.senderAddress);
|
|
547
|
+
const receiverTargetAddress = receiverIsContract ? req.receiverAddress : StellarChain.toClassicAccountId(req.receiverAddress);
|
|
548
|
+
const useClassicPayment = (asset.isNative() || asset.isSac()) && !receiverIsContract;
|
|
549
|
+
const memoText = req.memoText ?? null;
|
|
550
|
+
if (!useClassicPayment && memoText) {
|
|
551
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidArgument, `Cannot transfer ${asset.symbol} to ${req.receiverAddress} with a memo: it requires a Soroban \`transfer\` invocation, and Soroban transactions do not support memos.`, { chainId: this.chainId });
|
|
552
|
+
}
|
|
553
|
+
const transferOp = useClassicPayment
|
|
554
|
+
? stellar_sdk_1.Operation.payment({
|
|
555
|
+
source: senderClassicAddress,
|
|
556
|
+
destination: receiverTargetAddress,
|
|
557
|
+
asset: asset.toSdkAsset(),
|
|
558
|
+
amount: (0, stellar_transactions_ts_1.stellarOperationAmount)(req.amountHr, 'amount'),
|
|
559
|
+
})
|
|
560
|
+
: this.buildTokenTransferOperation({
|
|
561
|
+
asset,
|
|
562
|
+
senderAddress: senderClassicAddress,
|
|
563
|
+
receiverAddress: receiverTargetAddress,
|
|
564
|
+
amountHr: req.amountHr,
|
|
565
|
+
});
|
|
566
|
+
const baseFee = await this._resolveGasPricing(req.gasPricing === undefined ? priority_ts_1.FeePriority.NORMAL : req.gasPricing);
|
|
567
|
+
const unsignedTx = new stellar_transactions_ts_1.StellarUnsignedTransaction({
|
|
568
|
+
chainId: this.chainId,
|
|
569
|
+
sourceAccountId: senderClassicAddress,
|
|
570
|
+
operations: [transferOp],
|
|
571
|
+
baseFee,
|
|
572
|
+
memo: memoText ? (0, stellar_transactions_ts_1.stellarTextMemo)(memoText) : null,
|
|
573
|
+
});
|
|
574
|
+
const prerequisites = [];
|
|
575
|
+
if (!receiverIsContract) {
|
|
576
|
+
const prerequisite = this.createPrerequisiteForReceivableAsset(asset, receiverTargetAddress);
|
|
577
|
+
if (prerequisite !== null)
|
|
578
|
+
prerequisites.push(prerequisite);
|
|
579
|
+
}
|
|
580
|
+
return new transaction_prerequisite_ts_1.UnsignedTransactionWithPrerequisites({ prerequisites, transaction: unsignedTx });
|
|
581
|
+
}
|
|
582
|
+
async createExactInSwapTransaction(req) {
|
|
583
|
+
const senderClassicAddress = StellarChain.toClassicAccountId(req.senderAddress);
|
|
584
|
+
const receiverClassicAddress = StellarChain.toClassicAccountId(req.receiverAddress);
|
|
585
|
+
const sendPath = await this.asyncHorizonServer
|
|
586
|
+
.strictSendPaths(req.sendAsset.toSdkAsset(), (0, python_builtins_ts_1.pyDecimalStr)(req.sendAmount.toString()), [req.receiveAsset.toSdkAsset()])
|
|
587
|
+
.call();
|
|
588
|
+
const records = sendPath.records;
|
|
589
|
+
if (records.length === 0) {
|
|
590
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidArgument, 'Cannot find a swap route', { chainId: this.chainId });
|
|
591
|
+
}
|
|
592
|
+
const bestRecord = records[0];
|
|
593
|
+
const path = bestRecord.path.map((p) => p.asset_type === 'native' ? this._nativeAsset.toSdkAsset() : (0, stellar_asset_ts_1.stellarSdkAsset)(p.asset_code, p.asset_issuer));
|
|
594
|
+
const destinationAmount = new PythonDecimal((0, python_builtins_ts_1.pyDecimalString)((0, python_builtins_ts_1.pyItem)(bestRecord, 'destination_amount')));
|
|
595
|
+
const minimumReceiveValue = destinationAmount
|
|
596
|
+
.mul(new PythonDecimal(1).minus(new PythonDecimal(req.slippageTolerancePercent.toString()).div(new PythonDecimal(100))))
|
|
597
|
+
.toDecimalPlaces(req.receiveAsset.decimals, decimal_js_1.Decimal.ROUND_HALF_UP);
|
|
598
|
+
const prerequisite = this.createPrerequisiteForReceivableAsset(req.receiveAsset, receiverClassicAddress);
|
|
599
|
+
const prerequisites = [];
|
|
600
|
+
if (prerequisite !== null)
|
|
601
|
+
prerequisites.push(prerequisite);
|
|
602
|
+
const unsignedTx = new stellar_transactions_ts_1.StellarUnsignedTransaction({
|
|
603
|
+
chainId: this.chainId,
|
|
604
|
+
sourceAccountId: senderClassicAddress,
|
|
605
|
+
operations: [
|
|
606
|
+
stellar_sdk_1.Operation.pathPaymentStrictSend({
|
|
607
|
+
sendAsset: req.sendAsset.toSdkAsset(),
|
|
608
|
+
sendAmount: (0, stellar_transactions_ts_1.stellarOperationAmount)(req.sendAmount, 'send_amount'),
|
|
609
|
+
destAsset: req.receiveAsset.toSdkAsset(),
|
|
610
|
+
destMin: (0, stellar_transactions_ts_1.stellarOperationAmount)(minimumReceiveValue, 'dest_min'),
|
|
611
|
+
path,
|
|
612
|
+
source: senderClassicAddress,
|
|
613
|
+
destination: receiverClassicAddress,
|
|
614
|
+
}),
|
|
615
|
+
],
|
|
616
|
+
});
|
|
617
|
+
return new transaction_prerequisite_ts_1.UnsignedTransactionWithPrerequisites({ prerequisites, transaction: unsignedTx });
|
|
618
|
+
}
|
|
619
|
+
static _muxedToClassic(account) {
|
|
620
|
+
if (account instanceof stellar_sdk_1.MuxedAccount)
|
|
621
|
+
return account.baseAccount().accountId();
|
|
622
|
+
return (0, stellar_transactions_ts_1.toClassicStellarAccountId)(account);
|
|
623
|
+
}
|
|
624
|
+
_balanceChangesFromOperations(tx, opts = {}) {
|
|
625
|
+
const { filteredWallets = null, filteredAssets = null } = opts;
|
|
626
|
+
const includeNative = filteredAssets === null || filteredAssets.some((a) => a.isNative());
|
|
627
|
+
const filteredAssetsByIdentifier = filteredAssets === null ? null : this.identifierIndex(filteredAssets);
|
|
628
|
+
const txSourceClassic = StellarChain._muxedToClassic(tx.source);
|
|
629
|
+
const balanceChanges = new Map();
|
|
630
|
+
const record = (account, sdkAsset, deltaHr) => {
|
|
631
|
+
if (filteredWallets !== null && !(0, python_builtins_ts_1.pyContains)(filteredWallets, account))
|
|
632
|
+
return;
|
|
633
|
+
let stellarAsset;
|
|
634
|
+
if (sdkAsset.isNative()) {
|
|
635
|
+
if (!includeNative)
|
|
636
|
+
return;
|
|
637
|
+
stellarAsset = this._nativeAsset;
|
|
638
|
+
}
|
|
639
|
+
else {
|
|
640
|
+
stellarAsset = this.createSacToken(sdkAsset.getCode(), sdkAsset.getIssuer());
|
|
641
|
+
if (filteredAssetsByIdentifier !== null && !filteredAssetsByIdentifier.has(stellarAsset.identifier))
|
|
642
|
+
return;
|
|
643
|
+
}
|
|
644
|
+
transaction_status_ts_1.AssetBalanceChange.upsert(balanceChanges, account, stellarAsset, transaction_status_ts_1.AssetBalanceChange.fromHr(deltaHr, stellarAsset.decimals));
|
|
645
|
+
};
|
|
646
|
+
const rawOperations = transactionXdrOperations(tx);
|
|
647
|
+
for (const [index, op] of tx.operations.entries()) {
|
|
648
|
+
const opSource = op.source ? StellarChain._muxedToClassic(op.source) : txSourceClassic;
|
|
649
|
+
const body = rawOperations[index].body();
|
|
650
|
+
if (op.type === 'payment') {
|
|
651
|
+
const asset = (0, stellar_asset_ts_1.stellarSdkAssetFromXdr)(body.paymentOp().asset());
|
|
652
|
+
const amountHr = new decimal_js_1.Decimal(op.amount);
|
|
653
|
+
const destination = StellarChain._muxedToClassic(op.destination);
|
|
654
|
+
record(opSource, asset, amountHr.neg());
|
|
655
|
+
record(destination, asset, amountHr);
|
|
656
|
+
}
|
|
657
|
+
else if (op.type === 'pathPaymentStrictSend') {
|
|
658
|
+
const raw = body.pathPaymentStrictSendOp();
|
|
659
|
+
const sendAmountHr = new decimal_js_1.Decimal(op.sendAmount);
|
|
660
|
+
const destMin = new decimal_js_1.Decimal(op.destMin);
|
|
661
|
+
const destination = StellarChain._muxedToClassic(op.destination);
|
|
662
|
+
record(opSource, (0, stellar_asset_ts_1.stellarSdkAssetFromXdr)(raw.sendAsset()), sendAmountHr.neg());
|
|
663
|
+
record(destination, (0, stellar_asset_ts_1.stellarSdkAssetFromXdr)(raw.destAsset()), destMin);
|
|
664
|
+
}
|
|
665
|
+
else if (op.type === 'pathPaymentStrictReceive') {
|
|
666
|
+
const raw = body.pathPaymentStrictReceiveOp();
|
|
667
|
+
const sendMax = new decimal_js_1.Decimal(op.sendMax);
|
|
668
|
+
const destAmount = new decimal_js_1.Decimal(op.destAmount);
|
|
669
|
+
const destination = StellarChain._muxedToClassic(op.destination);
|
|
670
|
+
record(opSource, (0, stellar_asset_ts_1.stellarSdkAssetFromXdr)(raw.sendAsset()), sendMax.neg());
|
|
671
|
+
record(destination, (0, stellar_asset_ts_1.stellarSdkAssetFromXdr)(raw.destAsset()), destAmount);
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
return balanceChanges;
|
|
675
|
+
}
|
|
676
|
+
async _getTransactionDataFromStellarExpert(pagingToken) {
|
|
677
|
+
const url = `${this.stellarExpertApiUrl}/tx/${pagingToken}`;
|
|
678
|
+
const response = await fetch(url, { signal: AbortSignal.timeout(AIOHTTP_DEFAULT_TOTAL_TIMEOUT_MS) });
|
|
679
|
+
return (0, stellar_transactions_ts_1.parseStellarExpertTransactionInfo)(await response.json());
|
|
680
|
+
}
|
|
681
|
+
async getTransactionStatus(txHash, opts) {
|
|
682
|
+
if (opts?.wait || (opts?.confirmations !== undefined && opts.confirmations > 1)) {
|
|
683
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.FeatureNotSupported, 'StellarChain.getTransactionStatus does not honor wait/confirmations opts (would silently return immediately). Poll consumer-side or omit the opts.', { chainId: this.chainId });
|
|
684
|
+
}
|
|
685
|
+
const filteredWallets = opts?.filteredWallets === undefined || opts.filteredWallets === null ? null : (0, python_builtins_ts_1.pyStringContainer)(opts.filteredWallets);
|
|
686
|
+
const filteredAssets = opts?.filteredAssets === undefined || opts.filteredAssets === null ? null : [...opts.filteredAssets];
|
|
687
|
+
if (Array.isArray(txHash)) {
|
|
688
|
+
return runBatch(txHash, (hash) => this.getTransactionStatusOnce(hash, filteredWallets, filteredAssets));
|
|
689
|
+
}
|
|
690
|
+
return this.getTransactionStatusOnce(txHash, filteredWallets, filteredAssets);
|
|
691
|
+
}
|
|
692
|
+
async getTransactionStatusOnce(txHash, filteredWallets, filteredAssets) {
|
|
693
|
+
let txResp;
|
|
694
|
+
try {
|
|
695
|
+
txResp = await this.asyncHorizonServer.transactions().transaction(txHash).call();
|
|
696
|
+
}
|
|
697
|
+
catch (err) {
|
|
698
|
+
if (err instanceof stellar_sdk_1.NotFoundError) {
|
|
699
|
+
return stellar_transaction_status_ts_1.StellarTransactionStatus.notFound(this.chainId, { code: 'NOT_FOUND', reason: err.message });
|
|
700
|
+
}
|
|
701
|
+
throw this.rpcError(`Horizon transaction lookup failed for ${txHash}`, err, txHash, this.horizonUrl);
|
|
702
|
+
}
|
|
703
|
+
const ledger = await this.asyncHorizonServer.ledgers().ledger(txResp.ledger_attr).call();
|
|
704
|
+
const inclusionAt = new Date(ledger.closed_at);
|
|
705
|
+
const raw = txResp;
|
|
706
|
+
const pagingToken = String(raw.paging_token);
|
|
707
|
+
const successful = Boolean(raw.successful);
|
|
708
|
+
const envelopeXdr = String(raw.envelope_xdr);
|
|
709
|
+
let fees = null;
|
|
710
|
+
if ('fee_charged' in raw) {
|
|
711
|
+
const feePayer = String(raw.fee_account);
|
|
712
|
+
const feeCharged = Math.trunc(Number(raw.fee_charged ?? raw.max_fee ?? '0'));
|
|
713
|
+
fees = new stellar_transactions_ts_1.StellarTransactionFees({ feeStroops: feeCharged, feePayer });
|
|
714
|
+
}
|
|
715
|
+
const txEnvelope = stellar_sdk_1.xdr.TransactionEnvelope.fromXDR(envelopeXdr, 'base64');
|
|
716
|
+
let operationsXdr;
|
|
717
|
+
let memoXdr;
|
|
718
|
+
switch (txEnvelope.switch().name) {
|
|
719
|
+
case 'envelopeTypeTxFeeBump': {
|
|
720
|
+
const inner = txEnvelope.feeBump().tx().innerTx().v1().tx();
|
|
721
|
+
operationsXdr = inner.operations();
|
|
722
|
+
memoXdr = inner.memo();
|
|
723
|
+
break;
|
|
724
|
+
}
|
|
725
|
+
case 'envelopeTypeTxV0': {
|
|
726
|
+
const inner = txEnvelope.v0().tx();
|
|
727
|
+
operationsXdr = inner.operations();
|
|
728
|
+
memoXdr = inner.memo();
|
|
729
|
+
break;
|
|
730
|
+
}
|
|
731
|
+
case 'envelopeTypeTx': {
|
|
732
|
+
const inner = txEnvelope.v1().tx();
|
|
733
|
+
operationsXdr = inner.operations();
|
|
734
|
+
memoXdr = inner.memo();
|
|
735
|
+
break;
|
|
736
|
+
}
|
|
737
|
+
default:
|
|
738
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.TransactionDecodeFailed, `Unknown envelope type: ${txEnvelope.switch().name}`, {
|
|
739
|
+
chainId: this.chainId,
|
|
740
|
+
txHash,
|
|
741
|
+
});
|
|
742
|
+
}
|
|
743
|
+
const memo = stellar_sdk_1.Memo.fromXDRObject(memoXdr);
|
|
744
|
+
if (!successful) {
|
|
745
|
+
const extras = raw.extras;
|
|
746
|
+
const resultCodes = extras?.result_codes || raw.result_codes;
|
|
747
|
+
const errorMessage = resultCodes ? `Stellar transaction failed: ${(0, python_repr_ts_1.pyRepr)(resultCodes)}` : 'Stellar transaction failed';
|
|
748
|
+
return stellar_transaction_status_ts_1.StellarTransactionStatus.failed({
|
|
749
|
+
chainId: this.chainId,
|
|
750
|
+
inclusionAt,
|
|
751
|
+
error: { code: 'FAILED', reason: errorMessage },
|
|
752
|
+
fees,
|
|
753
|
+
memo,
|
|
754
|
+
});
|
|
755
|
+
}
|
|
756
|
+
const operations = operationsXdr.map((op) => stellar_sdk_1.Operation.fromXDRObject(op));
|
|
757
|
+
const isContractCall = operations.length === 1 && operations[0].type === 'invokeHostFunction';
|
|
758
|
+
if (isContractCall) {
|
|
759
|
+
if (operations.length > 1) {
|
|
760
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.TransactionDecodeFailed, `Soroban contract call cannot have more than 1 operation ${txHash}`, { chainId: this.chainId, txHash });
|
|
761
|
+
}
|
|
762
|
+
let sorobanTxResp;
|
|
763
|
+
try {
|
|
764
|
+
const reply = await this._sorobanRpc('getTransaction', { hash: txHash });
|
|
765
|
+
sorobanTxResp = isGetTransactionResponse(reply) ? reply : null;
|
|
766
|
+
}
|
|
767
|
+
catch {
|
|
768
|
+
sorobanTxResp = null;
|
|
769
|
+
}
|
|
770
|
+
const sorobanDiagnosticEvents = sorobanTxResp?.events?.diagnosticEventsXdr;
|
|
771
|
+
const hasSorobanTxResp = sorobanTxResp !== null &&
|
|
772
|
+
sorobanTxResp.status !== stellar_sdk_1.rpc.Api.GetTransactionStatus.NOT_FOUND &&
|
|
773
|
+
sorobanDiagnosticEvents !== undefined &&
|
|
774
|
+
sorobanDiagnosticEvents !== null;
|
|
775
|
+
let stellarExpertResult = null;
|
|
776
|
+
if (!hasSorobanTxResp) {
|
|
777
|
+
try {
|
|
778
|
+
stellarExpertResult = await this._getTransactionDataFromStellarExpert(pagingToken);
|
|
779
|
+
}
|
|
780
|
+
catch {
|
|
781
|
+
stellarExpertResult = null;
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
if (hasSorobanTxResp && sorobanTxResp !== null) {
|
|
785
|
+
const balanceChanges = await this.getBalanceChangesFromDiagnosisEvents(sorobanDiagnosticEvents.map((d) => stellar_sdk_1.xdr.DiagnosticEvent.fromXDR(d, 'base64')), { filteredWallets, filteredAssets });
|
|
786
|
+
this.upsertFee(balanceChanges, fees);
|
|
787
|
+
if (sorobanTxResp.status === stellar_sdk_1.rpc.Api.GetTransactionStatus.SUCCESS) {
|
|
788
|
+
return stellar_transaction_status_ts_1.StellarTransactionStatus.successful({ chainId: this.chainId, inclusionAt, balanceChanges, fees, memo });
|
|
789
|
+
}
|
|
790
|
+
return stellar_transaction_status_ts_1.StellarTransactionStatus.failed({
|
|
791
|
+
chainId: this.chainId,
|
|
792
|
+
inclusionAt,
|
|
793
|
+
error: {
|
|
794
|
+
code: String(sorobanTxResp.status),
|
|
795
|
+
reason: `Stellar soroban transaction failed: GetTransactionStatus.${sorobanTxResp.status}`,
|
|
796
|
+
},
|
|
797
|
+
fees,
|
|
798
|
+
memo,
|
|
799
|
+
});
|
|
800
|
+
}
|
|
801
|
+
else if (stellarExpertResult !== null) {
|
|
802
|
+
const txEnv = (0, stellar_transactions_ts_1.parseSignedStellarEnvelope)(stellarExpertResult.body, this.networkPassphrase);
|
|
803
|
+
const txMeta = stellar_sdk_1.xdr.TransactionMeta.fromXDR(stellarExpertResult.meta, 'base64');
|
|
804
|
+
const ops = txEnv.operations;
|
|
805
|
+
if (!(ops.length === 1 && ops[0].type === 'invokeHostFunction')) {
|
|
806
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.TransactionDecodeFailed, `Stellar expert returned envelope is not contract call, operations: ${ops.map((o) => o.type).join(',')}`, { chainId: this.chainId, txHash });
|
|
807
|
+
}
|
|
808
|
+
if (txMeta.switch() !== 4) {
|
|
809
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.TransactionDecodeFailed, `Unsupported transaction metadata version ${txMeta.switch()}`, {
|
|
810
|
+
chainId: this.chainId,
|
|
811
|
+
txHash,
|
|
812
|
+
});
|
|
813
|
+
}
|
|
814
|
+
const txResult = stellar_sdk_1.xdr.TransactionResult.fromXDR(stellarExpertResult.result, 'base64');
|
|
815
|
+
const balanceChanges = await this.getBalanceChangesFromDiagnosisEvents(txMeta.v4().diagnosticEvents(), { filteredWallets, filteredAssets });
|
|
816
|
+
this.upsertFee(balanceChanges, fees);
|
|
817
|
+
const resultCode = txResult.result().switch();
|
|
818
|
+
if (resultCode.name === 'txSuccess') {
|
|
819
|
+
return stellar_transaction_status_ts_1.StellarTransactionStatus.successful({ chainId: this.chainId, inclusionAt, balanceChanges, fees, memo });
|
|
820
|
+
}
|
|
821
|
+
return stellar_transaction_status_ts_1.StellarTransactionStatus.failed({
|
|
822
|
+
chainId: this.chainId,
|
|
823
|
+
inclusionAt,
|
|
824
|
+
error: { code: resultCode.name, reason: `Stellar transaction failed: ${resultCode.value}` },
|
|
825
|
+
fees,
|
|
826
|
+
memo,
|
|
827
|
+
});
|
|
828
|
+
}
|
|
829
|
+
else {
|
|
830
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.RpcError, `Cannot get status of transaction from soroban rpc and stellar expert for tx hash ${txHash}`, { chainId: this.chainId, txHash });
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
const balanceChanges = await this._effectsToBalanceChanges(txHash, { filteredWallets, filteredAssets });
|
|
834
|
+
this.upsertFee(balanceChanges, fees);
|
|
835
|
+
return stellar_transaction_status_ts_1.StellarTransactionStatus.successful({ chainId: this.chainId, inclusionAt, balanceChanges, fees, memo });
|
|
836
|
+
}
|
|
837
|
+
async _effectsToBalanceChanges(txHash, opts = {}) {
|
|
838
|
+
const { filteredWallets = null, filteredAssets = null } = opts;
|
|
839
|
+
const includeNative = filteredAssets === null || filteredAssets.some((a) => a.isNative());
|
|
840
|
+
const filteredAssetsByIdentifier = filteredAssets === null ? null : this.identifierIndex(filteredAssets);
|
|
841
|
+
const balanceChanges = new Map();
|
|
842
|
+
const page = await this.asyncHorizonServer.effects().forTransaction(txHash).limit(200).call();
|
|
843
|
+
const records = (page.records ?? []);
|
|
844
|
+
const buildAsset = (rec) => {
|
|
845
|
+
if (rec.asset_type === 'native') {
|
|
846
|
+
return includeNative ? this._nativeAsset : null;
|
|
847
|
+
}
|
|
848
|
+
const code = rec.asset_code;
|
|
849
|
+
const issuer = rec.asset_issuer;
|
|
850
|
+
if (code === undefined || code === null || issuer === undefined || issuer === null)
|
|
851
|
+
return null;
|
|
852
|
+
const stellarAsset = this.createSacToken(code, issuer);
|
|
853
|
+
if (filteredAssetsByIdentifier !== null && !filteredAssetsByIdentifier.has(stellarAsset.identifier))
|
|
854
|
+
return null;
|
|
855
|
+
return stellarAsset;
|
|
856
|
+
};
|
|
857
|
+
const operationId = (rec) => String(rec.id ?? '').split('-')[0];
|
|
858
|
+
const nativelyCreditedByOperation = new Set();
|
|
859
|
+
for (const rec of records) {
|
|
860
|
+
if (rec.type === 'account_credited' && rec.asset_type === 'native') {
|
|
861
|
+
if (rec.account)
|
|
862
|
+
nativelyCreditedByOperation.add(`${operationId(rec)}|${rec.account}`);
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
for (const rec of records) {
|
|
866
|
+
const eType = rec.type;
|
|
867
|
+
const wallet = eType === 'contract_credited' || eType === 'contract_debited' ? rec.contract : rec.account;
|
|
868
|
+
if (!wallet)
|
|
869
|
+
continue;
|
|
870
|
+
if (filteredWallets !== null && !(0, python_builtins_ts_1.pyContains)(filteredWallets, wallet))
|
|
871
|
+
continue;
|
|
872
|
+
if (eType === 'account_credited' || eType === 'contract_credited') {
|
|
873
|
+
const stellarAsset = buildAsset(rec);
|
|
874
|
+
if (stellarAsset === null)
|
|
875
|
+
continue;
|
|
876
|
+
transaction_status_ts_1.AssetBalanceChange.upsert(balanceChanges, wallet, stellarAsset, transaction_status_ts_1.AssetBalanceChange.fromHr(new decimal_js_1.Decimal((0, python_builtins_ts_1.pyDecimalString)((0, python_builtins_ts_1.pyItem)(rec, 'amount'))), stellarAsset.decimals));
|
|
877
|
+
}
|
|
878
|
+
else if (eType === 'account_debited' || eType === 'contract_debited') {
|
|
879
|
+
const stellarAsset = buildAsset(rec);
|
|
880
|
+
if (stellarAsset === null)
|
|
881
|
+
continue;
|
|
882
|
+
transaction_status_ts_1.AssetBalanceChange.upsert(balanceChanges, wallet, stellarAsset, transaction_status_ts_1.AssetBalanceChange.fromHr(new decimal_js_1.Decimal((0, python_builtins_ts_1.pyDecimalString)((0, python_builtins_ts_1.pyItem)(rec, 'amount'))).neg(), stellarAsset.decimals));
|
|
883
|
+
}
|
|
884
|
+
else if (eType === 'account_created') {
|
|
885
|
+
if (!includeNative)
|
|
886
|
+
continue;
|
|
887
|
+
const stellarAsset = this._nativeAsset;
|
|
888
|
+
const startingBalance = new decimal_js_1.Decimal((0, python_builtins_ts_1.pyDecimalString)((0, python_builtins_ts_1.pyItem)(rec, 'starting_balance')));
|
|
889
|
+
if (nativelyCreditedByOperation.has(`${operationId(rec)}|${wallet}`))
|
|
890
|
+
continue;
|
|
891
|
+
transaction_status_ts_1.AssetBalanceChange.upsert(balanceChanges, wallet, stellarAsset, transaction_status_ts_1.AssetBalanceChange.fromHr(startingBalance, stellarAsset.decimals));
|
|
892
|
+
}
|
|
893
|
+
}
|
|
894
|
+
return balanceChanges;
|
|
895
|
+
}
|
|
896
|
+
static getTransfersFromDiagnosisEvents(diagnosisEvents) {
|
|
897
|
+
const transfers = [];
|
|
898
|
+
for (const d of diagnosisEvents) {
|
|
899
|
+
const event = d.event();
|
|
900
|
+
const contractId = event.contractId();
|
|
901
|
+
const topics = event.body().v0().topics();
|
|
902
|
+
if (contractId && topics.length > 0) {
|
|
903
|
+
const tokenContractId = stellar_sdk_1.StrKey.encodeContract(contractId);
|
|
904
|
+
if (topics[0].switch().name === 'scvSymbol') {
|
|
905
|
+
const topic0 = topics[0].sym().toString();
|
|
906
|
+
if (topic0 === 'transfer') {
|
|
907
|
+
if (topics.length < 3)
|
|
908
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.TransactionDecodeFailed, 'list index out of range');
|
|
909
|
+
const transferFrom = stellar_sdk_1.Address.fromScVal(topics[1]).toString();
|
|
910
|
+
const transferTo = stellar_sdk_1.Address.fromScVal(topics[2]).toString();
|
|
911
|
+
let contractSacCode;
|
|
912
|
+
let contractSacIssuer;
|
|
913
|
+
if (topics.length > 3) {
|
|
914
|
+
const tokenIdentifier = scvalToUtf8String(topics[3]);
|
|
915
|
+
if (tokenIdentifier === 'native') {
|
|
916
|
+
contractSacCode = 'XLM';
|
|
917
|
+
contractSacIssuer = null;
|
|
918
|
+
}
|
|
919
|
+
else if (tokenIdentifier.includes(':')) {
|
|
920
|
+
const splitted = tokenIdentifier.split(':');
|
|
921
|
+
contractSacCode = splitted[0];
|
|
922
|
+
contractSacIssuer = splitted[1];
|
|
923
|
+
}
|
|
924
|
+
else {
|
|
925
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.TransactionDecodeFailed, `Invalid token identifier ${tokenIdentifier}`);
|
|
926
|
+
}
|
|
927
|
+
}
|
|
928
|
+
else {
|
|
929
|
+
contractSacCode = null;
|
|
930
|
+
contractSacIssuer = null;
|
|
931
|
+
}
|
|
932
|
+
const transferAmountMr = scvalToInt128(event.body().v0().data());
|
|
933
|
+
transfers.push({
|
|
934
|
+
fromAccount: transferFrom,
|
|
935
|
+
toAccount: transferTo,
|
|
936
|
+
tokenContractId,
|
|
937
|
+
tokenContractSacCode: contractSacCode,
|
|
938
|
+
tokenContractSacIssuer: contractSacIssuer,
|
|
939
|
+
amountMr: transferAmountMr,
|
|
940
|
+
});
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
}
|
|
944
|
+
}
|
|
945
|
+
return transfers;
|
|
946
|
+
}
|
|
947
|
+
async getBalanceChangesFromDiagnosisEvents(diagnosisEvents, opts = {}) {
|
|
948
|
+
const { filteredWallets = null, filteredAssets = null } = opts;
|
|
949
|
+
const tokenTransfers = StellarChain.getTransfersFromDiagnosisEvents(diagnosisEvents);
|
|
950
|
+
const balanceChanges = new Map();
|
|
951
|
+
for (const t of tokenTransfers) {
|
|
952
|
+
const asset = t.tokenContractSacCode !== null
|
|
953
|
+
? this.createSacToken(t.tokenContractSacCode, t.tokenContractSacIssuer)
|
|
954
|
+
: await this.createNonSacToken(t.tokenContractId);
|
|
955
|
+
if (filteredAssets !== null && !filteredAssets.some((a) => a.strictEquals(asset)))
|
|
956
|
+
continue;
|
|
957
|
+
if (filteredWallets === null || (0, python_builtins_ts_1.pyContains)(filteredWallets, t.fromAccount)) {
|
|
958
|
+
transaction_status_ts_1.AssetBalanceChange.upsert(balanceChanges, t.fromAccount, asset, transaction_status_ts_1.AssetBalanceChange.fromMr(-t.amountMr, asset.decimals));
|
|
959
|
+
}
|
|
960
|
+
if (filteredWallets === null || (0, python_builtins_ts_1.pyContains)(filteredWallets, t.toAccount)) {
|
|
961
|
+
transaction_status_ts_1.AssetBalanceChange.upsert(balanceChanges, t.toAccount, asset, transaction_status_ts_1.AssetBalanceChange.fromMr(t.amountMr, asset.decimals));
|
|
962
|
+
}
|
|
963
|
+
}
|
|
964
|
+
return balanceChanges;
|
|
965
|
+
}
|
|
966
|
+
async supportsFullTransactionSimulation(unsignedTransaction) {
|
|
967
|
+
if (!(unsignedTransaction instanceof stellar_transactions_ts_1.StellarUnsignedTransaction)) {
|
|
968
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidArgument, 'Expected StellarUnsignedTransaction', { chainId: this.chainId });
|
|
969
|
+
}
|
|
970
|
+
return true;
|
|
971
|
+
}
|
|
972
|
+
async simulateTransaction(req) {
|
|
973
|
+
const transaction = req.transaction;
|
|
974
|
+
if (!(transaction instanceof stellar_transactions_ts_1.StellarUnsignedTransaction)) {
|
|
975
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidArgument, `Invalid transaction: ${String(transaction)}, expected StellarUnsignedTransaction.`, { chainId: this.chainId });
|
|
976
|
+
}
|
|
977
|
+
const filteredWallets = req.filteredWallets === undefined || req.filteredWallets === null ? null : (0, python_builtins_ts_1.pyStringContainer)(req.filteredWallets);
|
|
978
|
+
const filteredAssets = req.filteredAssets === undefined || req.filteredAssets === null ? null : [...req.filteredAssets];
|
|
979
|
+
const envelope = await transaction.buildTransactionEnvelope(this);
|
|
980
|
+
if (transaction.isSorobanInvokeContractTransaction) {
|
|
981
|
+
const sim = await (0, stellar_transactions_ts_1.simulateSorobanTransaction)(envelope, this);
|
|
982
|
+
if (sim.error) {
|
|
983
|
+
return new stellar_transactions_ts_1.StellarTransactionSimulationResult({
|
|
984
|
+
chainId: this.chainId,
|
|
985
|
+
statusType: transaction_simulation_ts_1.TransactionSimulationStatusTypes.Failed,
|
|
986
|
+
balanceChanges: new Map(),
|
|
987
|
+
error: new Error(sim.error),
|
|
988
|
+
});
|
|
989
|
+
}
|
|
990
|
+
if (sim.events === null) {
|
|
991
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.RpcError, "'NoneType' object is not iterable", { chainId: this.chainId });
|
|
992
|
+
}
|
|
993
|
+
const balanceChanges = await this.getBalanceChangesFromDiagnosisEvents(sim.events.map((event) => stellar_sdk_1.xdr.DiagnosticEvent.fromXDR(event, 'base64')), { filteredWallets, filteredAssets });
|
|
994
|
+
return new stellar_transactions_ts_1.StellarTransactionSimulationResult({
|
|
995
|
+
chainId: this.chainId,
|
|
996
|
+
statusType: transaction_simulation_ts_1.TransactionSimulationStatusTypes.Success,
|
|
997
|
+
balanceChanges,
|
|
998
|
+
error: null,
|
|
999
|
+
fees: sim.minResourceFee !== null
|
|
1000
|
+
? new stellar_transactions_ts_1.StellarTransactionFees({
|
|
1001
|
+
feeStroops: Number(sim.minResourceFee),
|
|
1002
|
+
feePayer: StellarChain._muxedToClassic(envelope.source),
|
|
1003
|
+
})
|
|
1004
|
+
: null,
|
|
1005
|
+
});
|
|
1006
|
+
}
|
|
1007
|
+
try {
|
|
1008
|
+
const balanceChanges = this._balanceChangesFromOperations(envelope, { filteredWallets, filteredAssets });
|
|
1009
|
+
const memo = envelope.memo;
|
|
1010
|
+
const feePayer = StellarChain._muxedToClassic(envelope.source);
|
|
1011
|
+
const feeStroops = Math.trunc(Number(envelope.fee));
|
|
1012
|
+
const fees = new stellar_transactions_ts_1.StellarTransactionFees({ feeStroops, feePayer });
|
|
1013
|
+
transaction_status_ts_1.AssetBalanceChange.upsert(balanceChanges, feePayer, this._nativeAsset, transaction_status_ts_1.AssetBalanceChange.fromMr(-BigInt(feeStroops), stellar_asset_ts_1.StellarAsset.DECIMALS));
|
|
1014
|
+
return new stellar_transactions_ts_1.StellarTransactionSimulationResult({
|
|
1015
|
+
chainId: this.chainId,
|
|
1016
|
+
statusType: transaction_simulation_ts_1.TransactionSimulationStatusTypes.Success,
|
|
1017
|
+
balanceChanges,
|
|
1018
|
+
error: null,
|
|
1019
|
+
fees,
|
|
1020
|
+
memo,
|
|
1021
|
+
});
|
|
1022
|
+
}
|
|
1023
|
+
catch (err) {
|
|
1024
|
+
return new stellar_transactions_ts_1.StellarTransactionSimulationResult({
|
|
1025
|
+
chainId: this.chainId,
|
|
1026
|
+
statusType: transaction_simulation_ts_1.TransactionSimulationStatusTypes.Failed,
|
|
1027
|
+
balanceChanges: new Map(),
|
|
1028
|
+
error: err instanceof Error ? err : new Error(String(err)),
|
|
1029
|
+
});
|
|
1030
|
+
}
|
|
1031
|
+
}
|
|
1032
|
+
async broadcastSignedTransaction(signedTransaction) {
|
|
1033
|
+
if (!(signedTransaction instanceof stellar_transactions_ts_1.StellarSignedTransaction)) {
|
|
1034
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidArgument, `Invalid transaction ${String(signedTransaction)}, expected StellarSignedTransaction.`, { chainId: this.chainId });
|
|
1035
|
+
}
|
|
1036
|
+
if (this.chainId !== signedTransaction.chainId) {
|
|
1037
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidArgument, `Invalid chain for signed transaction with chain id ${signedTransaction.chainId}, expected ${this.chainId}.`, { chainId: this.chainId });
|
|
1038
|
+
}
|
|
1039
|
+
const envelope = (0, stellar_transactions_ts_1.parseSignedStellarEnvelope)(signedTransaction.signedXdr, this.networkPassphrase);
|
|
1040
|
+
try {
|
|
1041
|
+
const response = await this._submitTransaction(envelope);
|
|
1042
|
+
if (response === null || typeof response !== 'object' || !('hash' in response)) {
|
|
1043
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.RpcError, (0, python_repr_ts_1.pyRepr)('hash'), { chainId: this.chainId, txHash: signedTransaction.txHash });
|
|
1044
|
+
}
|
|
1045
|
+
return new stellar_transactions_ts_1.StellarBroadcastTransactionResponse({ chain: this, txHash: response.hash });
|
|
1046
|
+
}
|
|
1047
|
+
catch (err) {
|
|
1048
|
+
return new stellar_transactions_ts_1.StellarBroadcastTransactionResponse({
|
|
1049
|
+
chain: this,
|
|
1050
|
+
txHash: signedTransaction.txHash,
|
|
1051
|
+
broadcastError: err instanceof Error ? err : new Error(String(err)),
|
|
1052
|
+
});
|
|
1053
|
+
}
|
|
1054
|
+
}
|
|
1055
|
+
static verifySignature(publicKey, message, signedMessage) {
|
|
1056
|
+
if (!(signedMessage instanceof StellarSignedMessage)) {
|
|
1057
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidArgument, `StellarChain expected a StellarSignedMessage, got ${(0, python_repr_ts_1.pyTypeRepr)(signedMessage)}`);
|
|
1058
|
+
}
|
|
1059
|
+
try {
|
|
1060
|
+
return stellar_sdk_1.Keypair.fromPublicKey(String(publicKey)).verify(stellarMessageHash(message), Buffer.from((0, bytes_from_hex_ts_1.bytesFromHex)(signedMessage.signature)));
|
|
1061
|
+
}
|
|
1062
|
+
catch {
|
|
1063
|
+
return false;
|
|
1064
|
+
}
|
|
1065
|
+
}
|
|
1066
|
+
verifySignature(publicKey, message, signedMessage) {
|
|
1067
|
+
return StellarChain.verifySignature(publicKey, message, signedMessage);
|
|
1068
|
+
}
|
|
1069
|
+
async getAccountNextSequence(walletAddress) {
|
|
1070
|
+
const classicAddress = StellarChain.toClassicAccountId(walletAddress);
|
|
1071
|
+
const account = await (0, stellar_transactions_ts_1.loadStellarAccount)(this, classicAddress);
|
|
1072
|
+
return BigInt(account.sequenceNumber()) + 1n;
|
|
1073
|
+
}
|
|
1074
|
+
async getBalance(owner, tokenIdentifier) {
|
|
1075
|
+
const asset = await this.resolveAsset(tokenIdentifier);
|
|
1076
|
+
const balance = await this.getAssetBalance(asset, owner);
|
|
1077
|
+
return (0, transaction_status_ts_1.hrDecimalToMinorUnits)(balance, asset.decimals);
|
|
1078
|
+
}
|
|
1079
|
+
async createTransferUnsignedTransaction(req) {
|
|
1080
|
+
if (!req.from) {
|
|
1081
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidArgument, 'Stellar transfers require an explicit `from` (no implicit signer)', {
|
|
1082
|
+
chainId: this.chainId,
|
|
1083
|
+
});
|
|
1084
|
+
}
|
|
1085
|
+
if (req.isFullBalance === true) {
|
|
1086
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidArgument, 'CreateTransferRequest.isFullBalance is not supported on StellarChain — pass `amount` or `amountHr` explicitly.', { chainId: this.chainId });
|
|
1087
|
+
}
|
|
1088
|
+
const asset = await this.resolveAsset(req.tokenIdentifier);
|
|
1089
|
+
const resolved = (0, chain_base_ts_1.resolveTransferAmount)(req, asset.decimals);
|
|
1090
|
+
if (resolved.kind !== 'exact') {
|
|
1091
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidArgument, 'Stellar transfers require an explicit amount', { chainId: this.chainId });
|
|
1092
|
+
}
|
|
1093
|
+
const bundle = await this.createTransferTransaction({
|
|
1094
|
+
asset,
|
|
1095
|
+
amountHr: new decimal_js_1.Decimal((0, transaction_status_ts_1.minorUnitsToHrString)(resolved.amountMr, asset.decimals)),
|
|
1096
|
+
senderAddress: req.from,
|
|
1097
|
+
receiverAddress: req.to,
|
|
1098
|
+
memoText: req.memo ?? null,
|
|
1099
|
+
gasPricing: req.gasPricing,
|
|
1100
|
+
});
|
|
1101
|
+
for (const prerequisite of bundle.prerequisites) {
|
|
1102
|
+
if (await this.isPrerequisiteAlreadyMet(prerequisite))
|
|
1103
|
+
continue;
|
|
1104
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidArgument, `Stellar transfer to ${req.to} needs a prerequisite the receiver must handle first (${prerequisite.constructor.name}); createTransferUnsignedTransaction cannot return it. Use createTransferTransaction and handle the prerequisite with the receiver's wallet.`, { chainId: this.chainId, address: req.to });
|
|
1105
|
+
}
|
|
1106
|
+
return bundle.transaction;
|
|
1107
|
+
}
|
|
1108
|
+
async isPrerequisiteAlreadyMet(prerequisite) {
|
|
1109
|
+
if (!(prerequisite instanceof stellar_transactions_ts_1.StellarChangeTrustLineTransactionPrerequisite))
|
|
1110
|
+
return false;
|
|
1111
|
+
try {
|
|
1112
|
+
const current = await this.getTrustLineLimit(prerequisite.walletAddress, this.createSacToken(prerequisite.code, prerequisite.issuer));
|
|
1113
|
+
return current.limit.gte(prerequisite.limit);
|
|
1114
|
+
}
|
|
1115
|
+
catch (err) {
|
|
1116
|
+
if (err instanceof stellar_sdk_1.NotFoundError)
|
|
1117
|
+
return false;
|
|
1118
|
+
throw err;
|
|
1119
|
+
}
|
|
1120
|
+
}
|
|
1121
|
+
async broadcast(signed, opts) {
|
|
1122
|
+
if (opts && opts.signal !== undefined) {
|
|
1123
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.FeatureNotSupported, "Stellar broadcast: signal is not honored (silently ignoring would let a caller conclude 'not sent' while the tx still lands)", { chainId: this.chainId });
|
|
1124
|
+
}
|
|
1125
|
+
const signedTransaction = this.parseSignedInput(signed);
|
|
1126
|
+
const response = await this.broadcastSignedTransaction(signedTransaction);
|
|
1127
|
+
const error = response.broadcastError;
|
|
1128
|
+
if (error === null) {
|
|
1129
|
+
const signedHash = signedTransaction.txHash.toLowerCase();
|
|
1130
|
+
if (typeof response.txHash !== 'string' || response.txHash.toLowerCase() !== signedHash) {
|
|
1131
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.RpcError, `Horizon answered hash ${(0, python_repr_ts_1.pyRepr)(response.txHash)} for the signed transaction ${signedTransaction.txHash}`, { chainId: this.chainId, txHash: signedTransaction.txHash });
|
|
1132
|
+
}
|
|
1133
|
+
return signedHash;
|
|
1134
|
+
}
|
|
1135
|
+
const rpcUrl = this.horizonUrl;
|
|
1136
|
+
if (error instanceof stellar_sdk_1.AccountRequiresMemoError) {
|
|
1137
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.BroadcastRejected, `Stellar broadcast refused before submission on ${this.name}: destination ${error.accountId} requires a memo (SEP-29, operation ${error.operationIndex})`, { chainId: this.chainId, txHash: response.txHash, address: error.accountId }, error);
|
|
1138
|
+
}
|
|
1139
|
+
const rejection = horizonSubmissionRejection(error);
|
|
1140
|
+
if (rejection !== null) {
|
|
1141
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.BroadcastRejected, (0, errors_ts_1.sanitizeMessage)(`Stellar broadcast rejected on ${this.name}: ${describeHorizonRejection(rejection, error)}`, rpcUrl), { chainId: this.chainId, txHash: response.txHash }, (0, errors_ts_1.sanitizeCause)(error, rpcUrl));
|
|
1142
|
+
}
|
|
1143
|
+
throw this.rpcError(`Stellar broadcast failed on ${this.name}`, error, response.txHash, rpcUrl);
|
|
1144
|
+
}
|
|
1145
|
+
async getChainTipHeight() {
|
|
1146
|
+
const page = await this.asyncHorizonServer.ledgers().order('desc').limit(1).call();
|
|
1147
|
+
return Number(page.records[0].sequence);
|
|
1148
|
+
}
|
|
1149
|
+
async verifyMessageSignature(req) {
|
|
1150
|
+
try {
|
|
1151
|
+
return StellarChain.verifySignature(req.signer, req.message, new StellarSignedMessage(req.signature));
|
|
1152
|
+
}
|
|
1153
|
+
catch {
|
|
1154
|
+
return false;
|
|
1155
|
+
}
|
|
1156
|
+
}
|
|
1157
|
+
parseSignedInput(signed) {
|
|
1158
|
+
if (typeof signed === 'string') {
|
|
1159
|
+
const trimmed = signed.trim();
|
|
1160
|
+
if (trimmed.startsWith('{')) {
|
|
1161
|
+
const payload = (0, transaction_json_ts_1.coerceJsonDict)(trimmed);
|
|
1162
|
+
if (payload[transaction_json_ts_1.JSON_TRANSACTION_TYPE_KEY] === stellar_transactions_ts_1.StellarSignedTransaction.JSON_TYPE) {
|
|
1163
|
+
return stellar_transactions_ts_1.StellarSignedTransaction.fromJson(payload);
|
|
1164
|
+
}
|
|
1165
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidArgument, 'Stellar broadcast: JSON input must be a StellarSignedTransaction payload', {
|
|
1166
|
+
chainId: this.chainId,
|
|
1167
|
+
});
|
|
1168
|
+
}
|
|
1169
|
+
return new stellar_transactions_ts_1.StellarSignedTransaction({ chainId: this.chainId, signedXdr: trimmed, networkPassphrase: this.networkPassphrase });
|
|
1170
|
+
}
|
|
1171
|
+
return new stellar_transactions_ts_1.StellarSignedTransaction({
|
|
1172
|
+
chainId: this.chainId,
|
|
1173
|
+
signedXdr: Buffer.from(signed).toString('base64'),
|
|
1174
|
+
networkPassphrase: this.networkPassphrase,
|
|
1175
|
+
});
|
|
1176
|
+
}
|
|
1177
|
+
upsertFee(balanceChanges, fees) {
|
|
1178
|
+
if (!fees)
|
|
1179
|
+
return;
|
|
1180
|
+
transaction_status_ts_1.AssetBalanceChange.upsert(balanceChanges, fees.feePayer, this._nativeAsset, transaction_status_ts_1.AssetBalanceChange.fromMr(-BigInt(fees.feeStroops), stellar_asset_ts_1.StellarAsset.DECIMALS));
|
|
1181
|
+
}
|
|
1182
|
+
identifierIndex(assets) {
|
|
1183
|
+
const index = new Map();
|
|
1184
|
+
for (const a of assets) {
|
|
1185
|
+
this.assertStellarAsset(a);
|
|
1186
|
+
if (a.identifier !== undefined)
|
|
1187
|
+
index.set(a.identifier, a);
|
|
1188
|
+
}
|
|
1189
|
+
return index;
|
|
1190
|
+
}
|
|
1191
|
+
assertStellarAsset(asset) {
|
|
1192
|
+
if (!(asset instanceof stellar_asset_ts_1.StellarAsset)) {
|
|
1193
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidArgument, `Invalid asset ${String(asset)} of type ${(0, python_repr_ts_1.pyTypeRepr)(asset)}, expected StellarAsset.`, {
|
|
1194
|
+
chainId: this.chainId,
|
|
1195
|
+
});
|
|
1196
|
+
}
|
|
1197
|
+
}
|
|
1198
|
+
envName() {
|
|
1199
|
+
return this.name.replace(/ /g, '_').toUpperCase();
|
|
1200
|
+
}
|
|
1201
|
+
loadUrlFromEnv(candidates, fallback) {
|
|
1202
|
+
const env = globalThis.process?.env;
|
|
1203
|
+
for (const name of candidates) {
|
|
1204
|
+
const value = env?.[name];
|
|
1205
|
+
if (value)
|
|
1206
|
+
return value;
|
|
1207
|
+
}
|
|
1208
|
+
return fallback;
|
|
1209
|
+
}
|
|
1210
|
+
async soroban(call) {
|
|
1211
|
+
try {
|
|
1212
|
+
return await call;
|
|
1213
|
+
}
|
|
1214
|
+
catch (err) {
|
|
1215
|
+
throw (0, stellar_transactions_ts_1.sorobanRpcError)(err, this.chainId, this.sorobanRpcUrl);
|
|
1216
|
+
}
|
|
1217
|
+
}
|
|
1218
|
+
rpcError(message, err, txHash, rpcUrl) {
|
|
1219
|
+
return new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.RpcError, (0, errors_ts_1.sanitizeMessage)(`${message}: ${err instanceof Error ? err.message : String(err)}`, rpcUrl), { chainId: this.chainId, txHash }, (0, errors_ts_1.sanitizeCause)(err, rpcUrl));
|
|
1220
|
+
}
|
|
1221
|
+
}
|
|
1222
|
+
exports.StellarChain = StellarChain;
|
|
1223
|
+
function scvalToUint32(value) {
|
|
1224
|
+
if (value.switch().name !== 'scvU32') {
|
|
1225
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.TransactionDecodeFailed, `Expected an SCV_U32 value, got ${value.switch().name}`);
|
|
1226
|
+
}
|
|
1227
|
+
return value.u32();
|
|
1228
|
+
}
|
|
1229
|
+
function scvalToUtf8String(value) {
|
|
1230
|
+
if (value.switch().name !== 'scvString') {
|
|
1231
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.TransactionDecodeFailed, `Expected an SCV_STRING value, got ${value.switch().name}`);
|
|
1232
|
+
}
|
|
1233
|
+
const raw = value.str();
|
|
1234
|
+
return (0, python_builtins_ts_1.pyDecodeUtf8)(typeof raw === 'string' ? Buffer.from(raw, 'utf8') : Buffer.from(raw));
|
|
1235
|
+
}
|
|
1236
|
+
function scvalToInt128(value) {
|
|
1237
|
+
if (value.switch().name !== 'scvI128') {
|
|
1238
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.TransactionDecodeFailed, `Expected an SCV_I128 value, got ${value.switch().name}`);
|
|
1239
|
+
}
|
|
1240
|
+
return (0, stellar_sdk_1.scValToBigInt)(value);
|
|
1241
|
+
}
|
|
1242
|
+
const HORIZON_TRANSACTION_REJECTED_STATUS = 400;
|
|
1243
|
+
const STELLAR_SDK_GET_TIMEOUT_MS = 11_000;
|
|
1244
|
+
const STELLAR_SDK_POST_TIMEOUT_MS = 33_000;
|
|
1245
|
+
const AIOHTTP_DEFAULT_TOTAL_TIMEOUT_MS = 300_000;
|
|
1246
|
+
const AIOHTTP_MAX_REDIRECTS = 9;
|
|
1247
|
+
function applyAiohttpClientLimits(client) {
|
|
1248
|
+
client.interceptors.request.use((config) => {
|
|
1249
|
+
const total = String(config.method).toLowerCase() === 'post' ? STELLAR_SDK_POST_TIMEOUT_MS : STELLAR_SDK_GET_TIMEOUT_MS;
|
|
1250
|
+
return Object.assign(config, { timeout: total, signal: AbortSignal.timeout(total), proxy: false, maxRedirects: AIOHTTP_MAX_REDIRECTS });
|
|
1251
|
+
});
|
|
1252
|
+
}
|
|
1253
|
+
const GET_TRANSACTION_STATUSES = new Set(['SUCCESS', 'NOT_FOUND', 'FAILED']);
|
|
1254
|
+
const GET_TRANSACTION_REQUIRED_INTS = ['latestLedger', 'latestLedgerCloseTime', 'oldestLedger', 'oldestLedgerCloseTime'];
|
|
1255
|
+
const GET_TRANSACTION_OPTIONAL_INTS = ['applicationOrder', 'ledger', 'createdAt'];
|
|
1256
|
+
const GET_TRANSACTION_OPTIONAL_STRS = ['envelopeXdr', 'resultXdr', 'resultMetaXdr'];
|
|
1257
|
+
function isAbsent(value) {
|
|
1258
|
+
return value === undefined || value === null;
|
|
1259
|
+
}
|
|
1260
|
+
function isGetTransactionEvents(value) {
|
|
1261
|
+
if (isAbsent(value))
|
|
1262
|
+
return true;
|
|
1263
|
+
if (typeof value !== 'object' || Array.isArray(value))
|
|
1264
|
+
return false;
|
|
1265
|
+
const events = value;
|
|
1266
|
+
return ((isAbsent(events.diagnosticEventsXdr) || (0, python_pydantic_ts_1.isPydanticStrList)(events.diagnosticEventsXdr)) &&
|
|
1267
|
+
(isAbsent(events.transactionEventsXdr) || (0, python_pydantic_ts_1.isPydanticStrList)(events.transactionEventsXdr)) &&
|
|
1268
|
+
(isAbsent(events.contractEventsXdr) ||
|
|
1269
|
+
(Array.isArray(events.contractEventsXdr) && events.contractEventsXdr.every((perOperation) => (0, python_pydantic_ts_1.isPydanticStrList)(perOperation)))));
|
|
1270
|
+
}
|
|
1271
|
+
function isGetTransactionResponse(reply) {
|
|
1272
|
+
if (reply === null || typeof reply !== 'object' || Array.isArray(reply))
|
|
1273
|
+
return false;
|
|
1274
|
+
const fields = reply;
|
|
1275
|
+
return (GET_TRANSACTION_STATUSES.has(fields.status) &&
|
|
1276
|
+
typeof fields.txHash === 'string' &&
|
|
1277
|
+
GET_TRANSACTION_REQUIRED_INTS.every((name) => (0, python_pydantic_ts_1.isPydanticLaxInt)(fields[name])) &&
|
|
1278
|
+
GET_TRANSACTION_OPTIONAL_INTS.every((name) => isAbsent(fields[name]) || (0, python_pydantic_ts_1.isPydanticLaxInt)(fields[name])) &&
|
|
1279
|
+
(isAbsent(fields.feeBump) || (0, python_pydantic_ts_1.isPydanticLaxBool)(fields.feeBump)) &&
|
|
1280
|
+
GET_TRANSACTION_OPTIONAL_STRS.every((name) => isAbsent(fields[name]) || typeof fields[name] === 'string') &&
|
|
1281
|
+
isGetTransactionEvents(fields.events));
|
|
1282
|
+
}
|
|
1283
|
+
function firstHostFunctionResult(results) {
|
|
1284
|
+
if (results === null)
|
|
1285
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.SimulationFailed, "'NoneType' object is not subscriptable");
|
|
1286
|
+
if (results.length === 0)
|
|
1287
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.SimulationFailed, 'list index out of range');
|
|
1288
|
+
return stellar_sdk_1.xdr.ScVal.fromXDR(results[0].xdr, 'base64');
|
|
1289
|
+
}
|
|
1290
|
+
const MEMO_REQUIRED_OPERATION_TYPES = new Set(['payment', 'accountMerge', 'pathPaymentStrictSend', 'pathPaymentStrictReceive']);
|
|
1291
|
+
const MEMO_REQUIRED_CONFIG_KEY = 'config.memo_required';
|
|
1292
|
+
const MEMO_REQUIRED_CONFIG_VALUE = 'MQ==';
|
|
1293
|
+
function transactionXdrOperations(tx) {
|
|
1294
|
+
const envelope = tx.toEnvelope();
|
|
1295
|
+
return envelope.switch().name === 'envelopeTypeTxV0' ? envelope.v0().tx().operations() : envelope.v1().tx().operations();
|
|
1296
|
+
}
|
|
1297
|
+
function horizonSubmissionRejection(error) {
|
|
1298
|
+
const response = error.response;
|
|
1299
|
+
if (typeof response !== 'object' || response === null)
|
|
1300
|
+
return null;
|
|
1301
|
+
const problem = error instanceof stellar_sdk_1.BadResponseError
|
|
1302
|
+
? response
|
|
1303
|
+
: response.data;
|
|
1304
|
+
const status = error instanceof stellar_sdk_1.BadResponseError ? problem?.status : response.status;
|
|
1305
|
+
if (status !== HORIZON_TRANSACTION_REJECTED_STATUS)
|
|
1306
|
+
return null;
|
|
1307
|
+
return typeof problem === 'object' && problem !== null ? problem : {};
|
|
1308
|
+
}
|
|
1309
|
+
function describeHorizonRejection(problem, error) {
|
|
1310
|
+
const resultCodes = problem.extras?.result_codes;
|
|
1311
|
+
return resultCodes !== undefined ? JSON.stringify(resultCodes) : error.message;
|
|
1312
|
+
}
|
|
1313
|
+
async function runBatch(items, fetchOne) {
|
|
1314
|
+
const results = new Array(items.length);
|
|
1315
|
+
let cursor = 0;
|
|
1316
|
+
let aborted = false;
|
|
1317
|
+
const spawn = async () => {
|
|
1318
|
+
while (!aborted) {
|
|
1319
|
+
const idx = cursor++;
|
|
1320
|
+
if (idx >= items.length)
|
|
1321
|
+
return;
|
|
1322
|
+
try {
|
|
1323
|
+
results[idx] = await fetchOne(items[idx]);
|
|
1324
|
+
}
|
|
1325
|
+
catch (err) {
|
|
1326
|
+
aborted = true;
|
|
1327
|
+
throw err;
|
|
1328
|
+
}
|
|
1329
|
+
}
|
|
1330
|
+
};
|
|
1331
|
+
await Promise.all(Array.from({ length: Math.min(8, items.length) }, spawn));
|
|
1332
|
+
return results;
|
|
1333
|
+
}
|
|
1334
|
+
//# sourceMappingURL=stellar_chain.js.map
|