@paraspell/sdk-pjs 8.3.0 → 8.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -315,7 +315,7 @@ await getBalanceForeign({address, node, currency /*- {id: currencyID} | {symbol:
315
315
  await getBalanceNative({address, node, api /* api/ws_url_string optional */})
316
316
 
317
317
  //Get fee information regarding XCM call
318
- await getOriginFeeDetails({from, to, currency /*- {id: currencyID} | {symbol: currencySymbol} | {symbol: Native('currencySymbol')} | {symbol: Foreign('currencySymbol')} | {symbol: ForeignAbstract('currencySymbol')} | {multilocation: AssetMultilocationString | AssetMultilocationJson}*/, amount, originAddress, destinationAddress, api /* api/ws_url_string optional */, feeMargin /* 10% by default */})
318
+ await getOriginFeeDetails({from, to, currency /*- {id: currencyID} | {symbol: currencySymbol} | {symbol: Native('currencySymbol')} | {symbol: Foreign('currencySymbol')} | {symbol: ForeignAbstract('currencySymbol')} | {multilocation: AssetMultilocationString | AssetMultilocationJson}*/, amount, originAddress, destinationAddress, ahAddress /* optional parameter when destination is Ethereum and origin is Parachain other than AssetHub*/, api /* api/ws_url_string optional */, feeMargin /* 10% by default */})
319
319
 
320
320
  //Retrieves the asset balance for a given account on a specified node. (You do not need to specify if it is native or foreign).
321
321
  await getAssetBalance({address, node, currency /*- {id: currencyID} | {symbol: currencySymbol} | {symbol: Native('currencySymbol')} | {symbol: Foreign('currencySymbol')} | {symbol: ForeignAbstract('currencySymbol')} | {multilocation: AssetMultilocationString | AssetMultilocationJson}*/, api /* api/ws_url_string optional */});
package/dist/index.cjs CHANGED
@@ -7,6 +7,8 @@ var api$1 = require('@polkadot/api');
7
7
  var types = require('@polkadot/types');
8
8
  var utilCrypto = require('@polkadot/util-crypto');
9
9
  var util = require('@polkadot/util');
10
+ var ethers = require('ethers');
11
+ var viem = require('viem');
10
12
 
11
13
  function _arrayLikeToArray(r, a) {
12
14
  (null == a || a > r.length) && (a = r.length);
@@ -16,6 +18,9 @@ function _arrayLikeToArray(r, a) {
16
18
  function _arrayWithHoles(r) {
17
19
  if (Array.isArray(r)) return r;
18
20
  }
21
+ function _arrayWithoutHoles(r) {
22
+ if (Array.isArray(r)) return _arrayLikeToArray(r);
23
+ }
19
24
  function asyncGeneratorStep(n, t, e, r, o, a, c) {
20
25
  try {
21
26
  var i = n[a](c),
@@ -63,6 +68,9 @@ function _defineProperty(e, r, t) {
63
68
  writable: true
64
69
  }) : e[r] = t, e;
65
70
  }
71
+ function _iterableToArray(r) {
72
+ if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r);
73
+ }
66
74
  function _iterableToArrayLimit(r, l) {
67
75
  var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"];
68
76
  if (null != t) {
@@ -90,6 +98,9 @@ function _iterableToArrayLimit(r, l) {
90
98
  function _nonIterableRest() {
91
99
  throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
92
100
  }
101
+ function _nonIterableSpread() {
102
+ throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
103
+ }
93
104
  function ownKeys(e, r) {
94
105
  var t = Object.keys(e);
95
106
  if (Object.getOwnPropertySymbols) {
@@ -415,6 +426,9 @@ function _regeneratorRuntime() {
415
426
  function _slicedToArray(r, e) {
416
427
  return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest();
417
428
  }
429
+ function _toConsumableArray(r) {
430
+ return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread();
431
+ }
418
432
  function _toPrimitive(t, r) {
419
433
  if ("object" != typeof t || !t) return t;
420
434
  var e = t[Symbol.toPrimitive];
@@ -468,6 +482,9 @@ var createContext = function createContext(executionUrl, config) {
468
482
  var isEthersSigner = function isEthersSigner(signer) {
469
483
  return _typeof(signer) === 'object' && signer !== null && 'provider' in signer;
470
484
  };
485
+ var isEthersContract = function isEthersContract(contract) {
486
+ return !('abi' in contract);
487
+ };
471
488
 
472
489
  /**
473
490
  * Transfers an Ethereum asset to a Polkadot account.
@@ -1456,6 +1473,318 @@ var assets = /*#__PURE__*/Object.freeze({
1456
1473
  isNodeEvm: sdkCore.isNodeEvm
1457
1474
  });
1458
1475
 
1476
+ var abi = [
1477
+ {
1478
+ inputs: [
1479
+ {
1480
+ components: [
1481
+ {
1482
+ internalType: "uint8",
1483
+ name: "parents",
1484
+ type: "uint8"
1485
+ },
1486
+ {
1487
+ internalType: "bytes[]",
1488
+ name: "interior",
1489
+ type: "bytes[]"
1490
+ }
1491
+ ],
1492
+ internalType: "struct XCM.Location",
1493
+ name: "dest",
1494
+ type: "tuple"
1495
+ },
1496
+ {
1497
+ components: [
1498
+ {
1499
+ internalType: "address",
1500
+ name: "asset",
1501
+ type: "address"
1502
+ },
1503
+ {
1504
+ internalType: "uint256",
1505
+ name: "amount",
1506
+ type: "uint256"
1507
+ }
1508
+ ],
1509
+ internalType: "struct XCM.AssetAddressInfo[]",
1510
+ name: "assets",
1511
+ type: "tuple[]"
1512
+ },
1513
+ {
1514
+ internalType: "enum XCM.TransferType",
1515
+ name: "assetsTransferType",
1516
+ type: "uint8"
1517
+ },
1518
+ {
1519
+ internalType: "uint8",
1520
+ name: "remoteFeesIdIndex",
1521
+ type: "uint8"
1522
+ },
1523
+ {
1524
+ internalType: "enum XCM.TransferType",
1525
+ name: "feesTransferType",
1526
+ type: "uint8"
1527
+ },
1528
+ {
1529
+ internalType: "bytes",
1530
+ name: "customXcmOnDest",
1531
+ type: "bytes"
1532
+ }
1533
+ ],
1534
+ name: "transferAssetsUsingTypeAndThenAddress",
1535
+ outputs: [
1536
+ ],
1537
+ stateMutability: "nonpayable",
1538
+ type: "function"
1539
+ }
1540
+ ];
1541
+
1542
+ // https://github.com/moonbeam-foundation/moonbeam/blob/b2b1bde7ced13aad4bd2928effc415c521fd48cb/runtime/moonbeam/src/precompiles.rs#L281
1543
+ var xcmInterfacePrecompile = '0x000000000000000000000000000000000000081A';
1544
+ var XCDOT = '0xFfFFfFff1FcaCBd218EDc0EbA20Fc2308C778080';
1545
+ var transferMoonbeamToEth = /*#__PURE__*/function () {
1546
+ var _ref2 = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime().mark(function _callee(_ref) {
1547
+ var _signer$account;
1548
+ var api, from, to, signer, address, ahAddress, currency, foundAsset, ethAsset, contract, BRIDGE_LOCATION, ERC20_TOKEN_LOCATION, ERC20_TOKEN_LOCATION_REANCHORED, customXcm, apiPjs, assetHubApi, assetHubApiPjs, xcmHash, sender, _yield$Promise$all, _yield$Promise$all2, parachainId, accountNextId, entropy, messageId, xcmOnDest, customXcmOnDest, transferFee, createTx, tx;
1549
+ return _regeneratorRuntime().wrap(function _callee$(_context) {
1550
+ while (1) switch (_context.prev = _context.next) {
1551
+ case 0:
1552
+ api = _ref.api, from = _ref.from, to = _ref.to, signer = _ref.signer, address = _ref.address, ahAddress = _ref.ahAddress, currency = _ref.currency;
1553
+ if (!('multiasset' in currency)) {
1554
+ _context.next = 3;
1555
+ break;
1556
+ }
1557
+ throw new Error('Multiassets syntax is not supported for Evm transfers');
1558
+ case 3:
1559
+ if (!('multilocation' in currency && sdkCore.isOverrideMultiLocationSpecifier(currency.multilocation))) {
1560
+ _context.next = 5;
1561
+ break;
1562
+ }
1563
+ throw new Error('Override multilocation is not supported for Evm transfers');
1564
+ case 5:
1565
+ foundAsset = sdkCore.getAssetBySymbolOrId(from, currency, to);
1566
+ if (!(foundAsset === null)) {
1567
+ _context.next = 8;
1568
+ break;
1569
+ }
1570
+ throw new sdkCore.InvalidCurrencyError("Origin node ".concat(from, " does not support currency ").concat(JSON.stringify(currency), "."));
1571
+ case 8:
1572
+ if (!(!sdkCore.isForeignAsset(foundAsset) || !foundAsset.multiLocation)) {
1573
+ _context.next = 10;
1574
+ break;
1575
+ }
1576
+ throw new sdkCore.InvalidCurrencyError('Currency must be a foreign asset with valid multi-location');
1577
+ case 10:
1578
+ ethAsset = sdkCore.findAssetByMultiLocation(sdkCore.getOtherAssets('Ethereum'), foundAsset.multiLocation);
1579
+ if (ethAsset) {
1580
+ _context.next = 13;
1581
+ break;
1582
+ }
1583
+ throw new sdkCore.InvalidCurrencyError("Could not obtain Ethereum asset address for ".concat(JSON.stringify(foundAsset)));
1584
+ case 13:
1585
+ contract = isEthersSigner(signer) ? new ethers.Contract(xcmInterfacePrecompile, abi, signer) : viem.getContract({
1586
+ abi: abi,
1587
+ address: xcmInterfacePrecompile,
1588
+ client: {
1589
+ "public": viem.createPublicClient({
1590
+ chain: signer.chain,
1591
+ transport: viem.http()
1592
+ }),
1593
+ wallet: signer
1594
+ }
1595
+ });
1596
+ BRIDGE_LOCATION = {
1597
+ parents: 2,
1598
+ interior: {
1599
+ X1: [sdkCore.ETHEREUM_JUNCTION]
1600
+ }
1601
+ };
1602
+ ERC20_TOKEN_LOCATION = {
1603
+ parents: 2,
1604
+ interior: {
1605
+ X2: [{
1606
+ GlobalConsensus: {
1607
+ Ethereum: {
1608
+ chain_id: sdkCore.ETH_CHAIN_ID
1609
+ }
1610
+ }
1611
+ }, {
1612
+ AccountKey20: {
1613
+ key: foundAsset.assetId
1614
+ }
1615
+ }]
1616
+ }
1617
+ };
1618
+ ERC20_TOKEN_LOCATION_REANCHORED = {
1619
+ parents: 0,
1620
+ interior: {
1621
+ X1: [{
1622
+ AccountKey20: {
1623
+ key: foundAsset.assetId
1624
+ }
1625
+ }]
1626
+ }
1627
+ };
1628
+ customXcm = [{
1629
+ setAppendix: [{
1630
+ depositAsset: {
1631
+ assets: {
1632
+ Wild: 'All'
1633
+ },
1634
+ beneficiary: {
1635
+ parents: 0,
1636
+ interior: {
1637
+ x1: [{
1638
+ AccountId32: {
1639
+ id: util.u8aToHex(utilCrypto.decodeAddress(ahAddress))
1640
+ }
1641
+ }]
1642
+ }
1643
+ }
1644
+ }
1645
+ }]
1646
+ }, {
1647
+ initiateReserveWithdraw: {
1648
+ assets: {
1649
+ Wild: {
1650
+ AllOf: {
1651
+ id: ERC20_TOKEN_LOCATION,
1652
+ fun: 'Fungible'
1653
+ }
1654
+ }
1655
+ },
1656
+ reserve: BRIDGE_LOCATION,
1657
+ xcm: [{
1658
+ buyExecution: {
1659
+ fees: {
1660
+ id: ERC20_TOKEN_LOCATION_REANCHORED,
1661
+ // CAUTION: Must use reanchored locations.
1662
+ fun: {
1663
+ Fungible: '1' // Offering 1 unit as fee, but it is returned to the destination address.
1664
+ }
1665
+ },
1666
+ weight_limit: 'Unlimited'
1667
+ }
1668
+ }, {
1669
+ depositAsset: {
1670
+ assets: {
1671
+ Wild: {
1672
+ AllCounted: 1
1673
+ }
1674
+ },
1675
+ beneficiary: {
1676
+ parents: 0,
1677
+ interior: {
1678
+ x1: [{
1679
+ AccountKey20: {
1680
+ key: address
1681
+ }
1682
+ }]
1683
+ }
1684
+ }
1685
+ }
1686
+ }, {
1687
+ setTopic: '0x0000000000000000000000000000000000000000000000000000000000000000'
1688
+ }]
1689
+ }
1690
+ }, {
1691
+ setTopic: '0x0000000000000000000000000000000000000000000000000000000000000000'
1692
+ }];
1693
+ _context.next = 20;
1694
+ return api.init(from);
1695
+ case 20:
1696
+ apiPjs = api.getApi();
1697
+ _context.next = 23;
1698
+ return api.createApiForNode('AssetHubPolkadot');
1699
+ case 23:
1700
+ assetHubApi = _context.sent;
1701
+ assetHubApiPjs = assetHubApi.getApi(); // Generate an unique messageId and set into `setTopic` for remote track
1702
+ xcmHash = assetHubApiPjs.createType('Xcm', customXcm);
1703
+ if (!isEthersSigner(signer)) {
1704
+ _context.next = 32;
1705
+ break;
1706
+ }
1707
+ _context.next = 29;
1708
+ return signer.getAddress();
1709
+ case 29:
1710
+ _context.t0 = _context.sent;
1711
+ _context.next = 33;
1712
+ break;
1713
+ case 32:
1714
+ _context.t0 = (_signer$account = signer.account) === null || _signer$account === undefined ? undefined : _signer$account.address;
1715
+ case 33:
1716
+ sender = _context.t0;
1717
+ _context.next = 36;
1718
+ return Promise.all([apiPjs.query.parachainInfo.parachainId(), apiPjs.rpc.system.accountNextIndex(sender)]);
1719
+ case 36:
1720
+ _yield$Promise$all = _context.sent;
1721
+ _yield$Promise$all2 = _slicedToArray(_yield$Promise$all, 2);
1722
+ parachainId = _yield$Promise$all2[0];
1723
+ accountNextId = _yield$Promise$all2[1];
1724
+ entropy = new Uint8Array([].concat(_toConsumableArray(parachainId.toU8a()), _toConsumableArray(accountNextId.toU8a()), _toConsumableArray(xcmHash.toU8a())));
1725
+ messageId = utilCrypto.blake2AsHex(entropy);
1726
+ if (!(customXcm.length == 2)) {
1727
+ _context.next = 47;
1728
+ break;
1729
+ }
1730
+ customXcm[0].initiateReserveWithdraw.xcm[2].setTopic = messageId;
1731
+ customXcm[1].setTopic = messageId;
1732
+ _context.next = 53;
1733
+ break;
1734
+ case 47:
1735
+ if (!(customXcm.length == 3)) {
1736
+ _context.next = 52;
1737
+ break;
1738
+ }
1739
+ customXcm[1].initiateReserveWithdraw.xcm[2].setTopic = messageId;
1740
+ customXcm[2].setTopic = messageId;
1741
+ _context.next = 53;
1742
+ break;
1743
+ case 52:
1744
+ throw new Error('invalid xcm');
1745
+ case 53:
1746
+ xcmOnDest = assetHubApiPjs.createType('XcmVersionedXcm', {
1747
+ V4: customXcm
1748
+ });
1749
+ customXcmOnDest = xcmOnDest.toHex();
1750
+ _context.next = 57;
1751
+ return sdkCore.calculateFee(assetHubApi);
1752
+ case 57:
1753
+ transferFee = _context.sent;
1754
+ // Partially inspired by Moonbeam XCM-SDK
1755
+ // https://github.com/moonbeam-foundation/xcm-sdk/blob/ab835c15bf41612604b1c858d956a9f07705ed65/packages/sdk/src/contract/contracts/Xtokens/Xtokens.ts#L53
1756
+ createTx = function createTx(func, args) {
1757
+ if (isEthersContract(contract)) {
1758
+ return contract[func].apply(contract, _toConsumableArray(args));
1759
+ }
1760
+ return contract.write[func](args);
1761
+ }; // Execute the custom XCM message with the precompile
1762
+ _context.next = 61;
1763
+ return createTx(isEthersSigner(signer) ? 'transferAssetsUsingTypeAndThenAddress((uint8,bytes[]),(address,uint256)[],uint8,uint8,uint8,bytes)' : 'transferAssetsUsingTypeAndThenAddress', [
1764
+ // This represents (1,X1(Parachain(1000)))
1765
+ [1, ['0x00' + util.numberToHex(sdkCore.getParaId('AssetHubPolkadot'), 32).slice(2)]],
1766
+ // Assets including fee and the ERC20 asset, with fee be the first
1767
+ [[XCDOT, transferFee], [ethAsset.assetId, currency.amount]],
1768
+ // The TransferType corresponding to asset being sent, 2 represents `DestinationReserve`
1769
+ 2,
1770
+ // index for the fee
1771
+ 0,
1772
+ // The TransferType corresponding to fee asset
1773
+ 2, customXcmOnDest]);
1774
+ case 61:
1775
+ tx = _context.sent;
1776
+ return _context.abrupt("return", _typeof(tx) === 'object' ? tx.hash : tx);
1777
+ case 63:
1778
+ case "end":
1779
+ return _context.stop();
1780
+ }
1781
+ }, _callee);
1782
+ }));
1783
+ return function transferMoonbeamToEth(_x) {
1784
+ return _ref2.apply(this, arguments);
1785
+ };
1786
+ }();
1787
+
1459
1788
  /**
1460
1789
  * Builder class for constructing transfers from Ethereum to Polkadot.
1461
1790
  */
@@ -1504,8 +1833,9 @@ var EvmBuilderClass = /*#__PURE__*/function () {
1504
1833
  */
1505
1834
  }, {
1506
1835
  key: "address",
1507
- value: function address(_address) {
1836
+ value: function address(_address, ahAddress) {
1508
1837
  this._options.address = _address;
1838
+ this._options.ahAddress = ahAddress;
1509
1839
  return this;
1510
1840
  }
1511
1841
  /**
@@ -1551,22 +1881,35 @@ var EvmBuilderClass = /*#__PURE__*/function () {
1551
1881
  _context.next = 2;
1552
1882
  break;
1553
1883
  case 9:
1884
+ sdkCore.validateAddress(this._options.address, this._options.to);
1885
+ if (!(this._options.from === 'Moonbeam' && this._options.to === 'Ethereum')) {
1886
+ _context.next = 12;
1887
+ break;
1888
+ }
1889
+ return _context.abrupt("return", transferMoonbeamToEth(this._options));
1890
+ case 12:
1554
1891
  if (!(this._options.from === 'Moonbeam' || this._options.from === 'Moonriver')) {
1555
- _context.next = 13;
1892
+ _context.next = 16;
1556
1893
  break;
1557
1894
  }
1558
- _context.next = 12;
1895
+ _context.next = 15;
1559
1896
  return sdkCore.transferMoonbeamEvm(this._options);
1560
- case 12:
1897
+ case 15:
1561
1898
  return _context.abrupt("return", _context.sent);
1562
- case 13:
1563
- _context.next = 15;
1899
+ case 16:
1900
+ if (!(this._options.from === 'Ethereum')) {
1901
+ _context.next = 22;
1902
+ break;
1903
+ }
1904
+ _context.next = 19;
1564
1905
  return transferEthToPolkadot$1(this._options);
1565
- case 15:
1906
+ case 19:
1566
1907
  _yield$transferEthToP = _context.sent;
1567
1908
  response = _yield$transferEthToP.response;
1568
1909
  return _context.abrupt("return", response.hash);
1569
- case 18:
1910
+ case 22:
1911
+ throw new Error('Scenario not supported');
1912
+ case 23:
1570
1913
  case "end":
1571
1914
  return _context.stop();
1572
1915
  }
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as _paraspell_sdk_core from '@paraspell/sdk-core';
2
- import { TApiOrUrl, TEvmBuilderOptions, Foreign, ForeignAbstract, Native, Override, getAllAssetsSymbols, getAssetBySymbolOrId, getAssetDecimals, getAssetId, getAssets, getAssetsObject, getExistentialDeposit, getNativeAssetSymbol, getNativeAssets, getOtherAssets, getRelayChainSymbol, getSupportedAssets, getTNode, hasSupportForAsset, isNodeEvm, TOptionalEvmBuilderOptions, IPolkadotApi, TNodeDotKsmWithRelayChains, TCurrencyInputWithAmount, GeneralBuilder as GeneralBuilder$1, IFinalBuilderWithOptions as IFinalBuilderWithOptions$1 } from '@paraspell/sdk-core';
2
+ import { TApiOrUrl, TEvmBuilderOptions, Foreign, ForeignAbstract, Native, Override, getAllAssetsSymbols, getAssetBySymbolOrId, getAssetDecimals, getAssetId, getAssets, getAssetsObject, getExistentialDeposit, getNativeAssetSymbol, getNativeAssets, getOtherAssets, getRelayChainSymbol, getSupportedAssets, getTNode, hasSupportForAsset, isNodeEvm, TOptionalEvmBuilderOptions, IPolkadotApi, TNodeWithRelayChains, TCurrencyInputWithAmount, GeneralBuilder as GeneralBuilder$1, IFinalBuilderWithOptions as IFinalBuilderWithOptions$1, TNodeDotKsmWithRelayChains } from '@paraspell/sdk-core';
3
3
  export * from '@paraspell/sdk-core';
4
4
  import * as _snowbridge_api_dist_toPolkadot_v2 from '@snowbridge/api/dist/toPolkadot_v2';
5
5
  import * as ethers from 'ethers';
@@ -157,7 +157,7 @@ declare class EvmBuilderClass<TApi, TRes> {
157
157
  * @param node - The Polkadot node to which the transfer will be made.
158
158
  * @returns An instance of EvmBuilder
159
159
  */
160
- to(node: TNodeDotKsmWithRelayChains): this;
160
+ to(node: TNodeWithRelayChains): this;
161
161
  /**
162
162
  * Specifies the currency to transfer.
163
163
  *
@@ -171,7 +171,7 @@ declare class EvmBuilderClass<TApi, TRes> {
171
171
  * @param address - The Polkadot address to receive the transfer.
172
172
  * @returns An instance of EvmBuilder
173
173
  */
174
- address(address: string): this;
174
+ address(address: string, ahAddress?: string): this;
175
175
  /**
176
176
  * Specifies the signer for the Ethereum transaction.
177
177
  *
package/dist/index.mjs CHANGED
@@ -1,11 +1,13 @@
1
- import { getParaId, isForeignAsset, InvalidCurrencyError, getAssetBySymbolOrId, isOverrideMultiLocationSpecifier, BatchMode, createApiInstanceForNode as createApiInstanceForNode$1, getNode, computeFeeFromDryRunPjs, resolveModuleError, getAssetsObject, send as send$1, getDryRun as getDryRun$1, getBalanceNative as getBalanceNative$1, getBalanceForeign as getBalanceForeign$1, getTransferInfo as getTransferInfo$1, getAssetBalance as getAssetBalance$1, claimAssets as claimAssets$1, getOriginFeeDetails as getOriginFeeDetails$1, getMaxNativeTransferableAmount as getMaxNativeTransferableAmount$1, getMaxForeignTransferableAmount as getMaxForeignTransferableAmount$1, getTransferableAmount as getTransferableAmount$1, Foreign, ForeignAbstract, Native, Override, getAllAssetsSymbols, getAssetDecimals, getAssetId, getAssets, getExistentialDeposit, getNativeAssetSymbol, getNativeAssets, getOtherAssets, getRelayChainSymbol, getSupportedAssets, getTNode, hasSupportForAsset, isNodeEvm, transferMoonbeamEvm, Builder as Builder$1, GeneralBuilder as GeneralBuilder$1 } from '@paraspell/sdk-core';
1
+ import { getParaId, isForeignAsset, InvalidCurrencyError, getAssetBySymbolOrId, isOverrideMultiLocationSpecifier, BatchMode, createApiInstanceForNode as createApiInstanceForNode$1, getNode, computeFeeFromDryRunPjs, resolveModuleError, getAssetsObject, send as send$1, getDryRun as getDryRun$1, getBalanceNative as getBalanceNative$1, getBalanceForeign as getBalanceForeign$1, getTransferInfo as getTransferInfo$1, getAssetBalance as getAssetBalance$1, claimAssets as claimAssets$1, getOriginFeeDetails as getOriginFeeDetails$1, getMaxNativeTransferableAmount as getMaxNativeTransferableAmount$1, getMaxForeignTransferableAmount as getMaxForeignTransferableAmount$1, getTransferableAmount as getTransferableAmount$1, Foreign, ForeignAbstract, Native, Override, getAllAssetsSymbols, getAssetDecimals, getAssetId, getAssets, getExistentialDeposit, getNativeAssetSymbol, getNativeAssets, getOtherAssets, getRelayChainSymbol, getSupportedAssets, getTNode, hasSupportForAsset, isNodeEvm, calculateFee, ETH_CHAIN_ID, findAssetByMultiLocation, ETHEREUM_JUNCTION, transferMoonbeamEvm, validateAddress, Builder as Builder$1, GeneralBuilder as GeneralBuilder$1 } from '@paraspell/sdk-core';
2
2
  export * from '@paraspell/sdk-core';
3
3
  import { Context, toPolkadotV2, assetsV2, environment } from '@snowbridge/api';
4
4
  import { WETH9__factory } from '@snowbridge/contract-types';
5
5
  import { WsProvider, ApiPromise } from '@polkadot/api';
6
6
  import { u32 } from '@polkadot/types';
7
- import { decodeAddress } from '@polkadot/util-crypto';
8
- import { u8aToHex } from '@polkadot/util';
7
+ import { decodeAddress, blake2AsHex } from '@polkadot/util-crypto';
8
+ import { u8aToHex, numberToHex } from '@polkadot/util';
9
+ import { Contract } from 'ethers';
10
+ import { getContract, createPublicClient, http } from 'viem';
9
11
 
10
12
  function _arrayLikeToArray(r, a) {
11
13
  (null == a || a > r.length) && (a = r.length);
@@ -15,6 +17,9 @@ function _arrayLikeToArray(r, a) {
15
17
  function _arrayWithHoles(r) {
16
18
  if (Array.isArray(r)) return r;
17
19
  }
20
+ function _arrayWithoutHoles(r) {
21
+ if (Array.isArray(r)) return _arrayLikeToArray(r);
22
+ }
18
23
  function asyncGeneratorStep(n, t, e, r, o, a, c) {
19
24
  try {
20
25
  var i = n[a](c),
@@ -62,6 +67,9 @@ function _defineProperty(e, r, t) {
62
67
  writable: true
63
68
  }) : e[r] = t, e;
64
69
  }
70
+ function _iterableToArray(r) {
71
+ if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r);
72
+ }
65
73
  function _iterableToArrayLimit(r, l) {
66
74
  var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"];
67
75
  if (null != t) {
@@ -89,6 +97,9 @@ function _iterableToArrayLimit(r, l) {
89
97
  function _nonIterableRest() {
90
98
  throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
91
99
  }
100
+ function _nonIterableSpread() {
101
+ throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
102
+ }
92
103
  function ownKeys(e, r) {
93
104
  var t = Object.keys(e);
94
105
  if (Object.getOwnPropertySymbols) {
@@ -414,6 +425,9 @@ function _regeneratorRuntime() {
414
425
  function _slicedToArray(r, e) {
415
426
  return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest();
416
427
  }
428
+ function _toConsumableArray(r) {
429
+ return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread();
430
+ }
417
431
  function _toPrimitive(t, r) {
418
432
  if ("object" != typeof t || !t) return t;
419
433
  var e = t[Symbol.toPrimitive];
@@ -467,6 +481,9 @@ var createContext = function createContext(executionUrl, config) {
467
481
  var isEthersSigner = function isEthersSigner(signer) {
468
482
  return _typeof(signer) === 'object' && signer !== null && 'provider' in signer;
469
483
  };
484
+ var isEthersContract = function isEthersContract(contract) {
485
+ return !('abi' in contract);
486
+ };
470
487
 
471
488
  /**
472
489
  * Transfers an Ethereum asset to a Polkadot account.
@@ -1455,6 +1472,318 @@ var assets = /*#__PURE__*/Object.freeze({
1455
1472
  isNodeEvm: isNodeEvm
1456
1473
  });
1457
1474
 
1475
+ var abi = [
1476
+ {
1477
+ inputs: [
1478
+ {
1479
+ components: [
1480
+ {
1481
+ internalType: "uint8",
1482
+ name: "parents",
1483
+ type: "uint8"
1484
+ },
1485
+ {
1486
+ internalType: "bytes[]",
1487
+ name: "interior",
1488
+ type: "bytes[]"
1489
+ }
1490
+ ],
1491
+ internalType: "struct XCM.Location",
1492
+ name: "dest",
1493
+ type: "tuple"
1494
+ },
1495
+ {
1496
+ components: [
1497
+ {
1498
+ internalType: "address",
1499
+ name: "asset",
1500
+ type: "address"
1501
+ },
1502
+ {
1503
+ internalType: "uint256",
1504
+ name: "amount",
1505
+ type: "uint256"
1506
+ }
1507
+ ],
1508
+ internalType: "struct XCM.AssetAddressInfo[]",
1509
+ name: "assets",
1510
+ type: "tuple[]"
1511
+ },
1512
+ {
1513
+ internalType: "enum XCM.TransferType",
1514
+ name: "assetsTransferType",
1515
+ type: "uint8"
1516
+ },
1517
+ {
1518
+ internalType: "uint8",
1519
+ name: "remoteFeesIdIndex",
1520
+ type: "uint8"
1521
+ },
1522
+ {
1523
+ internalType: "enum XCM.TransferType",
1524
+ name: "feesTransferType",
1525
+ type: "uint8"
1526
+ },
1527
+ {
1528
+ internalType: "bytes",
1529
+ name: "customXcmOnDest",
1530
+ type: "bytes"
1531
+ }
1532
+ ],
1533
+ name: "transferAssetsUsingTypeAndThenAddress",
1534
+ outputs: [
1535
+ ],
1536
+ stateMutability: "nonpayable",
1537
+ type: "function"
1538
+ }
1539
+ ];
1540
+
1541
+ // https://github.com/moonbeam-foundation/moonbeam/blob/b2b1bde7ced13aad4bd2928effc415c521fd48cb/runtime/moonbeam/src/precompiles.rs#L281
1542
+ var xcmInterfacePrecompile = '0x000000000000000000000000000000000000081A';
1543
+ var XCDOT = '0xFfFFfFff1FcaCBd218EDc0EbA20Fc2308C778080';
1544
+ var transferMoonbeamToEth = /*#__PURE__*/function () {
1545
+ var _ref2 = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime().mark(function _callee(_ref) {
1546
+ var _signer$account;
1547
+ var api, from, to, signer, address, ahAddress, currency, foundAsset, ethAsset, contract, BRIDGE_LOCATION, ERC20_TOKEN_LOCATION, ERC20_TOKEN_LOCATION_REANCHORED, customXcm, apiPjs, assetHubApi, assetHubApiPjs, xcmHash, sender, _yield$Promise$all, _yield$Promise$all2, parachainId, accountNextId, entropy, messageId, xcmOnDest, customXcmOnDest, transferFee, createTx, tx;
1548
+ return _regeneratorRuntime().wrap(function _callee$(_context) {
1549
+ while (1) switch (_context.prev = _context.next) {
1550
+ case 0:
1551
+ api = _ref.api, from = _ref.from, to = _ref.to, signer = _ref.signer, address = _ref.address, ahAddress = _ref.ahAddress, currency = _ref.currency;
1552
+ if (!('multiasset' in currency)) {
1553
+ _context.next = 3;
1554
+ break;
1555
+ }
1556
+ throw new Error('Multiassets syntax is not supported for Evm transfers');
1557
+ case 3:
1558
+ if (!('multilocation' in currency && isOverrideMultiLocationSpecifier(currency.multilocation))) {
1559
+ _context.next = 5;
1560
+ break;
1561
+ }
1562
+ throw new Error('Override multilocation is not supported for Evm transfers');
1563
+ case 5:
1564
+ foundAsset = getAssetBySymbolOrId(from, currency, to);
1565
+ if (!(foundAsset === null)) {
1566
+ _context.next = 8;
1567
+ break;
1568
+ }
1569
+ throw new InvalidCurrencyError("Origin node ".concat(from, " does not support currency ").concat(JSON.stringify(currency), "."));
1570
+ case 8:
1571
+ if (!(!isForeignAsset(foundAsset) || !foundAsset.multiLocation)) {
1572
+ _context.next = 10;
1573
+ break;
1574
+ }
1575
+ throw new InvalidCurrencyError('Currency must be a foreign asset with valid multi-location');
1576
+ case 10:
1577
+ ethAsset = findAssetByMultiLocation(getOtherAssets('Ethereum'), foundAsset.multiLocation);
1578
+ if (ethAsset) {
1579
+ _context.next = 13;
1580
+ break;
1581
+ }
1582
+ throw new InvalidCurrencyError("Could not obtain Ethereum asset address for ".concat(JSON.stringify(foundAsset)));
1583
+ case 13:
1584
+ contract = isEthersSigner(signer) ? new Contract(xcmInterfacePrecompile, abi, signer) : getContract({
1585
+ abi: abi,
1586
+ address: xcmInterfacePrecompile,
1587
+ client: {
1588
+ "public": createPublicClient({
1589
+ chain: signer.chain,
1590
+ transport: http()
1591
+ }),
1592
+ wallet: signer
1593
+ }
1594
+ });
1595
+ BRIDGE_LOCATION = {
1596
+ parents: 2,
1597
+ interior: {
1598
+ X1: [ETHEREUM_JUNCTION]
1599
+ }
1600
+ };
1601
+ ERC20_TOKEN_LOCATION = {
1602
+ parents: 2,
1603
+ interior: {
1604
+ X2: [{
1605
+ GlobalConsensus: {
1606
+ Ethereum: {
1607
+ chain_id: ETH_CHAIN_ID
1608
+ }
1609
+ }
1610
+ }, {
1611
+ AccountKey20: {
1612
+ key: foundAsset.assetId
1613
+ }
1614
+ }]
1615
+ }
1616
+ };
1617
+ ERC20_TOKEN_LOCATION_REANCHORED = {
1618
+ parents: 0,
1619
+ interior: {
1620
+ X1: [{
1621
+ AccountKey20: {
1622
+ key: foundAsset.assetId
1623
+ }
1624
+ }]
1625
+ }
1626
+ };
1627
+ customXcm = [{
1628
+ setAppendix: [{
1629
+ depositAsset: {
1630
+ assets: {
1631
+ Wild: 'All'
1632
+ },
1633
+ beneficiary: {
1634
+ parents: 0,
1635
+ interior: {
1636
+ x1: [{
1637
+ AccountId32: {
1638
+ id: u8aToHex(decodeAddress(ahAddress))
1639
+ }
1640
+ }]
1641
+ }
1642
+ }
1643
+ }
1644
+ }]
1645
+ }, {
1646
+ initiateReserveWithdraw: {
1647
+ assets: {
1648
+ Wild: {
1649
+ AllOf: {
1650
+ id: ERC20_TOKEN_LOCATION,
1651
+ fun: 'Fungible'
1652
+ }
1653
+ }
1654
+ },
1655
+ reserve: BRIDGE_LOCATION,
1656
+ xcm: [{
1657
+ buyExecution: {
1658
+ fees: {
1659
+ id: ERC20_TOKEN_LOCATION_REANCHORED,
1660
+ // CAUTION: Must use reanchored locations.
1661
+ fun: {
1662
+ Fungible: '1' // Offering 1 unit as fee, but it is returned to the destination address.
1663
+ }
1664
+ },
1665
+ weight_limit: 'Unlimited'
1666
+ }
1667
+ }, {
1668
+ depositAsset: {
1669
+ assets: {
1670
+ Wild: {
1671
+ AllCounted: 1
1672
+ }
1673
+ },
1674
+ beneficiary: {
1675
+ parents: 0,
1676
+ interior: {
1677
+ x1: [{
1678
+ AccountKey20: {
1679
+ key: address
1680
+ }
1681
+ }]
1682
+ }
1683
+ }
1684
+ }
1685
+ }, {
1686
+ setTopic: '0x0000000000000000000000000000000000000000000000000000000000000000'
1687
+ }]
1688
+ }
1689
+ }, {
1690
+ setTopic: '0x0000000000000000000000000000000000000000000000000000000000000000'
1691
+ }];
1692
+ _context.next = 20;
1693
+ return api.init(from);
1694
+ case 20:
1695
+ apiPjs = api.getApi();
1696
+ _context.next = 23;
1697
+ return api.createApiForNode('AssetHubPolkadot');
1698
+ case 23:
1699
+ assetHubApi = _context.sent;
1700
+ assetHubApiPjs = assetHubApi.getApi(); // Generate an unique messageId and set into `setTopic` for remote track
1701
+ xcmHash = assetHubApiPjs.createType('Xcm', customXcm);
1702
+ if (!isEthersSigner(signer)) {
1703
+ _context.next = 32;
1704
+ break;
1705
+ }
1706
+ _context.next = 29;
1707
+ return signer.getAddress();
1708
+ case 29:
1709
+ _context.t0 = _context.sent;
1710
+ _context.next = 33;
1711
+ break;
1712
+ case 32:
1713
+ _context.t0 = (_signer$account = signer.account) === null || _signer$account === undefined ? undefined : _signer$account.address;
1714
+ case 33:
1715
+ sender = _context.t0;
1716
+ _context.next = 36;
1717
+ return Promise.all([apiPjs.query.parachainInfo.parachainId(), apiPjs.rpc.system.accountNextIndex(sender)]);
1718
+ case 36:
1719
+ _yield$Promise$all = _context.sent;
1720
+ _yield$Promise$all2 = _slicedToArray(_yield$Promise$all, 2);
1721
+ parachainId = _yield$Promise$all2[0];
1722
+ accountNextId = _yield$Promise$all2[1];
1723
+ entropy = new Uint8Array([].concat(_toConsumableArray(parachainId.toU8a()), _toConsumableArray(accountNextId.toU8a()), _toConsumableArray(xcmHash.toU8a())));
1724
+ messageId = blake2AsHex(entropy);
1725
+ if (!(customXcm.length == 2)) {
1726
+ _context.next = 47;
1727
+ break;
1728
+ }
1729
+ customXcm[0].initiateReserveWithdraw.xcm[2].setTopic = messageId;
1730
+ customXcm[1].setTopic = messageId;
1731
+ _context.next = 53;
1732
+ break;
1733
+ case 47:
1734
+ if (!(customXcm.length == 3)) {
1735
+ _context.next = 52;
1736
+ break;
1737
+ }
1738
+ customXcm[1].initiateReserveWithdraw.xcm[2].setTopic = messageId;
1739
+ customXcm[2].setTopic = messageId;
1740
+ _context.next = 53;
1741
+ break;
1742
+ case 52:
1743
+ throw new Error('invalid xcm');
1744
+ case 53:
1745
+ xcmOnDest = assetHubApiPjs.createType('XcmVersionedXcm', {
1746
+ V4: customXcm
1747
+ });
1748
+ customXcmOnDest = xcmOnDest.toHex();
1749
+ _context.next = 57;
1750
+ return calculateFee(assetHubApi);
1751
+ case 57:
1752
+ transferFee = _context.sent;
1753
+ // Partially inspired by Moonbeam XCM-SDK
1754
+ // https://github.com/moonbeam-foundation/xcm-sdk/blob/ab835c15bf41612604b1c858d956a9f07705ed65/packages/sdk/src/contract/contracts/Xtokens/Xtokens.ts#L53
1755
+ createTx = function createTx(func, args) {
1756
+ if (isEthersContract(contract)) {
1757
+ return contract[func].apply(contract, _toConsumableArray(args));
1758
+ }
1759
+ return contract.write[func](args);
1760
+ }; // Execute the custom XCM message with the precompile
1761
+ _context.next = 61;
1762
+ return createTx(isEthersSigner(signer) ? 'transferAssetsUsingTypeAndThenAddress((uint8,bytes[]),(address,uint256)[],uint8,uint8,uint8,bytes)' : 'transferAssetsUsingTypeAndThenAddress', [
1763
+ // This represents (1,X1(Parachain(1000)))
1764
+ [1, ['0x00' + numberToHex(getParaId('AssetHubPolkadot'), 32).slice(2)]],
1765
+ // Assets including fee and the ERC20 asset, with fee be the first
1766
+ [[XCDOT, transferFee], [ethAsset.assetId, currency.amount]],
1767
+ // The TransferType corresponding to asset being sent, 2 represents `DestinationReserve`
1768
+ 2,
1769
+ // index for the fee
1770
+ 0,
1771
+ // The TransferType corresponding to fee asset
1772
+ 2, customXcmOnDest]);
1773
+ case 61:
1774
+ tx = _context.sent;
1775
+ return _context.abrupt("return", _typeof(tx) === 'object' ? tx.hash : tx);
1776
+ case 63:
1777
+ case "end":
1778
+ return _context.stop();
1779
+ }
1780
+ }, _callee);
1781
+ }));
1782
+ return function transferMoonbeamToEth(_x) {
1783
+ return _ref2.apply(this, arguments);
1784
+ };
1785
+ }();
1786
+
1458
1787
  /**
1459
1788
  * Builder class for constructing transfers from Ethereum to Polkadot.
1460
1789
  */
@@ -1503,8 +1832,9 @@ var EvmBuilderClass = /*#__PURE__*/function () {
1503
1832
  */
1504
1833
  }, {
1505
1834
  key: "address",
1506
- value: function address(_address) {
1835
+ value: function address(_address, ahAddress) {
1507
1836
  this._options.address = _address;
1837
+ this._options.ahAddress = ahAddress;
1508
1838
  return this;
1509
1839
  }
1510
1840
  /**
@@ -1550,22 +1880,35 @@ var EvmBuilderClass = /*#__PURE__*/function () {
1550
1880
  _context.next = 2;
1551
1881
  break;
1552
1882
  case 9:
1883
+ validateAddress(this._options.address, this._options.to);
1884
+ if (!(this._options.from === 'Moonbeam' && this._options.to === 'Ethereum')) {
1885
+ _context.next = 12;
1886
+ break;
1887
+ }
1888
+ return _context.abrupt("return", transferMoonbeamToEth(this._options));
1889
+ case 12:
1553
1890
  if (!(this._options.from === 'Moonbeam' || this._options.from === 'Moonriver')) {
1554
- _context.next = 13;
1891
+ _context.next = 16;
1555
1892
  break;
1556
1893
  }
1557
- _context.next = 12;
1894
+ _context.next = 15;
1558
1895
  return transferMoonbeamEvm(this._options);
1559
- case 12:
1896
+ case 15:
1560
1897
  return _context.abrupt("return", _context.sent);
1561
- case 13:
1562
- _context.next = 15;
1898
+ case 16:
1899
+ if (!(this._options.from === 'Ethereum')) {
1900
+ _context.next = 22;
1901
+ break;
1902
+ }
1903
+ _context.next = 19;
1563
1904
  return transferEthToPolkadot$1(this._options);
1564
- case 15:
1905
+ case 19:
1565
1906
  _yield$transferEthToP = _context.sent;
1566
1907
  response = _yield$transferEthToP.response;
1567
1908
  return _context.abrupt("return", response.hash);
1568
- case 18:
1909
+ case 22:
1910
+ throw new Error('Scenario not supported');
1911
+ case 23:
1569
1912
  case "end":
1570
1913
  return _context.stop();
1571
1914
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@paraspell/sdk-pjs",
3
- "version": "8.3.0",
3
+ "version": "8.4.0",
4
4
  "description": "Polkadot.js based SDK for ParaSpell XCM/XCMP tool for developers",
5
5
  "repository": {
6
6
  "type": "git",
@@ -27,7 +27,7 @@
27
27
  "@snowbridge/contract-types": "^0.1.32",
28
28
  "ethers": "^6.13.5",
29
29
  "viem": "^2.22.22",
30
- "@paraspell/sdk-core": "8.3.0"
30
+ "@paraspell/sdk-core": "8.4.0"
31
31
  },
32
32
  "peerDependencies": {
33
33
  "@polkadot/api": ">= 15.0 < 16",