Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix broken AssetFromString() #1341

Merged
merged 2 commits into from
Jan 20, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changeset/large-ravens-lay.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@xchainjs/xchain-thorchain-query': patch
'@xchainjs/xchain-solana': patch
'@xchainjs/xchain-util': patch
---

fix assetFromString util function
5 changes: 5 additions & 0 deletions .changeset/ninety-toys-shake.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@xchainjs/xchain-util': patch
---

Fix broken assetFromString()
4 changes: 4 additions & 0 deletions packages/xchain-solana/__tests__/client.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,10 @@ describe('Solana client', () => {
})

describe('Addresses', () => {
let client: Client
beforeAll(() => {
client = new Client()
})
it('Should not get address without phrase', () => {
expect(async () => await client.getAddressAsync()).rejects.toThrowError('Phrase must be provided')
})
Expand Down
2 changes: 1 addition & 1 deletion packages/xchain-solana/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
"@metaplex-foundation/mpl-token-metadata": "3.2.1",
"@metaplex-foundation/umi": "0.9.2",
"@metaplex-foundation/umi-bundle-defaults": "0.9.2",
"@solana/addresses": "2.0.0-rc.1",
"@solana/addresses": "2.0.0",
"@solana/spl-token": "0.4.8",
"@solana/web3.js": "1.95.2",
"@xchainjs/xchain-client": "workspace:*",
Expand Down
4 changes: 4 additions & 0 deletions packages/xchain-thorchain-query/src/thorchain-query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
AssetCryptoAmount,
Chain,
CryptoAmount,
SECURED_ASSET_DELIMITER,
SYNTH_ASSET_DELIMITER,
SecuredAsset,
SynthAsset,
Expand Down Expand Up @@ -1614,6 +1615,7 @@ export class ThorchainQuery {
['c', 'BCH.BCH'],
['a', 'AVAX.AVAX'],
['s', 'BSC.BNB'],
['f', 'BASE.ETH'],
])

const nativeAsset = nativeAlias.get(alias.toLowerCase())
Expand All @@ -1625,6 +1627,8 @@ export class ThorchainQuery {
delimiter = TRADE_ASSET_DELIMITER
} else if (alias.includes(SYNTH_ASSET_DELIMITER)) {
delimiter = SYNTH_ASSET_DELIMITER
} else if (alias.includes(SECURED_ASSET_DELIMITER)) {
delimiter = SECURED_ASSET_DELIMITER
}

const splitedAlias = alias.split(delimiter)
Expand Down
38 changes: 37 additions & 1 deletion packages/xchain-thorchain/__e2e__/keystore-client.e2e.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
import { Tx } from '@xchainjs/xchain-client'
import { assetAmount, assetFromStringEx, assetToBase, assetToString, baseToAsset } from '@xchainjs/xchain-util'
import {
AssetType,
SecuredAsset,
assetAmount,
assetFromStringEx,
assetToBase,
assetToString,
baseToAsset,
} from '@xchainjs/xchain-util'

import { AssetRuneNative as AssetRune, Client, DepositTx } from '../src'

Expand Down Expand Up @@ -47,6 +55,12 @@ const getPrintableDepositTx = (depositTx: DepositTx) => {
}),
}
}
const BTCSECURED: SecuredAsset = {
chain: 'BTC',
ticker: 'BTC',
symbol: 'BTC',
type: AssetType.SECURED,
}

describe('Thorchain Keystore', () => {
let client: Client
Expand Down Expand Up @@ -143,6 +157,28 @@ describe('Thorchain Keystore', () => {
}
})

it('Should make secured Asset swap', async () => {
try {
/**
* MAKE SURE TO TEST THIS FUNCTION WITH YOUR ADDRESS BNB, OTHERWISE, YOU COULD LOSE FUNDS
*/
const address: string = 'thor1rkpukrhljr72sxww2t0nwvng84zegp59805e03' || 'TO_BE_DEFINED'
if (address === 'TO_BE_DEFINED') throw Error('Set an address to try the deposit e2e function')
const memo = `=:AVAX-AVAX:${address}`

const hash = await client.deposit({
walletIndex: 0,
amount: assetToBase(assetAmount(0.00024005, 8)),
asset: BTCSECURED,
memo,
})
console.log(hash)
} catch (error) {
console.log(error)
throw error
}
})

it('Should transfer offline', async () => {
const txRaw = await client.transferOffline({
walletIndex: 0,
Expand Down
37 changes: 31 additions & 6 deletions packages/xchain-util/__tests__/asset.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -343,15 +343,35 @@ describe('asset', () => {
expect(result).toEqual({ chain: 'ETH', symbol: 'ETH', ticker: 'ETH', type: AssetType.TRADE })
})

it('trade BTC-BTC', () => {
it('secured BTC-BTC', () => {
const result = assetFromString('BTC-BTC')
expect(result).toEqual({ chain: 'BTC', symbol: 'BTC', ticker: 'BTC', type: AssetType.SECURED })
})
it('trade ETH-ETH', () => {
it('secured ETH-ETH', () => {
const result = assetFromString('ETH-ETH')
expect(result).toEqual({ chain: 'ETH', symbol: 'ETH', ticker: 'ETH', type: AssetType.SECURED })
})

it('secured AVAX-SOL-0XFE6B19286885A4F7F55ADAD09C3CD1F906D2478', () => {
const result = assetFromString('AVAX-SOL-0XFE6B19286885A4F7F55ADAD09C3CD1F906D2478')
expect(result).toEqual({
chain: 'AVAX',
symbol: 'SOL-0XFE6B19286885A4F7F55ADAD09C3CD1F906D2478',
ticker: 'SOL',
type: AssetType.SECURED,
})
})

it('synth ETH/USDC-0XA0B86991C6218B36C1D19D4A2E9EB0CE3606EB48', () => {
const result = assetFromString('ETH/USDC-0XA0B86991C6218B36C1D19D4A2E9EB0CE3606EB48')
expect(result).toEqual({
chain: 'ETH',
symbol: 'USDC-0XA0B86991C6218B36C1D19D4A2E9EB0CE3606EB48',
ticker: 'USDC',
type: AssetType.SYNTH,
})
})

it('KUJI.USK', () => {
const result = assetFromString('KUJI.USK')
expect(result).toEqual({ chain: 'KUJI', symbol: 'USK', ticker: 'USK', type: AssetType.TOKEN })
Expand Down Expand Up @@ -398,10 +418,6 @@ describe('asset', () => {
const result = assetFromString('.BNB.BNB')
expect(result).toBeNull()
})
it('null for invalid chain', () => {
const result = assetFromString('invalid.BNB.BNB')
expect(result).toEqual({ chain: 'invalid', symbol: 'BNB', type: AssetType.NATIVE, ticker: 'BNB' })
})
})

describe('assetToString', () => {
Expand All @@ -413,6 +429,15 @@ describe('asset', () => {
const asset: Asset = { chain: 'ETH', symbol: 'ETH', ticker: 'ETH', type: AssetType.NATIVE }
expect(assetToString(asset)).toEqual('ETH.ETH')
})
it('DAI string test', () => {
const asset: TokenAsset = {
chain: 'ETH',
symbol: 'DAI-0X6B175474E89094C44DA98B954EEDEAC495271D0F',
ticker: 'DAI',
type: AssetType.TOKEN,
}
expect(assetToString(asset)).toEqual('ETH.DAI-0X6B175474E89094C44DA98B954EEDEAC495271D0F')
})
it('ETH/ETH', () => {
const asset: SynthAsset = { chain: 'ETH', symbol: 'ETH', ticker: 'ETH', type: AssetType.SYNTH }
expect(assetToString(asset)).toEqual('ETH/ETH')
Expand Down
52 changes: 35 additions & 17 deletions packages/xchain-util/src/asset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -278,41 +278,59 @@ const assetConfigs = new Map<string, AnyAsset>([
['RUNE', { chain: 'THOR', symbol: 'RUNE', ticker: 'RUNE', type: AssetType.NATIVE }],
])

const createAsset = (chain: string, symbol: string, ticker: string, type: AssetType) => {
// Helper function to create an asset from its components
const createAsset = (chain: string, symbol: string, ticker: string, type: AssetType): AnyAsset => {
return { chain, symbol, ticker, type }
}

export const assetFromString = (s: string): AnyAsset | null => {
if (!s || s.trim() === '') return null // Handle empty strings

// Check if the asset is directly in the assetConfigs
const directAsset = assetConfigs.get(s)
if (directAsset) return directAsset

// Define possible delimiters and their associated asset types
const delimiters: Record<'.' | '/' | '~' | '-', AssetType> = {
// Define asset delimiters for the first delimiter
const assetDelimiters: Record<string, AssetType> = {
'.': AssetType.NATIVE,
'/': AssetType.SYNTH,
'~': AssetType.TRADE,
'-': AssetType.SECURED,
}

// Identify the first delimiter
const delimiter = Object.keys(delimiters).find((delim) => s.includes(delim)) as '.' | '/' | '~' | '-' | undefined
if (!delimiter) return null
// Identify the first delimiter in the string
const firstDelimiter = Object.keys(assetDelimiters).find((delim) => s.includes(delim)) as
| keyof typeof assetDelimiters
| undefined
if (!firstDelimiter) return null

// Split the string by the first delimiter
const [chain, symbol] = s.split(delimiter)
if (!chain || !symbol) return null
// Split the string into chain and symbol part based on the first delimiter
const [chain, ...restParts] = s.split(firstDelimiter)

// Determine initial type based on delimiter
let type = delimiters[delimiter]
if (!chain || restParts.length === 0) return null // Invalid format or empty parts

// Additional checks for token classification
if (delimiter === '.' && symbol.includes('-')) {
type = AssetType.TOKEN
}
// Handle secured and trade assets which may have further splits
const symbol = restParts.join(firstDelimiter)
let ticker = symbol.split('-')[0]

// Extract the ticker from the symbol (first part before `-` if it exists)
const ticker = symbol.split('-')[0]
// For secured and trade assets, handle contract address as part of the symbol
const type = assetDelimiters[firstDelimiter]

// Check if symbol is empty (e.g., BNB. or AVAX~ cases)
if (symbol === '') return null
// Handle trade and secured assets
if (firstDelimiter === '~' || firstDelimiter === '-' || firstDelimiter === '/') {
return createAsset(chain.trim(), symbol.trim(), ticker.trim(), type)
}
// Handle token assets: if the symbol has more than one part (split by `-`)
if (symbol.includes('-')) {
const [primaryTicker] = symbol.split('-')
ticker = primaryTicker

// For token assets, use the contract address
return createAsset(chain.trim(), symbol.trim(), ticker.trim(), AssetType.TOKEN)
}
// For native, synth, or other types of assets
return createAsset(chain.trim(), symbol.trim(), ticker.trim(), type)
}

Expand Down
Loading
Loading