@shapeshiftoss/swapper 17.0.1 → 17.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,3 @@
1
+ import { ChainId } from '@shapeshiftoss/caip';
2
+ export declare const isValidMemoAddress: (chainId: ChainId, thorId: string, address: string) => boolean;
3
+ export declare const assertIsValidMemo: (memo: string) => void;
@@ -0,0 +1,66 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.assertIsValidMemo = exports.isValidMemoAddress = void 0;
7
+ const caip_1 = require("@shapeshiftoss/caip");
8
+ const chain_adapters_1 = require("@shapeshiftoss/chain-adapters");
9
+ const multicoin_address_validator_1 = __importDefault(require("multicoin-address-validator"));
10
+ const api_1 = require("../../../../api");
11
+ const thorChainAssetToChainId = new Map([
12
+ ['ETH', caip_1.ethChainId],
13
+ ['AVAX', caip_1.avalancheChainId],
14
+ ['BTC', caip_1.btcChainId],
15
+ ['BCH', caip_1.bchChainId],
16
+ ['LTC', caip_1.ltcChainId],
17
+ ['BNB', caip_1.binanceChainId],
18
+ ['DOGE', caip_1.dogeChainId],
19
+ ['GAIA', caip_1.cosmosChainId],
20
+ ['RUNE', caip_1.thorchainChainId],
21
+ ]);
22
+ const isValidMemoAddress = (chainId, thorId, address) => {
23
+ switch (true) {
24
+ case thorId.startsWith('ETH.'):
25
+ case thorId.startsWith('AVAX.'):
26
+ case thorId.startsWith('BTC.'):
27
+ case thorId.startsWith('BCH.'):
28
+ case thorId.startsWith('LTC.'):
29
+ case thorId.startsWith('BNB.'):
30
+ case thorId.startsWith('DOGE.'): {
31
+ const chainLabel = (0, chain_adapters_1.chainIdToChainLabel)(chainId);
32
+ return multicoin_address_validator_1.default.validate(address, chainLabel);
33
+ }
34
+ case thorId.startsWith('GAIA.'):
35
+ return address.startsWith('cosmos');
36
+ case thorId.startsWith('RUNE.'):
37
+ return address.startsWith('thor');
38
+ default:
39
+ return false;
40
+ }
41
+ };
42
+ exports.isValidMemoAddress = isValidMemoAddress;
43
+ const assertIsValidMemo = (memo) => {
44
+ // BTC (and likely other utxo coins) can only support up to 80 character (byte) memos
45
+ const MAX_MEMO_LENGTH = 80;
46
+ const MEMO_PART_DELIMITER = ':';
47
+ const POOL_PART_DELIMITER = '.';
48
+ const memoParts = memo.split(MEMO_PART_DELIMITER);
49
+ const pool = memoParts[1];
50
+ const address = memoParts[2];
51
+ const buyAssetChainId = thorChainAssetToChainId.get(pool.split(POOL_PART_DELIMITER)[0]);
52
+ const isAddressValid = buyAssetChainId
53
+ ? (0, exports.isValidMemoAddress)(buyAssetChainId, pool, address)
54
+ : undefined;
55
+ if (!isAddressValid) {
56
+ throw new api_1.SwapError(`[makeSwapMemo] - memo ${memo} invalid`, {
57
+ code: api_1.SwapErrorType.MAKE_MEMO_FAILED,
58
+ });
59
+ }
60
+ if (memo.length > MAX_MEMO_LENGTH) {
61
+ throw new api_1.SwapError(`[makeSwapMemo] - memo length exceeds ${MAX_MEMO_LENGTH} characters`, {
62
+ code: api_1.SwapErrorType.MAKE_MEMO_FAILED,
63
+ });
64
+ }
65
+ };
66
+ exports.assertIsValidMemo = assertIsValidMemo;
@@ -1,9 +1,20 @@
1
1
  /**
2
- * @returns thorchain memo shortened to a max of 80 characters as described:
3
- * https://dev.thorchain.org/thorchain-dev/memos#mechanism-for-transaction-intent
2
+ * definition of THORChain asset notation
3
+ * https://dev.thorchain.org/thorchain-dev/concepts/memos#asset-notation
4
+ *
5
+ * e.g. BTC/BTC (bitcoin synth) - unaffected by this function
6
+ * e.g. ETH.USDT-0xdac17f958d2ee523a2206206994597c13d831ec7 (usdt on ethereum) - abbreviated by this function
4
7
  */
5
- export declare const makeSwapMemo: ({ buyAssetId, destinationAddress, limit, }: {
8
+ export declare const abbreviateThorAssetId: (fullThorAssetId: string) => string;
9
+ declare type MakeSwapMemoArgs = {
6
10
  buyAssetId: string;
7
11
  destinationAddress: string;
8
12
  limit: string;
9
- }) => string;
13
+ };
14
+ declare type MakeSwapMemo = (args: MakeSwapMemoArgs) => string;
15
+ /**
16
+ * @returns thorchain memo shortened to a max of 80 characters as described:
17
+ * https://dev.thorchain.org/thorchain-dev/memos#mechanism-for-transaction-intent
18
+ */
19
+ export declare const makeSwapMemo: MakeSwapMemo;
20
+ export {};
@@ -1,22 +1,55 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.makeSwapMemo = void 0;
3
+ exports.makeSwapMemo = exports.abbreviateThorAssetId = void 0;
4
4
  const caip_1 = require("@shapeshiftoss/caip");
5
5
  const api_1 = require("../../../../api");
6
6
  const constants_1 = require("../constants");
7
- // BTC (and likely other utxo coins) can only support up to 80 character memos
8
- const MAX_LENGTH = 80;
7
+ const assertIsValidMemo_1 = require("./assertIsValidMemo");
8
+ /**
9
+ * definition of THORChain asset notation
10
+ * https://dev.thorchain.org/thorchain-dev/concepts/memos#asset-notation
11
+ *
12
+ * e.g. BTC/BTC (bitcoin synth) - unaffected by this function
13
+ * e.g. ETH.USDT-0xdac17f958d2ee523a2206206994597c13d831ec7 (usdt on ethereum) - abbreviated by this function
14
+ */
15
+ const abbreviateThorAssetId = (fullThorAssetId) => {
16
+ const CONTRACT_ADDRESS_DELIMITER = '-';
17
+ const [existingPrefix, contractAddress] = fullThorAssetId.split(CONTRACT_ADDRESS_DELIMITER);
18
+ // we can't shorten any asset that doesn't have a contract address
19
+ if (!contractAddress)
20
+ return fullThorAssetId;
21
+ /**
22
+ * https://dev.thorchain.org/thorchain-dev/concepts/memos#asset-abbreviations
23
+ *
24
+ * ETH.USDT
25
+ * ETH.USDT-ec7 // 3 characters - "short"
26
+ * ETH.USDT-6994597c13d831ec7 // 17 characters - "medium"
27
+ * ETH.USDT-0xdac17f958d2ee523a2206206994597c13d831ec7 // 26 characters - "long"
28
+ */
29
+ /**
30
+ * for the purposes of future proofing, let's use the shortest permissible format for contract addresses
31
+ * this has (26 + 10)^3 = 46,656 of entropy, and per the docs, the deepest pool will be used upon a collision
32
+ */
33
+ const SHORT_ABBREVIATION_LENGTH = 3;
34
+ // take the last n characters of the contract address (negative slice takes last n characters)
35
+ const shortenedContractAddress = contractAddress.slice(-SHORT_ABBREVIATION_LENGTH);
36
+ // and put it back together with the existing prefix
37
+ return [existingPrefix, shortenedContractAddress].join(CONTRACT_ADDRESS_DELIMITER);
38
+ };
39
+ exports.abbreviateThorAssetId = abbreviateThorAssetId;
9
40
  // use symbol of thor Asset?
10
41
  const runeThorId = 'RUNE';
11
42
  /**
12
43
  * @returns thorchain memo shortened to a max of 80 characters as described:
13
44
  * https://dev.thorchain.org/thorchain-dev/memos#mechanism-for-transaction-intent
14
45
  */
15
- const makeSwapMemo = ({ buyAssetId, destinationAddress, limit, }) => {
46
+ const makeSwapMemo = ({ buyAssetId, destinationAddress, limit }) => {
16
47
  const isRune = buyAssetId === caip_1.thorchainAssetId;
17
- const thorId = isRune ? runeThorId : caip_1.adapters.assetIdToPoolAssetId({ assetId: buyAssetId });
18
- if (!thorId)
19
- throw new api_1.SwapError('[makeSwapMemo] - undefined thorId for given buyAssetId', {
48
+ const fullThorAssetId = isRune
49
+ ? runeThorId
50
+ : caip_1.adapters.assetIdToPoolAssetId({ assetId: buyAssetId });
51
+ if (!fullThorAssetId)
52
+ throw new api_1.SwapError('[makeSwapMemo] - undefined thorAssetId for given buyAssetId', {
20
53
  code: api_1.SwapErrorType.MAKE_MEMO_FAILED,
21
54
  details: { buyAssetId },
22
55
  });
@@ -27,21 +60,9 @@ const makeSwapMemo = ({ buyAssetId, destinationAddress, limit, }) => {
27
60
  const parsedDestinationAddress = destinationAddress.includes('bitcoincash:')
28
61
  ? destinationAddress.replace('bitcoincash:', '')
29
62
  : destinationAddress;
30
- const memo = `s:${thorId}:${parsedDestinationAddress}:${limit}:${constants_1.THORCHAIN_AFFILIATE_NAME}:${constants_1.THORCHAIN_AFFILIATE_BIPS}`;
31
- if (memo.length <= MAX_LENGTH)
32
- return memo;
33
- const abbreviationAmount = memo.length - MAX_LENGTH;
34
- if (abbreviationAmount > 39)
35
- throw new api_1.SwapError('[makeSwapMemo] - too much abbreviation for accurate matching', {
36
- code: api_1.SwapErrorType.MAKE_MEMO_FAILED,
37
- });
38
- // delimeter between ticker and id allowing us to abbreviate the id: https://dev.thorchain.org/thorchain-dev/memos#asset-notation
39
- const delimeterIndex = memo.indexOf('-') + 1;
40
- if (!delimeterIndex) {
41
- throw new api_1.SwapError('[makeSwapMemo] - unable to abbreviate asset, no delimeter found', {
42
- code: api_1.SwapErrorType.MAKE_MEMO_FAILED,
43
- });
44
- }
45
- return memo.replace(memo.slice(delimeterIndex, delimeterIndex + abbreviationAmount), '');
63
+ const abbreviatedThorAssetId = (0, exports.abbreviateThorAssetId)(fullThorAssetId);
64
+ const memo = `s:${abbreviatedThorAssetId}:${parsedDestinationAddress}:${limit}:${constants_1.THORCHAIN_AFFILIATE_NAME}:${constants_1.THORCHAIN_AFFILIATE_BIPS}`;
65
+ (0, assertIsValidMemo_1.assertIsValidMemo)(memo);
66
+ return memo;
46
67
  };
47
68
  exports.makeSwapMemo = makeSwapMemo;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shapeshiftoss/swapper",
3
- "version": "17.0.1",
3
+ "version": "17.1.0",
4
4
  "description": "An interface and implementations to trade coins via various protocols",
5
5
  "repository": "https://github.com/shapeshift/lib",
6
6
  "license": "MIT",