@swapkit/helpers
Advanced tools
Comparing version 0.0.0-nightly-20240607015403 to 0.0.0-nightly-20240718103505
@@ -5,15 +5,14 @@ { | ||
"dependencies": { | ||
"ky": "1.2.3", | ||
"@swapkit/tokens": "1.0.3", | ||
"picocolors": "1.0.1", | ||
"zod": "3.23.8" | ||
}, | ||
"devDependencies": { | ||
"@swapkit/tokens": "0.0.0-nightly-20240607015403", | ||
"bun-types": "1.1.8", | ||
"ethers": "6.11.1" | ||
"@swapkit/toolbox-cosmos": "0.0.0-nightly-20240718103505", | ||
"@swapkit/toolbox-evm": "0.0.0-nightly-20240718103505", | ||
"@swapkit/toolbox-solana": "0.0.0-nightly-20240718103505", | ||
"@swapkit/toolbox-radix": "0.0.0-nightly-20240718103505", | ||
"@swapkit/toolbox-substrate": "0.0.0-nightly-20240718103505", | ||
"@swapkit/toolbox-utxo": "0.0.0-nightly-20240718103505" | ||
}, | ||
"peerDependencies": { | ||
"@swapkit/tokens": "0.0.0-nightly-20240607015403", | ||
"ky": "1.2.3", | ||
"zod": "3.23.8" | ||
}, | ||
"files": [ | ||
@@ -34,6 +33,6 @@ "src/", | ||
"build": "bun run ./build.ts", | ||
"clean": "rm -rf .turbo dist node_modules *.tsbuildinfo", | ||
"lint": "biome check --apply ./src", | ||
"clean": "rm -rf dist node_modules *.tsbuildinfo", | ||
"lint": "biome check --write ./src", | ||
"test": "bun test", | ||
"test:coverage": "echo 'bun test --coverage'", | ||
"test:coverage": "bun test --coverage", | ||
"type-check": "tsc --noEmit" | ||
@@ -43,3 +42,3 @@ }, | ||
"types": "./src/index.ts", | ||
"version": "0.0.0-nightly-20240607015403" | ||
"version": "0.0.0-nightly-20240718103505" | ||
} |
@@ -39,9 +39,2 @@ import { describe, expect, test } from "bun:test"; | ||
describe("for Binance chain", () => { | ||
test('should return "BEP2" for non-BNB tickers', () => { | ||
const result = getAssetType({ chain: Chain.Binance, symbol: "NOT_BNB" }); | ||
expect(result).toBe("BEP2"); | ||
}); | ||
}); | ||
describe("for Binance Smart Chain", () => { | ||
@@ -185,3 +178,3 @@ test('should return "BEP20" for non-BNB tickers', () => { | ||
describe("Radix", () => { | ||
test( | ||
test.todo( | ||
"returns proper decimal for radix and it's assets", | ||
@@ -230,3 +223,3 @@ async () => { | ||
test("should return the correct object for Radix resource", () => { | ||
test.todo("should return the correct object for Radix resource", () => { | ||
const assetString = | ||
@@ -233,0 +226,0 @@ "XRD.xwBTC-resource_rdx1t580qxc7upat7lww4l2c4jckacafjeudxj5wpjrrct0p3e82sq4y75"; |
import { describe, expect, test } from "bun:test"; | ||
import { Chain, MemoType } from "../../types"; | ||
import { getMemoFor } from "../memo.ts"; | ||
import { | ||
getMemoForDeposit, | ||
getMemoForLeaveAndBond, | ||
getMemoForNamePreferredAssetRegister, | ||
getMemoForNameRegister, | ||
getMemoForSaverDeposit, | ||
getMemoForSaverWithdraw, | ||
getMemoForWithdraw, | ||
} from "../memo.ts"; | ||
describe("getMemoFor", () => { | ||
describe("for Leave, Upgrade, and Bond", () => { | ||
const nodeMemos = [ | ||
[MemoType.LEAVE, "LEAVE:ABC123"], | ||
[MemoType.BOND, "BOND:ABC123"], | ||
]; | ||
for (const [memoType, expected = ""] of nodeMemos) { | ||
test(`returns correct memo for ${memoType}`, () => { | ||
const result = getMemoFor(memoType as MemoType, { address: "ABC123" }); | ||
expect(result).toBe(expected); | ||
}); | ||
} | ||
describe("getMemoForSaverDeposit", () => { | ||
test("returns correct memo for single side", () => { | ||
const result = getMemoForSaverDeposit({ chain: Chain.Ethereum, symbol: "ETH" }); | ||
expect(result).toBe("+:ETH/ETH"); | ||
}); | ||
}); | ||
describe("for Unbond and Thorname/Mayaname Register", () => { | ||
test("returns correct memo for Unbond", () => { | ||
const result = getMemoFor(MemoType.UNBOND, { address: "ABC123", unbondAmount: 1000000000 }); | ||
expect(result).toBe("UNBOND:ABC123:1000000000"); | ||
describe("getMemoForSaverWithdraw", () => { | ||
test("returns correct memo for single side", () => { | ||
const result = getMemoForSaverWithdraw({ | ||
basisPoints: 5000, | ||
chain: Chain.Ethereum, | ||
symbol: "ETH", | ||
}); | ||
expect(result).toBe("-:ETH/ETH:5000"); | ||
}); | ||
}); | ||
test("returns correct memo for Thorname Register", () => { | ||
const result = getMemoFor(MemoType.THORNAME_REGISTER, { | ||
name: "thorname", | ||
chain: "BNB", | ||
address: "0xABC123", | ||
owner: "0xDEF456", | ||
}); | ||
expect(result).toBe("~:thorname:BNB:0xABC123:0xDEF456"); | ||
}); | ||
describe("getMemoForLeaveAndBond", () => { | ||
test("returns correct memo for Leave", () => { | ||
const result = getMemoForLeaveAndBond({ address: "ABC123", type: MemoType.LEAVE }); | ||
expect(result).toBe("LEAVE:ABC123"); | ||
}); | ||
test("returns correct memo for Mayaname Register", () => { | ||
const result = getMemoFor(MemoType.THORNAME_REGISTER, { | ||
name: "mayaname", | ||
chain: "BNB", | ||
address: "0xABC123", | ||
owner: "0xDEF456", | ||
}); | ||
expect(result).toBe("~:mayaname:BNB:0xABC123:0xDEF456"); | ||
}); | ||
test("returns correct memo for Bond", () => { | ||
const result = getMemoForLeaveAndBond({ address: "ABC123", type: MemoType.BOND }); | ||
expect(result).toBe("BOND:ABC123"); | ||
}); | ||
}); | ||
describe("for Deposit", () => { | ||
test("returns correct memo for Deposit (single side)", () => { | ||
const result = getMemoFor(MemoType.DEPOSIT, { | ||
chain: Chain.Ethereum, | ||
symbol: "ETH", | ||
singleSide: true, | ||
}); | ||
expect(result).toBe("+:ETH/ETH"); | ||
describe("getMemoForNameRegister", () => { | ||
test("returns correct memo for single side", () => { | ||
const result = getMemoForNameRegister({ | ||
name: "asdfg", | ||
chain: Chain.Ethereum, | ||
owner: "thor1234", | ||
address: "0xaasd123", | ||
}); | ||
expect(result).toBe("~:asdfg:ETH:0xaasd123:thor1234"); | ||
}); | ||
}); | ||
test("returns correct memo for Deposit (dual side)", () => { | ||
const result = getMemoFor(MemoType.DEPOSIT, { | ||
chain: Chain.Avalanche, | ||
symbol: "AVAX", | ||
address: "0xABC123", | ||
}); | ||
expect(result).toBe("+:AVAX.AVAX:0xABC123"); | ||
describe("getMemoForNamePreferredAssetRegister", () => { | ||
test("returns correct memo for single side", () => { | ||
const result = getMemoForNamePreferredAssetRegister({ | ||
name: "asdfg", | ||
chain: Chain.Ethereum, | ||
owner: "thor1234", | ||
asset: "ETH.USDC-0XA0B86991C6218B36C1D19D4A2E9EB0CE3606EB48", | ||
payout: "0x6621d872f17109d6601c49edba526ebcfd332d5d", | ||
}); | ||
expect(result).toBe( | ||
"~:asdfg:ETH:0x6621d872f17109d6601c49edba526ebcfd332d5d:thor1234:ETH.USDC-0XA0B86991C6218B36C1D19D4A2E9EB0CE3606EB48", | ||
); | ||
}); | ||
}); | ||
describe("for Withdraw", () => { | ||
test("returns correct memo for Withdraw (single side)", () => { | ||
const result = getMemoFor(MemoType.WITHDRAW, { | ||
chain: Chain.Bitcoin, | ||
ticker: "BTC", | ||
symbol: "BTC", | ||
basisPoints: 10000, | ||
singleSide: true, | ||
}); | ||
expect(result).toBe("-:BTC/BTC:10000"); | ||
describe("getMemoForDeposit", () => { | ||
test("returns correct memo for single side", () => { | ||
const result = getMemoForDeposit({ chain: Chain.Ethereum, symbol: "ETH" }); | ||
expect(result).toBe("+:ETH.ETH"); | ||
}); | ||
test("returns correct memo when paired address is not available but affiliate info is present", () => { | ||
const result = getMemoForDeposit({ | ||
chain: Chain.Ethereum, | ||
symbol: "ETH", | ||
affiliateAddress: "thor1abc123", | ||
affiliateBasisPoints: 500, | ||
}); | ||
expect(result).toBe("+:ETH.ETH::thor1abc123:500"); | ||
}); | ||
}); | ||
test("returns correct memo for Withdraw (dual side)", () => { | ||
const result = getMemoFor(MemoType.WITHDRAW, { | ||
chain: Chain.Ethereum, | ||
ticker: "ETH", | ||
symbol: "ETH", | ||
basisPoints: 100, | ||
targetAssetString: "ETH.ETH", | ||
}); | ||
expect(result).toBe("-:ETH.ETH:100:ETH.ETH"); | ||
describe("getMemoForWithdraw", () => { | ||
test("returns correct memo for single side", () => { | ||
const result = getMemoForWithdraw({ | ||
chain: Chain.Ethereum, | ||
symbol: "ETH", | ||
ticker: "ETH", | ||
basisPoints: 100, | ||
}); | ||
expect(result).toBe("-:ETH.ETH:100"); | ||
}); | ||
}); |
import { describe, expect, test } from "bun:test"; | ||
import { Chain, type DerivationPathArray } from "../../types"; | ||
import { Chain } from "../../types"; | ||
import { findAssetBy } from "../asset.ts"; | ||
import { derivationPathToString, getTHORNameCost } from "../others.ts"; | ||
import { getTHORNameCost } from "../others.ts"; | ||
describe("derivationPathToString", () => { | ||
test("should return the correct string for a full path", () => { | ||
const path = [1, 2, 3, 4, 5] as DerivationPathArray; | ||
expect(derivationPathToString(path)).toEqual("m/1'/2'/3'/4/5"); | ||
}); | ||
test("should return the correct string for a short path", () => { | ||
const path = [1, 2, 3, 4] as DerivationPathArray; | ||
expect(derivationPathToString(path)).toEqual("m/1'/2'/3'/4"); | ||
}); | ||
}); | ||
describe("getTHORNameCost", () => { | ||
@@ -37,3 +25,3 @@ describe("for correct values", () => { | ||
test("throws an error for negative years", () => { | ||
expect(() => getTHORNameCost(-1)).toThrow("Invalid number of year"); | ||
expect(() => getTHORNameCost(-1)).toThrow("helpers_invalid_number_of_years"); | ||
}); | ||
@@ -53,3 +41,5 @@ }); | ||
}); | ||
expect(assetByChainAndContract).toBe("ETH.USDC-0XA0B86991C6218B36C1D19D4A2E9EB0CE3606EB48"); | ||
expect(assetByChainAndContract?.toUpperCase()).toBe( | ||
"ETH.USDC-0XA0B86991C6218B36C1D19D4A2E9EB0CE3606EB48", | ||
); | ||
}); | ||
@@ -56,0 +46,0 @@ |
@@ -0,1 +1,2 @@ | ||
import { AssetValue } from "../modules/assetValue.ts"; | ||
import { RequestClient } from "../modules/requestClient.ts"; | ||
@@ -8,9 +9,15 @@ import { BaseDecimal, Chain, ChainToRPC, type EVMChain, EVMChains } from "../types/chains.ts"; | ||
export type CommonAssetString = | ||
| `${Chain.Maya}.MAYA` | ||
| `${Chain.Ethereum}.THOR` | ||
| `${Chain.Ethereum}.vTHOR` | ||
| `${Chain.Kujira}.USK` | ||
| Chain; | ||
export type CommonAssetString = (typeof CommonAssetStrings)[number] | Chain; | ||
export type ConditionalAssetValueReturn<T extends boolean> = T extends true | ||
? Promise<AssetValue[]> | ||
: AssetValue[]; | ||
export const CommonAssetStrings = [ | ||
`${Chain.Maya}.MAYA`, | ||
`${Chain.Ethereum}.THOR`, | ||
`${Chain.Ethereum}.vTHOR`, | ||
`${Chain.Kujira}.USK`, | ||
] as const; | ||
const getContractDecimals = async ({ chain, to }: { chain: EVMChain; to: string }) => { | ||
@@ -67,3 +74,4 @@ try { | ||
const splitSymbol = symbol.split("-"); | ||
const address = splitSymbol.length === 1 ? undefined : splitSymbol[splitSymbol.length - 1]; | ||
const address = | ||
splitSymbol.length === 1 ? undefined : splitSymbol[splitSymbol.length - 1]?.toLowerCase(); | ||
@@ -111,2 +119,21 @@ return address?.startsWith("0x") | ||
export const getGasAsset = ({ chain }: { chain: Chain }) => { | ||
switch (chain) { | ||
case Chain.Arbitrum: | ||
case Chain.Optimism: | ||
return AssetValue.from({ asset: `${chain}.ETH` }); | ||
case Chain.Maya: | ||
return AssetValue.from({ asset: `${chain}.CACAO` }); | ||
case Chain.Cosmos: | ||
return AssetValue.from({ asset: `${chain}.ATOM` }); | ||
case Chain.BinanceSmartChain: | ||
return AssetValue.from({ asset: `${chain}.BNB` }); | ||
case Chain.THORChain: | ||
return AssetValue.from({ asset: `${chain}.RUNE` }); | ||
default: | ||
return AssetValue.from({ asset: `${chain}.${chain}` }); | ||
} | ||
}; | ||
export const isGasAsset = ({ chain, symbol }: { chain: Chain; symbol: string }) => { | ||
@@ -121,4 +148,2 @@ switch (chain) { | ||
return symbol === "ATOM"; | ||
case Chain.Polygon: | ||
return symbol === "MATIC"; | ||
case Chain.BinanceSmartChain: | ||
@@ -138,2 +163,6 @@ return symbol === "BNB"; | ||
switch (assetString) { | ||
case Chain.Arbitrum: | ||
case Chain.Optimism: | ||
return { identifier: `${assetString}.ETH`, decimal: BaseDecimal[assetString] }; | ||
case `${Chain.Ethereum}.THOR`: | ||
@@ -143,20 +172,17 @@ return { identifier: "ETH.THOR-0xa5f2211b9b8170f694421f2046281775e8468044", decimal: 18 }; | ||
return { identifier: "ETH.vTHOR-0x815c23eca83261b6ec689b60cc4a58b54bc24d8d", decimal: 18 }; | ||
case Chain.Arbitrum: | ||
return { identifier: `${Chain.Arbitrum}.ETH`, decimal: BaseDecimal[assetString] }; | ||
case Chain.Optimism: | ||
return { identifier: `${Chain.Optimism}.ETH`, decimal: BaseDecimal[assetString] }; | ||
case Chain.Cosmos: | ||
return { identifier: "GAIA.ATOM", decimal: BaseDecimal[assetString] }; | ||
return { identifier: `${assetString}.ATOM`, decimal: BaseDecimal[assetString] }; | ||
case Chain.THORChain: | ||
return { identifier: "THOR.RUNE", decimal: BaseDecimal[assetString] }; | ||
return { identifier: `${assetString}.RUNE`, decimal: BaseDecimal[assetString] }; | ||
case Chain.BinanceSmartChain: | ||
return { identifier: "BSC.BNB", decimal: BaseDecimal[assetString] }; | ||
return { identifier: `${assetString}.BNB`, decimal: BaseDecimal[assetString] }; | ||
case Chain.Maya: | ||
return { identifier: "MAYA.CACAO", decimal: BaseDecimal.MAYA }; | ||
return { identifier: `${assetString}.CACAO`, decimal: 10 }; | ||
case Chain.Radix: | ||
return { identifier: `${Chain.Radix}.XRD`, decimal: BaseDecimal[assetString] }; | ||
case `${Chain.Maya}.MAYA`: | ||
return { identifier: "MAYA.MAYA", decimal: 4 }; | ||
return { identifier: assetString, decimal: 4 }; | ||
case `${Chain.Kujira}.USK`: | ||
return { identifier: `${Chain.Kujira}.USK`, decimal: 6 }; | ||
case Chain.Radix: | ||
return { identifier: `${Chain.Radix}.XRD`, decimal: BaseDecimal.XRD }; | ||
return { identifier: assetString, decimal: 6 }; | ||
@@ -177,6 +203,4 @@ default: | ||
return symbol === Chain.Kujira ? "Native" : Chain.Kujira; | ||
case Chain.Binance: | ||
return symbol === Chain.Binance ? "Native" : "BEP2"; | ||
case Chain.BinanceSmartChain: | ||
return symbol === Chain.Binance ? "Native" : "BEP20"; | ||
return symbol === "BNB" ? "Native" : "BEP20"; | ||
case Chain.Ethereum: | ||
@@ -183,0 +207,0 @@ return symbol === Chain.Ethereum ? "Native" : "ERC20"; |
@@ -16,24 +16,34 @@ import { | ||
const updatedLastIndex = (path: DerivationPathArray, index: number) => [ | ||
...path.slice(0, path.length - 1), | ||
index, | ||
]; | ||
const updatedLastIndex = (path: DerivationPathArray, index: number) => { | ||
const newPath = [...path.slice(0, path.length - 1), index]; | ||
return newPath as DerivationPathArray; | ||
}; | ||
export function derivationPathToString([network, chainId, account, change, index]: | ||
| [number, number, number, number, number | undefined] | ||
| DerivationPathArray) { | ||
const shortPath = typeof index !== "number"; | ||
return `m/${network}'/${chainId}'/${account}'/${change}${shortPath ? "" : `/${index}`}`; | ||
} | ||
export function getDerivationPathFor({ chain, index, addressIndex = 0, type }: Params) { | ||
if (EVMChains.includes(chain as EVMChain)) { | ||
if (type === "legacy") return [44, 60, 0, index]; | ||
if (type === "ledgerLive") return [44, 60, index, 0, addressIndex]; | ||
if (type === "legacy") return [44, 60, 0, index] as DerivationPathArray; | ||
if (type === "ledgerLive") return [44, 60, index, 0, addressIndex] as DerivationPathArray; | ||
return updatedLastIndex(NetworkDerivationPath[chain], index); | ||
} | ||
if ([Chain.Bitcoin, Chain.Litecoin].includes(chain)) { | ||
const chainId = chain === Chain.Bitcoin ? 0 : 2; | ||
const chainId = chain === Chain.Litecoin ? 2 : 0; | ||
if (type === "nativeSegwitMiddleAccount") return [84, chainId, index, 0, addressIndex]; | ||
if (type === "segwit") return [49, chainId, 0, 0, index]; | ||
if (type === "legacy") return [44, chainId, 0, 0, index]; | ||
return updatedLastIndex(NetworkDerivationPath[chain], index); | ||
switch (type) { | ||
case "nativeSegwitMiddleAccount": | ||
return [84, chainId, index, 0, addressIndex] as DerivationPathArray; | ||
case "segwit": | ||
return [49, chainId, 0, 0, index] as DerivationPathArray; | ||
case "legacy": | ||
return [44, chainId, 0, 0, index] as DerivationPathArray; | ||
default: | ||
return updatedLastIndex(NetworkDerivationPath[chain], index); | ||
} | ||
return updatedLastIndex(NetworkDerivationPath[chain], index); | ||
} | ||
@@ -40,0 +50,0 @@ |
@@ -0,5 +1,64 @@ | ||
import { SwapKitError } from "../modules/swapKitError"; | ||
import { Chain } from "../types/chains"; | ||
import { MemoType } from "../types/sdk"; | ||
export type ThornameRegisterParam = { | ||
type WithChain<T extends {}> = T & { chain: Chain }; | ||
type WithAffiliate<T extends {}> = T & { | ||
affiliateAddress?: string; | ||
affiliateBasisPoints?: number; | ||
}; | ||
function addAffiliate(memo: string, { affiliateAddress, affiliateBasisPoints }: WithAffiliate<{}>) { | ||
const affiliatePart = affiliateAddress ? `:${affiliateAddress}:${affiliateBasisPoints || 0}` : ""; | ||
return `${memo}${affiliatePart}`; | ||
} | ||
function getPoolIdentifier({ | ||
chain, | ||
symbol, | ||
}: { | ||
chain: Chain; | ||
symbol: string; | ||
}) { | ||
switch (chain) { | ||
case Chain.Bitcoin: | ||
case Chain.Dogecoin: | ||
case Chain.Litecoin: | ||
return chain.slice(0, 1).toLowerCase(); | ||
case Chain.BitcoinCash: | ||
return "c"; | ||
default: | ||
return `${chain}.${symbol}`; | ||
} | ||
} | ||
export function getMemoForLeaveAndBond({ | ||
type, | ||
address, | ||
}: { | ||
type: MemoType.BOND | MemoType.LEAVE; | ||
address: string; | ||
}) { | ||
return `${type}:${address}`; | ||
} | ||
export function getMemoForUnbond({ | ||
address, | ||
unbondAmount, | ||
}: { | ||
address: string; | ||
unbondAmount: number; | ||
}) { | ||
return `${MemoType.UNBOND}:${address}:${unbondAmount}`; | ||
} | ||
export function getMemoForNameRegister({ | ||
name, | ||
chain, | ||
address, | ||
owner, | ||
}: { | ||
name: string; | ||
@@ -9,8 +68,102 @@ chain: string; | ||
owner?: string; | ||
preferredAsset?: string; | ||
expiryBlock?: string; | ||
}; | ||
}) { | ||
const baseMemo = `${MemoType.NAME_REGISTER}:${name}:${chain}:${address}`; | ||
const ownerAssignmentOrChangePart = owner ? `:${owner}` : ""; | ||
type WithChain<T extends {}> = T & { chain: Chain }; | ||
return `${baseMemo}${ownerAssignmentOrChangePart}`; | ||
} | ||
export function getMemoForNamePreferredAssetRegister({ | ||
name, | ||
chain, | ||
asset, | ||
payout, | ||
owner, | ||
}: { | ||
name: string; | ||
chain: Chain; | ||
asset: string; | ||
payout: string; | ||
owner: string; | ||
}) { | ||
const memo = [name, chain, payout, owner, asset].join(":"); | ||
return `${MemoType.NAME_REGISTER}:${memo}`; | ||
} | ||
export function getMemoForLoan( | ||
memoType: MemoType.OPEN_LOAN | MemoType.CLOSE_LOAN, | ||
{ | ||
asset, | ||
address, | ||
minAmount, | ||
...affiliate | ||
}: WithAffiliate<{ | ||
address: string; | ||
asset: string; | ||
minAmount?: string; | ||
}>, | ||
) { | ||
const baseMemo = `${memoType}:${asset}:${address}`; | ||
const minAmountPart = minAmount ? `:${minAmount}` : ""; | ||
return addAffiliate(`${baseMemo}${minAmountPart}`, affiliate); | ||
} | ||
export function getMemoForSaverDeposit({ | ||
chain, | ||
symbol, | ||
...affiliate | ||
}: WithAffiliate<{ chain: Chain; symbol: string }>) { | ||
return addAffiliate(`${MemoType.DEPOSIT}:${chain}/${symbol}`, affiliate); | ||
} | ||
export function getMemoForDeposit({ | ||
chain, | ||
symbol, | ||
address, | ||
...affiliate | ||
}: WithAffiliate<{ | ||
chain: Chain; | ||
symbol: string; | ||
address?: string; | ||
}>) { | ||
const poolIdentifier = getPoolIdentifier({ chain, symbol }); | ||
const hasAffiliateInfo = !!affiliate.affiliateAddress; | ||
const addressPart = address ? `:${address}` : hasAffiliateInfo ? ":" : ""; | ||
return addAffiliate(`${MemoType.DEPOSIT}:${poolIdentifier}${addressPart}`, affiliate); | ||
} | ||
export function getMemoForSaverWithdraw({ | ||
chain, | ||
symbol, | ||
basisPoints, | ||
}: { chain: Chain; symbol: string; basisPoints: number }) { | ||
return `${MemoType.WITHDRAW}:${chain}/${symbol}:${basisPoints}`; | ||
} | ||
export function getMemoForWithdraw({ | ||
chain, | ||
symbol, | ||
ticker, | ||
basisPoints, | ||
targetAsset, | ||
}: { | ||
chain: Chain; | ||
symbol: string; | ||
ticker: string; | ||
basisPoints: number; | ||
targetAsset?: string; | ||
}) { | ||
const shortenedSymbol = | ||
chain === "ETH" && ticker !== "ETH" ? `${ticker}-${symbol.slice(-3)}` : symbol; | ||
const targetPart = targetAsset ? `:${targetAsset}` : ""; | ||
return `${MemoType.WITHDRAW}:${chain}.${shortenedSymbol}:${basisPoints}${targetPart}`; | ||
} | ||
/** | ||
* @deprecated - Use separate functions per each memo type like getMemoForDeposit, getMemoForWithdraw, etc. | ||
*/ | ||
export type MemoOptions<T extends MemoType> = { | ||
@@ -22,3 +175,7 @@ [MemoType.BOND]: { address: string }; | ||
[MemoType.UNBOND]: { address: string; unbondAmount: number }; | ||
[MemoType.DEPOSIT]: WithChain<{ symbol: string; address?: string; singleSide?: boolean }>; | ||
[MemoType.DEPOSIT]: WithChain<{ | ||
symbol: string; | ||
address?: string; | ||
singleSide?: boolean; | ||
}>; | ||
[MemoType.WITHDRAW]: WithChain<{ | ||
@@ -31,5 +188,8 @@ ticker: string; | ||
}>; | ||
[MemoType.THORNAME_REGISTER]: Omit<ThornameRegisterParam, "preferredAsset" | "expiryBlock">; | ||
[MemoType.NAME_REGISTER]: { name: string; chain: string; address: string }; | ||
}[T]; | ||
/** | ||
* @deprecated - Use separate functions per each memo type like getMemoForDeposit, getMemoForWithdraw, etc. | ||
*/ | ||
export const getMemoFor = <T extends MemoType>(memoType: T, options: MemoOptions<T>) => { | ||
@@ -40,3 +200,3 @@ switch (memoType) { | ||
const { address } = options as MemoOptions<MemoType.BOND>; | ||
return `${memoType}:${address}`; | ||
return getMemoForLeaveAndBond({ type: memoType, address }); | ||
} | ||
@@ -46,53 +206,53 @@ | ||
const { address, unbondAmount } = options as MemoOptions<MemoType.UNBOND>; | ||
return `${memoType}:${address}:${unbondAmount}`; | ||
return getMemoForUnbond({ address, unbondAmount }); | ||
} | ||
case MemoType.THORNAME_REGISTER: { | ||
const { name, chain, address, owner } = options as MemoOptions<MemoType.THORNAME_REGISTER>; | ||
return `${memoType}:${name}:${chain}:${address}${owner ? `:${owner}` : ""}`; | ||
case MemoType.NAME_REGISTER: { | ||
return getMemoForNameRegister(options as MemoOptions<MemoType.NAME_REGISTER>); | ||
} | ||
case MemoType.OPEN_LOAN: | ||
case MemoType.CLOSE_LOAN: { | ||
return getMemoForLoan(memoType, options as MemoOptions<MemoType.OPEN_LOAN>); | ||
} | ||
case MemoType.DEPOSIT: { | ||
const { chain, symbol, address, singleSide } = options as MemoOptions<MemoType.DEPOSIT>; | ||
const getPoolIdentifier = (chain: Chain, symbol: string): string => { | ||
switch (chain) { | ||
case Chain.Litecoin: | ||
return "l"; | ||
case Chain.Dogecoin: | ||
return "d"; | ||
case Chain.BitcoinCash: | ||
return "c"; | ||
default: | ||
return `${chain}.${symbol}`; | ||
} | ||
}; | ||
if (singleSide) { | ||
return getMemoForSaverDeposit({ chain, symbol }); | ||
} | ||
return singleSide | ||
? `${memoType}:${chain}/${symbol}` | ||
: `${memoType}:${getPoolIdentifier(chain, symbol)}:${address || ""}`; | ||
return getMemoForDeposit({ chain, symbol, address }); | ||
} | ||
case MemoType.WITHDRAW: { | ||
const { chain, ticker, symbol, basisPoints, targetAssetString, singleSide } = | ||
options as MemoOptions<MemoType.WITHDRAW>; | ||
const { | ||
chain, | ||
ticker, | ||
symbol, | ||
basisPoints, | ||
targetAssetString: targetAsset, | ||
singleSide, | ||
} = options as MemoOptions<MemoType.WITHDRAW>; | ||
const shortenedSymbol = | ||
chain === "ETH" && ticker !== "ETH" ? `${ticker}-${symbol.slice(-3)}` : symbol; | ||
const target = !singleSide && targetAssetString ? `:${targetAssetString}` : ""; | ||
const assetDivider = singleSide ? "/" : "."; | ||
if (singleSide) { | ||
return getMemoForSaverWithdraw({ chain, symbol, basisPoints }); | ||
} | ||
return `${memoType}:${chain}${assetDivider}${shortenedSymbol}:${basisPoints}${target}`; | ||
return getMemoForWithdraw({ | ||
chain, | ||
ticker, | ||
symbol, | ||
basisPoints, | ||
targetAsset, | ||
}); | ||
} | ||
case MemoType.OPEN_LOAN: | ||
case MemoType.CLOSE_LOAN: { | ||
const { asset, address } = options as MemoOptions<MemoType.OPEN_LOAN>; | ||
return `${memoType}:${asset}:${address}`; //:${minAmount ? `${minAmount}` : ''}:t:0`; | ||
} | ||
default: | ||
return ""; | ||
throw new SwapKitError({ | ||
errorKey: "helpers_invalid_memo_type", | ||
info: { memoType }, | ||
}); | ||
} | ||
}; |
import { type ErrorKeys, SwapKitError } from "../modules/swapKitError"; | ||
import type { DerivationPathArray } from "../types/derivationPath"; | ||
import { Chain } from "../types"; | ||
@@ -7,3 +7,7 @@ // 10 rune for register, 1 rune per year | ||
export function getTHORNameCost(numberOfYears: number) { | ||
if (numberOfYears < 0) throw new Error("Invalid number of years"); | ||
if (numberOfYears < 0) | ||
throw new SwapKitError({ | ||
errorKey: "helpers_invalid_number_of_years", | ||
info: { numberOfYears }, | ||
}); | ||
return 10 + numberOfYears; | ||
@@ -15,3 +19,7 @@ } | ||
export function getMAYANameCost(numberOfYears: number) { | ||
if (numberOfYears < 0) throw new Error("Invalid number of year"); | ||
if (numberOfYears < 0) | ||
throw new SwapKitError({ | ||
errorKey: "helpers_invalid_number_of_years", | ||
info: { numberOfYears }, | ||
}); | ||
// round to max 10 decimals | ||
@@ -21,10 +29,2 @@ return Math.round((10 + numberOfYears * 1.0512) * 1e10) / 1e10; | ||
export function derivationPathToString([network, chainId, account, change, index]: | ||
| [number, number, number, number, number | undefined] | ||
| DerivationPathArray) { | ||
const shortPath = typeof index !== "number"; | ||
return `m/${network}'/${chainId}'/${account}'/${change}${shortPath ? "" : `/${index}`}`; | ||
} | ||
export function wrapWithThrow<T>(fn: () => T, errorKey?: ErrorKeys) { | ||
@@ -41,1 +41,30 @@ try { | ||
} | ||
export function getChainIdentifier<T extends Chain>(chain: T) { | ||
switch (chain) { | ||
case Chain.THORChain: | ||
return `${chain}.RUNE`; | ||
case Chain.Cosmos: | ||
return `${chain}.ATOM`; | ||
case Chain.BinanceSmartChain: | ||
return `${chain}`; | ||
default: | ||
return `${chain}.${chain}`; | ||
} | ||
} | ||
const skipWarnings = ["production", "test"].includes(process.env.NODE_ENV || ""); | ||
const warnings = new Set(); | ||
export function warnOnce(condition: boolean, warning: string) { | ||
if (!skipWarnings && condition) { | ||
if (warnings.has(warning)) { | ||
return; | ||
} | ||
warnings.add(warning); | ||
console.warn(warning); | ||
} | ||
} |
@@ -0,1 +1,2 @@ | ||
import { SwapKitError } from "../modules/swapKitError"; | ||
import { Chain } from "../types/chains"; | ||
@@ -15,5 +16,9 @@ | ||
throw new Error( | ||
`Invalid identifier: ${identifier}. Expected format: <Chain>.<Ticker> or <Chain>.<Ticker>-<ContractAddress>`, | ||
); | ||
throw new SwapKitError({ | ||
errorKey: "helpers_invalid_identifier", | ||
info: { | ||
message: `Invalid identifier: ${identifier}. Expected format: <Chain>.<Ticker> or <Chain>.<Ticker>-<ContractAddress>`, | ||
identifier, | ||
}, | ||
}); | ||
} | ||
@@ -20,0 +25,0 @@ |
import type { BrowserProvider } from "ethers"; | ||
import { SwapKitError } from "../modules/swapKitError"; | ||
import { | ||
@@ -16,2 +17,3 @@ ChainId, | ||
isTrust?: boolean; | ||
isTalisman?: boolean; | ||
on: (event: string, callback?: () => void) => void; | ||
@@ -30,11 +32,2 @@ overrideIsMetaMask?: boolean; | ||
// declare global { | ||
// interface Window { | ||
// ethereum: EthereumWindowProvider; | ||
// trustwallet: EthereumWindowProvider; | ||
// coinbaseWalletExtension: EthereumWindowProvider; | ||
// braveSolana: Todo; | ||
// } | ||
// } | ||
type NetworkParams = { | ||
@@ -89,3 +82,6 @@ chainId: ChainId; | ||
} catch (error) { | ||
throw new Error(`Failed to switch network: ${error}`); | ||
throw new SwapKitError({ | ||
errorKey: "helpers_failed_to_switch_network", | ||
info: { error }, | ||
}); | ||
} | ||
@@ -96,3 +92,5 @@ return func(...args); | ||
const providerRequest = ({ provider, params, method }: ProviderRequestParams) => { | ||
if (!provider?.send) throw new Error("Provider not found"); | ||
if (!provider?.send) { | ||
throw new SwapKitError("helpers_not_found_provider"); | ||
} | ||
@@ -99,0 +97,0 @@ const providerParams = params ? (Array.isArray(params) ? params : [params]) : []; |
@@ -45,12 +45,13 @@ import { describe, expect, test } from "bun:test"; | ||
const radixXWBTC = new AssetValue({ | ||
identifier: | ||
"RADIX.XWBTC-resource_rdx1t580qxc7upat7lww4l2c4jckacafjeudxj5wpjrrct0p3e82sq4y75", | ||
decimal: 8, | ||
value: 11112222, | ||
}); | ||
// TODO: | ||
// const radixXWBTC = new AssetValue({ | ||
// identifier: | ||
// "RADIX.XWBTC-resource_rdx1t580qxc7upat7lww4l2c4jckacafjeudxj5wpjrrct0p3e82sq4y75", | ||
// decimal: 8, | ||
// value: 11112222, | ||
// }); | ||
expect(radixXWBTC.toString()).toBe( | ||
"RADIX.XWBTC-resource_rdx1t580qxc7upat7lww4l2c4jckacafjeudxj5wpjrrct0p3e82sq4y75", | ||
); | ||
// expect(radixXWBTC.toString()).toBe( | ||
// "RADIX.XWBTC-resource_rdx1t580qxc7upat7lww4l2c4jckacafjeudxj5wpjrrct0p3e82sq4y75", | ||
// ) | ||
}); | ||
@@ -71,3 +72,3 @@ }); | ||
const thor = AssetValue.fromChainOrSignature("ETH.THOR"); | ||
const thor = AssetValue.from({ asset: "ETH.THOR" }); | ||
expect(thor.toUrl()).toBe("ETH.THOR-0xa5f2211b9b8170f694421f2046281775e8468044"); | ||
@@ -95,5 +96,5 @@ | ||
test("checks if assets are same chain and symbol", () => { | ||
const firstThor = AssetValue.fromChainOrSignature("ETH.THOR"); | ||
const secondThor = AssetValue.fromChainOrSignature("ETH.THOR"); | ||
const vThor = AssetValue.fromChainOrSignature("ETH.vTHOR"); | ||
const firstThor = AssetValue.from({ asset: "ETH.THOR" }); | ||
const secondThor = AssetValue.from({ asset: "ETH.THOR" }); | ||
const vThor = AssetValue.from({ asset: "ETH.vTHOR" }); | ||
const firstUsdc = new AssetValue({ | ||
@@ -112,13 +113,37 @@ chain: Chain.Avalanche, | ||
expect(firstThor.eqAsset(firstThor)).toBe(true); | ||
expect(firstThor.eqAsset(secondThor)).toBe(true); | ||
expect(firstThor.eqAsset(vThor)).toBe(false); | ||
expect(firstThor.eqAsset(firstUsdc)).toBe(false); | ||
expect(firstThor.eqAsset(secondUsdc)).toBe(false); | ||
expect(firstUsdc.eqAsset(firstThor)).toBe(false); | ||
expect(firstUsdc.eqAsset(secondThor)).toBe(false); | ||
expect(firstUsdc.eqAsset(vThor)).toBe(false); | ||
expect(firstUsdc.eqAsset(firstUsdc)).toBe(true); | ||
expect(firstUsdc.eqAsset(secondUsdc)).toBe(true); | ||
}); | ||
test("check if assets have same value, even if not same asset", () => { | ||
const firstThor = AssetValue.from({ asset: "ETH.THOR", value: "20" }); | ||
const secondThor = AssetValue.from({ asset: "ETH.THOR", value: "35" }); | ||
const thirdThor = AssetValue.from({ asset: "ETH.THOR", value: "35" }); | ||
const vThor = AssetValue.from({ asset: "ETH.vTHOR", value: "20" }); | ||
expect(firstThor.eqValue(firstThor)).toBe(true); | ||
expect(firstThor.eqValue(secondThor)).toBe(false); | ||
expect(secondThor.eqValue(thirdThor)).toBe(true); | ||
expect(firstThor.eqValue(vThor)).toBe(true); | ||
}); | ||
test("check if assets have identical asset and value", () => { | ||
const firstThor = AssetValue.from({ asset: "ETH.THOR", value: "20" }); | ||
const secondThor = AssetValue.from({ asset: "ETH.THOR", value: "35" }); | ||
const thirdThor = AssetValue.from({ asset: "ETH.THOR", value: "35" }); | ||
const vThor = AssetValue.from({ asset: "ETH.vTHOR", value: "20" }); | ||
expect(firstThor.eq(firstThor)).toBe(true); | ||
expect(firstThor.eq(secondThor)).toBe(true); | ||
expect(firstThor.eq(secondThor)).toBe(false); | ||
expect(secondThor.eq(thirdThor)).toBe(true); | ||
expect(firstThor.eq(vThor)).toBe(false); | ||
expect(firstThor.eq(firstUsdc)).toBe(false); | ||
expect(firstThor.eq(secondUsdc)).toBe(false); | ||
expect(firstUsdc.eq(firstThor)).toBe(false); | ||
expect(firstUsdc.eq(secondThor)).toBe(false); | ||
expect(firstUsdc.eq(vThor)).toBe(false); | ||
expect(firstUsdc.eq(firstUsdc)).toBe(true); | ||
expect(firstUsdc.eq(secondUsdc)).toBe(true); | ||
}); | ||
@@ -129,6 +154,7 @@ }); | ||
test("returns asset value with correct decimal", async () => { | ||
const avaxUSDCAsset = await AssetValue.fromIdentifier( | ||
`${Chain.Avalanche}.USDC-0xb97ef9ef8734c71904d8002f8b6bc66dd9c48a6e`, | ||
1234567800n, | ||
); | ||
const avaxUSDCAsset = await AssetValue.from({ | ||
asset: `${Chain.Avalanche}.USDC-0xb97ef9ef8734c71904d8002f8b6bc66dd9c48a6e`, | ||
value: 1234567800n, | ||
asyncTokenLookup: true, | ||
}); | ||
expect(avaxUSDCAsset.getValue("string")).toBe("1234.5678"); | ||
@@ -148,6 +174,6 @@ }); | ||
const thor = AssetValue.fromChainOrSignature("ETH.THOR"); | ||
const thor = AssetValue.from({ asset: "ETH.THOR" }); | ||
expect(thor.toString()).toBe("ETH.THOR-0xa5f2211b9b8170f694421f2046281775e8468044"); | ||
const ethSynth = await AssetValue.fromIdentifier("ETH/ETH"); | ||
const ethSynth = await AssetValue.from({ asset: "ETH/ETH", asyncTokenLookup: true }); | ||
expect(ethSynth.toString()).toBe("ETH/ETH"); | ||
@@ -159,5 +185,6 @@ }); | ||
test("creates AssetValue from string", async () => { | ||
const avaxUSDCAsset = await AssetValue.fromIdentifier( | ||
"AVAX.USDC-0xb97ef9ef8734c71904d8002f8b6bc66dd9c48a6e", | ||
); | ||
const avaxUSDCAsset = await AssetValue.from({ | ||
asset: "AVAX.USDC-0xb97ef9ef8734c71904d8002f8b6bc66dd9c48a6e", | ||
asyncTokenLookup: true, | ||
}); | ||
@@ -178,3 +205,6 @@ expect(avaxUSDCAsset).toEqual( | ||
test("creates AssetValue from string with multiple dashes", async () => { | ||
const ethPendleLptAsset = await AssetValue.fromIdentifier("ETH.PENDLE-LPT-0x1234"); | ||
const ethPendleLptAsset = await AssetValue.from({ | ||
asset: "ETH.PENDLE-LPT-0x1234", | ||
asyncTokenLookup: true, | ||
}); | ||
@@ -198,3 +228,6 @@ expect(ethPendleLptAsset).toEqual( | ||
const fakeAvaxAssetString = "AVAX.ASDF-1234"; | ||
const fakeAvaxAsset = await AssetValue.fromString(fakeAvaxAssetString); | ||
const fakeAvaxAsset = await AssetValue.from({ | ||
asset: fakeAvaxAssetString, | ||
asyncTokenLookup: true, | ||
}); | ||
@@ -216,3 +249,6 @@ expect(fakeAvaxAsset).toEqual( | ||
const fakeAvaxAssetString = "AVAX.ASDF-LP-1234"; | ||
const fakeAvaxAsset = await AssetValue.fromString(fakeAvaxAssetString); | ||
const fakeAvaxAsset = await AssetValue.from({ | ||
asset: fakeAvaxAssetString, | ||
asyncTokenLookup: true, | ||
}); | ||
@@ -232,6 +268,7 @@ expect(fakeAvaxAsset).toEqual( | ||
test("creates AssetValue with _ symbol", async () => { | ||
const radixXWBTC = await AssetValue.fromString( | ||
"XRD.XWBTC-resource_rdx1t580qxc7upat7lww4l2c4jckacafjeudxj5wpjrrct0p3e82sq4y75", | ||
); | ||
test.todo("creates AssetValue with _ symbol", async () => { | ||
const radixXWBTC = await AssetValue.from({ | ||
asset: "XRD.XWBTC-resource_rdx1t580qxc7upat7lww4l2c4jckacafjeudxj5wpjrrct0p3e82sq4y75", | ||
asyncTokenLookup: true, | ||
}); | ||
@@ -255,3 +292,8 @@ expect(radixXWBTC).toEqual( | ||
const fakeAvaxAssetString = "AVAX.ASDF-1234"; | ||
const fakeAvaxAsset = await AssetValue.fromStringWithBase(fakeAvaxAssetString, 1, 8); | ||
const fakeAvaxAsset = await AssetValue.from({ | ||
asset: fakeAvaxAssetString, | ||
value: 1, | ||
fromBaseDecimal: 8, | ||
asyncTokenLookup: true, | ||
}); | ||
@@ -269,4 +311,4 @@ expect(fakeAvaxAsset).toEqual( | ||
); | ||
expect(fakeAvaxAsset.getValue("string")).toBe("100000000"); | ||
expect(fakeAvaxAsset.getBaseValue("string")).toBe("100000000000000000000000000"); | ||
expect(fakeAvaxAsset.getValue("string")).toBe("0.00000001"); | ||
expect(fakeAvaxAsset.getBaseValue("string")).toBe("10000000000"); | ||
}); | ||
@@ -276,3 +318,3 @@ }); | ||
describe("fromUrl", () => { | ||
test("creates AssetValue from url like format", async () => { | ||
test("creates AssetValue from url like format", () => { | ||
const synthETHString = "THOR.ETH.ETH"; | ||
@@ -284,7 +326,7 @@ const ethString = "ETH.ETH"; | ||
const synthETH = await AssetValue.fromUrl(synthETHString); | ||
const eth = await AssetValue.fromUrl(ethString); | ||
const thor = await AssetValue.fromUrl(thorString); | ||
const synthThor = await AssetValue.fromUrl(synthThorString); | ||
const synthDashes = await AssetValue.fromUrl(synthDashesString); | ||
const synthETH = AssetValue.fromUrl(synthETHString); | ||
const eth = AssetValue.fromUrl(ethString); | ||
const thor = AssetValue.fromUrl(thorString); | ||
const synthThor = AssetValue.fromUrl(synthThorString); | ||
const synthDashes = AssetValue.fromUrl(synthDashesString); | ||
@@ -302,5 +344,5 @@ expect(synthETH.toString()).toBe("ETH/ETH"); | ||
await AssetValue.loadStaticAssets(); | ||
const thor = AssetValue.fromIdentifierSync( | ||
"ARB.USDT-0XFD086BC7CD5C481DCC9C85EBE478A1C0B69FCBB9", | ||
); | ||
const thor = AssetValue.from({ | ||
asset: "ARB.USDT-0XFD086BC7CD5C481DCC9C85EBE478A1C0B69FCBB9", | ||
}); | ||
@@ -325,3 +367,5 @@ expect(thor).toBeDefined(); | ||
await AssetValue.loadStaticAssets(); | ||
const thor = AssetValue.fromStringSync("ETH.THOR-0xa5f2211b9b8170f694421f2046281775e8468044"); | ||
const thor = AssetValue.from({ | ||
asset: "ETH.THOR-0xa5f2211b9b8170f694421f2046281775e8468044", | ||
}); | ||
@@ -341,3 +385,5 @@ expect(thor).toBeDefined(); | ||
const usdc = AssetValue.fromStringSync("ETH.USDC-0XA0B86991C6218B36C1D19D4A2E9EB0CE3606EB48"); | ||
const usdc = AssetValue.from({ | ||
asset: "ETH.USDC-0XA0B86991C6218B36C1D19D4A2E9EB0CE3606EB48", | ||
}); | ||
expect(usdc).toBeDefined(); | ||
@@ -360,3 +406,3 @@ expect(usdc).toEqual( | ||
const fakeAvaxUSDCAssetString = "AVAX.USDC-1234"; | ||
const fakeAvaxUSDCAsset = AssetValue.fromStringSync(fakeAvaxUSDCAssetString); | ||
const fakeAvaxUSDCAsset = AssetValue.from({ asset: fakeAvaxUSDCAssetString }); | ||
@@ -380,6 +426,6 @@ expect(fakeAvaxUSDCAsset).toBeDefined(); | ||
const fakeAvaxUSDCAssetString = "AVAX.USDC-LPT-1234"; | ||
const fakeAvaxUSDCAsset = AssetValue.fromStringSync(fakeAvaxUSDCAssetString); | ||
const fakeAvaxUSDCAsset2 = AssetValue.from({ asset: fakeAvaxUSDCAssetString }); | ||
expect(fakeAvaxUSDCAsset).toBeDefined(); | ||
expect(fakeAvaxUSDCAsset).toEqual( | ||
expect(fakeAvaxUSDCAsset2).toBeDefined(); | ||
expect(fakeAvaxUSDCAsset2).toEqual( | ||
expect.objectContaining({ | ||
@@ -400,3 +446,3 @@ address: "1234", | ||
const avaxBTCb = "AVAX.BTC.b-0x152b9d0fdc40c096757f570a51e494bd4b943e50"; | ||
const AvaxBTCb = AssetValue.fromStringSync(avaxBTCb); | ||
const AvaxBTCb = AssetValue.from({ asset: avaxBTCb }); | ||
@@ -411,4 +457,4 @@ expect(AvaxBTCb).toBeDefined(); | ||
isSynthetic: false, | ||
symbol: "BTC.b-0x152b9d0fdc40c096757f570a51e494bd4b943e50", | ||
ticker: "BTC.b", | ||
symbol: "BTC.B-0x152b9d0fdc40c096757f570a51e494bd4b943e50", | ||
ticker: "BTC.B", | ||
}), | ||
@@ -422,3 +468,7 @@ ); | ||
await AssetValue.loadStaticAssets(); | ||
const btc = AssetValue.fromStringWithBaseSync("BTC.BTC", 5200000000000, 8); | ||
const btc = AssetValue.from({ | ||
asset: "BTC.BTC", | ||
value: 5200000000000, | ||
fromBaseDecimal: 8, | ||
}); | ||
@@ -444,3 +494,7 @@ expect(btc).toBeDefined(); | ||
const fakeAvaxUSDCAssetString = "AVAX.USDC-1234"; | ||
const fakeAvaxUSDCAsset = AssetValue.fromStringWithBaseSync(fakeAvaxUSDCAssetString, 1, 8); | ||
const fakeAvaxUSDCAsset = AssetValue.from({ | ||
asset: fakeAvaxUSDCAssetString, | ||
value: 1, | ||
fromBaseDecimal: 8, | ||
}); | ||
@@ -467,3 +521,7 @@ expect(fakeAvaxUSDCAsset).toBeDefined(); | ||
const avaxUSDC = "AVAX.USDC-0xb97ef9ef8734c71904d8002f8b6bc66dd9c48a6e"; | ||
const AvaxUSDC = AssetValue.fromStringWithBaseSync(avaxUSDC, 100000000, 8); | ||
const AvaxUSDC = AssetValue.from({ | ||
asset: avaxUSDC, | ||
value: 100000000, | ||
fromBaseDecimal: 8, | ||
}); | ||
@@ -490,30 +548,3 @@ expect(AvaxUSDC).toBeDefined(); | ||
test("creates AssetValue from common asset string or chain", () => { | ||
const customBaseAsset = [ | ||
Chain.Cosmos, | ||
Chain.BinanceSmartChain, | ||
Chain.THORChain, | ||
Chain.Maya, | ||
Chain.Arbitrum, | ||
Chain.Optimism, | ||
Chain.Radix, | ||
]; | ||
const filteredChains = Object.values(Chain).filter((c) => !customBaseAsset.includes(c)); | ||
for (const chain of filteredChains) { | ||
const asset = AssetValue.fromChainOrSignature(chain); | ||
expect(asset).toEqual( | ||
expect.objectContaining({ | ||
address: undefined, | ||
chain, | ||
decimal: BaseDecimal[chain], | ||
isGasAsset: true, | ||
isSynthetic: false, | ||
symbol: chain, | ||
ticker: chain, | ||
type: "Native", | ||
}), | ||
); | ||
} | ||
const cosmosAsset = AssetValue.fromChainOrSignature(Chain.Cosmos); | ||
const cosmosAsset = AssetValue.from({ chain: Chain.Cosmos }); | ||
expect(cosmosAsset).toEqual( | ||
@@ -532,3 +563,3 @@ expect.objectContaining({ | ||
const bscAsset = AssetValue.fromChainOrSignature(Chain.BinanceSmartChain); | ||
const bscAsset = AssetValue.from({ chain: Chain.BinanceSmartChain }); | ||
expect(bscAsset).toEqual( | ||
@@ -547,3 +578,3 @@ expect.objectContaining({ | ||
const thorAsset = AssetValue.fromChainOrSignature(Chain.THORChain); | ||
const thorAsset = AssetValue.from({ chain: Chain.THORChain }); | ||
expect(thorAsset).toEqual( | ||
@@ -562,3 +593,3 @@ expect.objectContaining({ | ||
const cacaoAsset = AssetValue.fromChainOrSignature(Chain.Maya); | ||
const cacaoAsset = AssetValue.from({ chain: Chain.Maya }); | ||
expect(cacaoAsset).toEqual( | ||
@@ -568,3 +599,3 @@ expect.objectContaining({ | ||
chain: Chain.Maya, | ||
decimal: BaseDecimal.MAYA, | ||
decimal: 10, | ||
isGasAsset: true, | ||
@@ -578,29 +609,30 @@ isSynthetic: false, | ||
const thor = AssetValue.fromChainOrSignature("ETH.THOR"); | ||
expect(thor).toEqual( | ||
expect.objectContaining({ | ||
address: "0xa5f2211b9b8170f694421f2046281775e8468044", | ||
chain: Chain.Ethereum, | ||
decimal: 18, | ||
isGasAsset: false, | ||
isSynthetic: false, | ||
symbol: "THOR-0xa5f2211b9b8170f694421f2046281775e8468044", | ||
ticker: "THOR", | ||
}), | ||
); | ||
// TODO enable when BE fixes case sensitivity | ||
// const thor = AssetValue.from({ asset: "ETH.THOR" }); | ||
// expect(thor).toEqual( | ||
// expect.objectContaining({ | ||
// address: "0xa5f2211b9b8170f694421f2046281775e8468044", | ||
// chain: Chain.Ethereum, | ||
// decimal: 18, | ||
// isGasAsset: false, | ||
// isSynthetic: false, | ||
// symbol: "THOR-0xa5f2211b9b8170f694421f2046281775e8468044", | ||
// ticker: "THOR", | ||
// }), | ||
// ); | ||
const vthor = AssetValue.fromChainOrSignature("ETH.vTHOR"); | ||
expect(vthor).toEqual( | ||
expect.objectContaining({ | ||
address: "0x815c23eca83261b6ec689b60cc4a58b54bc24d8d", | ||
chain: Chain.Ethereum, | ||
decimal: 18, | ||
isGasAsset: false, | ||
isSynthetic: false, | ||
symbol: "vTHOR-0x815c23eca83261b6ec689b60cc4a58b54bc24d8d", | ||
ticker: "vTHOR", | ||
}), | ||
); | ||
// const vthor = AssetValue.from({ asset: "ETH.vTHOR" }); | ||
// expect(vthor).toEqual( | ||
// expect.objectContaining({ | ||
// address: "0x815c23eca83261b6ec689b60cc4a58b54bc24d8d", | ||
// chain: Chain.Ethereum, | ||
// decimal: 18, | ||
// isGasAsset: false, | ||
// isSynthetic: false, | ||
// symbol: "vTHOR-0x815c23eca83261b6ec689b60cc4a58b54bc24d8d", | ||
// ticker: "vTHOR", | ||
// }), | ||
// ); | ||
const arbAsset = AssetValue.fromChainOrSignature(Chain.Arbitrum); | ||
const arbAsset = AssetValue.from({ chain: Chain.Arbitrum }); | ||
expect(arbAsset).toEqual( | ||
@@ -619,3 +651,3 @@ expect.objectContaining({ | ||
const opAsset = AssetValue.fromChainOrSignature(Chain.Optimism); | ||
const opAsset = AssetValue.from({ chain: Chain.Optimism }); | ||
expect(opAsset).toEqual( | ||
@@ -634,3 +666,3 @@ expect.objectContaining({ | ||
const xrdAsset = AssetValue.fromChainOrSignature(Chain.Radix); | ||
const xrdAsset = AssetValue.from({ chain: Chain.Radix }); | ||
expect(xrdAsset).toEqual( | ||
@@ -650,10 +682,2 @@ expect.objectContaining({ | ||
}); | ||
describe("loadStaticAssets", () => { | ||
test("loads static assets from `@swapkit/tokens` lists", async () => { | ||
// Dummy test - think of sth more meaningful | ||
const { ok } = await AssetValue.loadStaticAssets(); | ||
expect(ok).toBe(true); | ||
}); | ||
}); | ||
}); | ||
@@ -660,0 +684,0 @@ |
@@ -1,3 +0,11 @@ | ||
import type { CommonAssetString } from "../helpers/asset.ts"; | ||
import { getAssetType, getCommonAssetInfo, getDecimal, isGasAsset } from "../helpers/asset.ts"; | ||
import { red, yellow } from "picocolors"; | ||
import { | ||
type CommonAssetString, | ||
CommonAssetStrings, | ||
getAssetType, | ||
getCommonAssetInfo, | ||
getDecimal, | ||
isGasAsset, | ||
} from "../helpers/asset.ts"; | ||
import { warnOnce } from "../helpers/others.ts"; | ||
import { validateIdentifier } from "../helpers/validators.ts"; | ||
@@ -9,3 +17,4 @@ import { BaseDecimal, Chain, type ChainId, ChainToChainId } from "../types/chains.ts"; | ||
import { BigIntArithmetics, formatBigIntToSafeValue } from "./bigIntArithmetics.ts"; | ||
import { SwapKitNumber, type SwapKitValueType } from "./swapKitNumber.ts"; | ||
import { SwapKitError } from "./swapKitError.ts"; | ||
import type { SwapKitValueType } from "./swapKitNumber.ts"; | ||
@@ -17,2 +26,17 @@ const staticTokensMap = new Map< | ||
type ConditionalAssetValueReturn<T extends { asyncTokenLookup?: boolean }> = | ||
T["asyncTokenLookup"] extends true ? Promise<AssetValue> : AssetValue; | ||
type AssetIdentifier = | ||
| { asset: CommonAssetString } | ||
| { asset: TokenNames } | ||
| { asset: string } | ||
| { chain: Chain }; | ||
type AssetValueFromParams = AssetIdentifier & { | ||
value?: NumberPrimitives | SwapKitValueType; | ||
fromBaseDecimal?: number; | ||
asyncTokenLookup?: boolean; | ||
}; | ||
export class AssetValue extends BigIntArithmetics { | ||
@@ -63,6 +87,10 @@ address?: string; | ||
eq({ chain, symbol }: { chain: Chain; symbol: string }) { | ||
eqAsset({ chain, symbol }: { chain: Chain; symbol: string }) { | ||
return this.chain === chain && this.symbol === symbol; | ||
} | ||
eq(assetValue: AssetValue) { | ||
return this.eqAsset(assetValue) && this.eqValue(assetValue); | ||
} | ||
// THOR.RUNE | ||
@@ -73,111 +101,64 @@ // THOR.ETH.ETH | ||
const [chain, ticker, symbol] = urlAsset.split("."); | ||
if (!(chain && ticker)) throw new Error("Invalid asset url"); | ||
if (!(chain && ticker)) { | ||
throw new SwapKitError({ | ||
errorKey: "helpers_invalid_asset_url", | ||
info: { urlAsset }, | ||
}); | ||
} | ||
const assetString = | ||
chain === Chain.THORChain && symbol ? `${chain}.${ticker}/${symbol}` : urlAsset; | ||
const asset = chain === Chain.THORChain && symbol ? `${chain}.${ticker}/${symbol}` : urlAsset; | ||
return createAssetValue(assetString, value); | ||
return AssetValue.from({ asset, value }); | ||
} | ||
static fromString(assetString: string, value: NumberPrimitives = 0) { | ||
return createAssetValue(assetString, value); | ||
} | ||
static fromIdentifier( | ||
assetString: | ||
| `${Chain}.${string}` | ||
| `${Chain}/${string}` | ||
| `${Chain}.${string}-${string}` | ||
| TokenNames, | ||
value: NumberPrimitives = 0, | ||
) { | ||
return createAssetValue(assetString, value); | ||
} | ||
static from<T extends {}>({ | ||
value = 0, | ||
fromBaseDecimal, | ||
asyncTokenLookup, | ||
...fromAssetOrChain | ||
}: T & AssetValueFromParams): ConditionalAssetValueReturn<T> { | ||
const parsedValue = value instanceof BigIntArithmetics ? value.getValue("string") : value; | ||
const isFromChain = "chain" in fromAssetOrChain; | ||
const assetOrChain = isFromChain ? fromAssetOrChain.chain : fromAssetOrChain.asset; | ||
static fromStringSync(assetString: string, value: NumberPrimitives = 0) { | ||
const { chain, isSynthetic } = getAssetInfo(assetString); | ||
const tokenInfo = staticTokensMap.get(assetString.toUpperCase() as TokenNames); | ||
const isFromCommonAssetOrChain = | ||
isFromChain || | ||
CommonAssetStrings.includes(assetOrChain as (typeof CommonAssetStrings)[number]); | ||
if (isSynthetic) return createSyntheticAssetValue(assetString, value); | ||
// TODO: write logger that will only run in dev mode with some flag | ||
// if (!tokenInfo) { | ||
// console.error( | ||
// `Asset ${assetString} is not loaded. Use AssetValue.loadStaticAssets() to load it`, | ||
// ); | ||
// } | ||
const { identifier: unsafeIdentifier, decimal: commonAssetDecimal } = isFromCommonAssetOrChain | ||
? getCommonAssetInfo(assetOrChain as CommonAssetString) | ||
: { identifier: assetOrChain, decimal: undefined }; | ||
const { tax, decimal, identifier } = tokenInfo || { | ||
decimal: BaseDecimal[chain], | ||
identifier: assetString, | ||
}; | ||
const { chain, isSynthetic } = getAssetInfo(unsafeIdentifier); | ||
const token = staticTokensMap.get(unsafeIdentifier.toUpperCase() as TokenNames); | ||
const tokenDecimal = token?.decimal || commonAssetDecimal; | ||
return new AssetValue({ | ||
tax, | ||
value: safeValue(value, decimal), | ||
identifier: isSynthetic ? assetString : identifier, | ||
decimal: isSynthetic ? 8 : decimal, | ||
}); | ||
} | ||
warnOnce( | ||
!(asyncTokenLookup || tokenDecimal), | ||
yellow( | ||
`Couldn't find static decimal for ${red(unsafeIdentifier)} (Using default ${red(BaseDecimal[chain])} decimal as fallback). | ||
This can result in incorrect calculations and mess with amount sent on transactions. | ||
You can load static assets by installing @swapkit/tokens package and calling AssetValue.loadStaticAssets() | ||
or by passing asyncTokenLookup: true to the from() function, which will make it async and return a promise.`, | ||
), | ||
); | ||
static async fromStringWithBase( | ||
assetString: string, | ||
value: NumberPrimitives = 0, | ||
baseDecimal: number = BaseDecimal.THOR, | ||
) { | ||
const shiftedAmount = BigIntArithmetics.shiftDecimals({ | ||
value: SwapKitNumber.fromBigInt(BigInt(value)), | ||
from: 0, | ||
to: baseDecimal, | ||
}).getBaseValue("string"); | ||
const assetValue = await AssetValue.fromString(assetString, value); | ||
return assetValue.set(shiftedAmount); | ||
} | ||
static fromStringWithBaseSync( | ||
assetString: string, | ||
value: NumberPrimitives = 0, | ||
baseDecimal: number = BaseDecimal.THOR, | ||
) { | ||
const { chain, isSynthetic } = getAssetInfo(assetString); | ||
const tokenInfo = staticTokensMap.get(assetString.toUpperCase() as TokenNames); | ||
if (isSynthetic) return createSyntheticAssetValue(assetString, value); | ||
const { tax, decimal, identifier } = tokenInfo || { | ||
decimal: BaseDecimal[chain], | ||
identifier: assetString, | ||
const { decimal, identifier, tax } = token || { | ||
decimal: tokenDecimal || BaseDecimal[chain], | ||
identifier: unsafeIdentifier, | ||
}; | ||
return new AssetValue({ | ||
tax, | ||
value: safeValue(BigInt(value), baseDecimal), | ||
identifier, | ||
decimal, | ||
}); | ||
} | ||
const adjustedValue = fromBaseDecimal | ||
? safeValue(BigInt(parsedValue), fromBaseDecimal) | ||
: safeValue(parsedValue, decimal); | ||
static fromIdentifierSync(assetString: TokenNames, value: NumberPrimitives = 0) { | ||
const { chain, isSynthetic } = getAssetInfo(assetString); | ||
const tokenInfo = staticTokensMap.get(assetString); | ||
const assetValue = asyncTokenLookup | ||
? createAssetValue(identifier, fromBaseDecimal ? adjustedValue : parsedValue) | ||
: isSynthetic | ||
? createSyntheticAssetValue(identifier, adjustedValue) | ||
: new AssetValue({ tax, decimal, identifier, value: adjustedValue }); | ||
if (isSynthetic) return createSyntheticAssetValue(assetString, value); | ||
// TODO: write logger that will only run in dev mode with some flag | ||
// if (!tokenInfo) { | ||
// console.error( | ||
// `Asset ${assetString} is not loaded. - Loading with base Chain. Use AssetValue.loadStaticAssets() to load it`, | ||
// ); | ||
// } | ||
const { tax, decimal, identifier } = tokenInfo || { | ||
decimal: BaseDecimal[chain], | ||
identifier: assetString, | ||
}; | ||
return new AssetValue({ tax, decimal, identifier, value: safeValue(value, decimal) }); | ||
return assetValue as ConditionalAssetValueReturn<T>; | ||
} | ||
static fromChainOrSignature(assetString: CommonAssetString, value: NumberPrimitives = 0) { | ||
const { decimal, identifier } = getCommonAssetInfo(assetString); | ||
return new AssetValue({ value: safeValue(value, decimal), decimal, identifier }); | ||
} | ||
static loadStaticAssets() { | ||
@@ -211,6 +192,63 @@ return new Promise<{ ok: true } | { ok: false; message: string; error: Todo }>( | ||
} | ||
/** | ||
* @deprecated use AssetValue.from({ asset, value, asyncTokenLookup: true }) | ||
*/ | ||
static fromString(asset: string, value: NumberPrimitives = 0) { | ||
return AssetValue.from({ asset, value, asyncTokenLookup: true }); | ||
} | ||
/** | ||
* @deprecated use AssetValue.from({ asset, value, asyncTokenLookup: true }) | ||
*/ | ||
static fromIdentifier( | ||
asset: `${Chain}.${string}` | `${Chain}/${string}` | TokenNames, | ||
value: NumberPrimitives = 0, | ||
) { | ||
return AssetValue.from({ asset: asset as TokenNames, value, asyncTokenLookup: true }); | ||
} | ||
/** | ||
* @deprecated use AssetValue.from({ asset, value }) | ||
*/ | ||
static fromStringSync(asset: string, value: NumberPrimitives = 0) { | ||
return AssetValue.from({ asset, value }); | ||
} | ||
/** | ||
* @deprecated use AssetValue.from({ asset, value, fromBaseDecimal, asyncTokenLookup: true }) | ||
*/ | ||
static fromStringWithBase( | ||
asset: string, | ||
value: string | bigint = 0n, | ||
fromBaseDecimal: number = BaseDecimal.THOR, | ||
) { | ||
return AssetValue.from({ asyncTokenLookup: true, asset, value, fromBaseDecimal }); | ||
} | ||
/** | ||
* @deprecated use AssetValue.from({ asset, value, fromBaseDecimal, asyncTokenLookup: true }) | ||
*/ | ||
static fromStringWithBaseSync( | ||
asset: string, | ||
value: string | bigint = 0n, | ||
fromBaseDecimal: number = BaseDecimal.THOR, | ||
) { | ||
return AssetValue.from({ asset, value, fromBaseDecimal }); | ||
} | ||
/** | ||
* @deprecated use AssetValue.from({ asset, value }) | ||
*/ | ||
static fromIdentifierSync(asset: TokenNames, value: NumberPrimitives = 0) { | ||
return AssetValue.from({ asset, value }); | ||
} | ||
/** | ||
* @deprecated use AssetValue.from({ asset, value }) or AssetValue.from({ chain, value }) | ||
*/ | ||
static fromChainOrSignature(assetOrChain: CommonAssetString, value: NumberPrimitives = 0) { | ||
if (Object.values(Chain).includes(assetOrChain as Chain)) { | ||
return AssetValue.from({ chain: assetOrChain as Chain, value }); | ||
} | ||
return AssetValue.from({ asset: assetOrChain, value }); | ||
} | ||
} | ||
export function getMinAmountByChain(chain: Chain) { | ||
const asset = AssetValue.fromChainOrSignature(chain); | ||
const asset = AssetValue.from({ chain }); | ||
@@ -221,2 +259,3 @@ switch (chain) { | ||
case Chain.BitcoinCash: | ||
case Chain.Dash: | ||
return asset.set(0.00010001); | ||
@@ -229,2 +268,4 @@ | ||
case Chain.Ethereum: | ||
case Chain.Arbitrum: | ||
case Chain.BinanceSmartChain: | ||
return asset.set(0.00000001); | ||
@@ -237,2 +278,3 @@ | ||
case Chain.Cosmos: | ||
case Chain.Kujira: | ||
return asset.set(0.000001); | ||
@@ -263,3 +305,8 @@ | ||
if (!(synthChain && symbol)) throw new Error("Invalid asset identifier"); | ||
if (!(synthChain && symbol)) { | ||
throw new SwapKitError({ | ||
errorKey: "helpers_invalid_asset_identifier", | ||
info: { identifier }, | ||
}); | ||
} | ||
@@ -291,3 +338,8 @@ return new AssetValue({ | ||
if (isSynthetic && !(synthChain && synthSymbol)) throw new Error("Invalid asset identifier"); | ||
if (isSynthetic && !(synthChain && synthSymbol)) { | ||
throw new SwapKitError({ | ||
errorKey: "helpers_invalid_asset_identifier", | ||
info: { identifier }, | ||
}); | ||
} | ||
@@ -313,7 +365,7 @@ const adjustedIdentifier = | ||
isSynthetic, | ||
ticker, | ||
symbol: | ||
(isSynthetic ? `${synthChain}/` : "") + | ||
(address ? `${ticker}-${address?.toLowerCase() ?? ""}` : symbol), | ||
ticker, | ||
}; | ||
} |
@@ -45,5 +45,3 @@ import { BaseDecimal } from "../types/chains.ts"; | ||
// Increment the last decimal place and slice off the rest | ||
decimalString = `${decimalString.substring(0, bigIntDecimal - 1)}${( | ||
Number.parseInt(decimalString[bigIntDecimal - 1] || "0") + 1 | ||
).toString()}`; | ||
decimalString = `${decimalString.substring(0, bigIntDecimal - 1)}${(Number.parseInt(decimalString[bigIntDecimal - 1] || "0") + 1).toString()}`; | ||
} else { | ||
@@ -281,5 +279,3 @@ // Just slice off the extra digits | ||
// Increment the last decimal place and slice off the rest | ||
decimalString = `${decimalString.substring(0, bigIntDecimal - 1)}${( | ||
Number.parseInt(decimalString[bigIntDecimal - 1] || "0") + 1 | ||
).toString()}`; | ||
decimalString = `${decimalString.substring(0, bigIntDecimal - 1)}${(Number.parseInt(decimalString[bigIntDecimal - 1] || "0") + 1).toString()}`; | ||
} else { | ||
@@ -286,0 +282,0 @@ // Just slice off the extra digits |
@@ -1,5 +0,11 @@ | ||
import type { KyInstance, Options } from "ky"; | ||
import ky from "ky"; | ||
type Options = { | ||
headers?: Record<string, string>; | ||
apiKey?: string; | ||
method?: "GET" | "POST"; | ||
onError?: (error: NotWorth) => NotWorth; | ||
responseHandler?: (response: NotWorth) => NotWorth; | ||
[key: string]: NotWorth; | ||
}; | ||
let kyClient: typeof ky; | ||
let clientConfig: Options = {}; | ||
@@ -11,29 +17,41 @@ export const defaultRequestHeaders = | ||
export function setRequestClientConfig({ apiKey, ...config }: Options & { apiKey?: string }) { | ||
kyClient = ky.create({ | ||
...config, | ||
headers: { ...defaultRequestHeaders, ...config.headers, "x-api-key": apiKey }, | ||
}); | ||
export function setRequestClientConfig({ apiKey, ...config }: Options) { | ||
clientConfig = { ...config, apiKey }; | ||
} | ||
function getKyClient() { | ||
if (kyClient) return kyClient; | ||
kyClient = ky.create({ headers: defaultRequestHeaders }); | ||
return kyClient; | ||
async function fetchWithConfig(url: string, options: Options = {}) { | ||
const { apiKey, ...config } = clientConfig; | ||
const headers = { ...defaultRequestHeaders, ...config.headers, ...options.headers }; | ||
if (apiKey) headers["x-api-key"] = apiKey; | ||
try { | ||
const response = await fetch(url, { ...config, ...options, headers }); | ||
const body = await response.json(); | ||
if (options.responseHandler) return options.responseHandler(body); | ||
return body; | ||
} catch (error) { | ||
if (options.onError) return options.onError(error); | ||
console.error(error); | ||
} | ||
} | ||
const getTypedBaseRequestClient = (ky: KyInstance) => ({ | ||
get: <T>(url: string | URL | Request, options?: Options) => ky.get(url, options).json<T>(), | ||
post: <T>(url: string | URL | Request, options?: Options) => ky.post(url, options).json<T>(), | ||
}); | ||
export const RequestClient = { | ||
...getTypedBaseRequestClient(getKyClient()), | ||
get: async <T>(url: string, options?: Options): Promise<T> => | ||
fetchWithConfig(url, { ...options, method: "GET" }), | ||
post: async <T>(url: string, options?: Options): Promise<T> => | ||
fetchWithConfig(url, { ...options, method: "POST" }), | ||
extend: (options: Options) => { | ||
const extendedClient = getKyClient().extend(options); | ||
const extendedConfig = { ...clientConfig, ...options }; | ||
return { | ||
...getTypedBaseRequestClient(extendedClient), | ||
extend: RequestClient.extend, | ||
get: async <T>(url: string, options?: Options): Promise<T> => | ||
fetchWithConfig(url, { ...extendedConfig, ...options, method: "GET" }), | ||
post: async <T>(url: string, options?: Options): Promise<T> => | ||
fetchWithConfig(url, { ...extendedConfig, ...options, method: "POST" }), | ||
extend: (newOptions: Options) => RequestClient.extend({ ...extendedConfig, ...newOptions }), | ||
}; | ||
}, | ||
}; |
@@ -1,6 +0,5 @@ | ||
const errorMessages = { | ||
const errorCodes = { | ||
/** | ||
* Core | ||
*/ | ||
core_wallet_connection_not_found: 10001, | ||
core_estimated_max_spendable_chain_not_supported: 10002, | ||
@@ -13,7 +12,9 @@ core_extend_error: 10003, | ||
core_approve_asset_target_invalid: 10008, | ||
core_explorer_unsupported_chain: 10009, | ||
core_verify_message_not_supported: 10010, | ||
core_chain_halted: 10099, | ||
/** | ||
* Core - Wallet Connection | ||
* Core - Wallet | ||
*/ | ||
core_wallet_connection_not_found: 10100, | ||
core_wallet_xdefi_not_installed: 10101, | ||
@@ -28,2 +29,5 @@ core_wallet_evmwallet_not_installed: 10102, | ||
core_wallet_keepkey_not_installed: 10109, | ||
core_wallet_talisman_not_installed: 10110, | ||
core_wallet_not_keypair_wallet: 10111, | ||
core_wallet_sign_message_not_supported: 10110, | ||
/** | ||
@@ -44,8 +48,8 @@ * Core - Swap | ||
core_transaction_deposit_error: 10301, | ||
core_transaction_create_liquidity_rune_error: 10302, | ||
core_transaction_create_liquidity_base_error: 10302, | ||
core_transaction_create_liquidity_asset_error: 10303, | ||
core_transaction_create_liquidity_invalid_params: 10304, | ||
core_transaction_add_liquidity_invalid_params: 10305, | ||
core_transaction_add_liquidity_no_rune_address: 10306, | ||
core_transaction_add_liquidity_rune_error: 10307, | ||
core_transaction_add_liquidity_base_address: 10306, | ||
core_transaction_add_liquidity_base_error: 10307, | ||
core_transaction_add_liquidity_asset_error: 10308, | ||
@@ -59,12 +63,30 @@ core_transaction_withdraw_error: 10309, | ||
core_transaction_user_rejected: 10315, | ||
/** | ||
* Wallets | ||
*/ | ||
wallet_ledger_connection_error: 20001, | ||
wallet_ledger_connection_claimed: 20002, | ||
wallet_ledger_get_address_error: 20003, | ||
wallet_ledger_device_not_found: 20004, | ||
wallet_ledger_device_locked: 20005, | ||
wallet_connection_rejected_by_user: 20000, | ||
wallet_missing_api_key: 20001, | ||
wallet_chain_not_supported: 20002, | ||
wallet_missing_params: 20003, | ||
wallet_provider_not_found: 20004, | ||
wallet_failed_to_add_or_switch_network: 20005, | ||
wallet_ledger_connection_error: 20101, | ||
wallet_ledger_connection_claimed: 20102, | ||
wallet_ledger_get_address_error: 20103, | ||
wallet_ledger_device_not_found: 20104, | ||
wallet_ledger_device_locked: 20105, | ||
wallet_phantom_not_found: 20201, | ||
wallet_xdefi_not_found: 20301, | ||
wallet_xdefi_send_transaction_no_address: 20302, | ||
wallet_xdefi_contract_address_not_provided: 20303, | ||
wallet_xdefi_asset_not_defined: 20304, | ||
wallet_walletconnect_project_id_not_specified: 20401, | ||
wallet_walletconnect_connection_not_established: 20402, | ||
wallet_walletconnect_namespace_not_supported: 20403, | ||
wallet_trezor_failed_to_sign_transaction: 20501, | ||
wallet_trezor_derivation_path_not_supported: 20502, | ||
wallet_trezor_failed_to_get_address: 20503, | ||
wallet_talisman_not_enabled: 20601, | ||
wallet_talisman_not_found: 20602, | ||
wallet_polkadot_not_found: 20701, | ||
/** | ||
@@ -74,23 +96,71 @@ * Chainflip | ||
chainflip_channel_error: 30001, | ||
chainflip_broker_recipient_error: 30002, | ||
chainflip_unknown_asset: 30002, | ||
chainflip_broker_invalid_params: 30100, | ||
chainflip_broker_recipient_error: 30101, | ||
chainflip_broker_register: 30102, | ||
chainflip_broker_tx_error: 30103, | ||
chainflip_broker_withdraw: 30104, | ||
chainflip_broker_fund_only_flip_supported: 30105, | ||
chainflip_broker_fund_invalid_address: 30106, | ||
/** | ||
* THORChain | ||
*/ | ||
thorchain_chain_halted: 40001, | ||
thorchain_trading_halted: 40002, | ||
thorchain_swapin_router_required: 40100, | ||
thorchain_swapin_vault_required: 40101, | ||
thorchain_swapin_memo_required: 40102, | ||
thorchain_swapin_token_required: 40103, | ||
/** | ||
* SwapKit API | ||
*/ | ||
api_v2_invalid_response: 40001, | ||
api_v2_invalid_response: 50001, | ||
/** | ||
* Toolboxes | ||
*/ | ||
toolbox_cosmos_signer_not_defined: 90101, | ||
toolbox_cosmos_no_accounts_found: 90102, | ||
toolbox_cosmos_verify_signature_no_pubkey: 90103, | ||
toolbox_evm_no_abi_fragment: 90201, | ||
toolbox_evm_no_signer: 90202, | ||
toolbox_evm_no_signer_address: 90203, | ||
toolbox_evm_no_from_address: 90204, | ||
toolbox_evm_no_contract_address: 90205, | ||
toolbox_evm_no_fee_data: 90206, | ||
toolbox_evm_no_gas_price: 90207, | ||
toolbox_evm_no_to_address: 90208, | ||
toolbox_evm_invalid_gas_asset_address: 90209, | ||
toolbox_evm_provider_not_eip1193_compatible: 90210, | ||
toolbox_evm_error_estimating_gas_limit: 90211, | ||
toolbox_evm_error_sending_transaction: 90212, | ||
/** | ||
* Helpers | ||
*/ | ||
helpers_number_different_decimals: 99101, | ||
helpers_invalid_number_different_decimals: 99000, | ||
helpers_invalid_number_of_years: 99001, | ||
helpers_invalid_identifier: 99002, | ||
helpers_invalid_asset_url: 99003, | ||
helpers_invalid_asset_identifier: 99004, | ||
helpers_invalid_memo_type: 99005, | ||
helpers_failed_to_switch_network: 99103, | ||
helpers_not_found_provider: 99200, | ||
/** | ||
* Anything else | ||
*/ | ||
not_implemented: 99999, | ||
} as const; | ||
export type ErrorKeys = keyof typeof errorMessages; | ||
export type ErrorKeys = keyof typeof errorCodes; | ||
export class SwapKitError extends Error { | ||
constructor(errorKey: ErrorKeys, sourceError?: NotWorth) { | ||
static ErrorCode = errorCodes; | ||
constructor( | ||
errorOrErrorKey: ErrorKeys | { errorKey: ErrorKeys; info?: Record<string, NotWorth> }, | ||
sourceError?: NotWorth, | ||
) { | ||
const isErrorString = typeof errorOrErrorKey === "string"; | ||
const errorKey = isErrorString ? errorOrErrorKey : errorOrErrorKey.errorKey; | ||
if (sourceError) { | ||
@@ -104,6 +174,10 @@ console.error(sourceError, { | ||
super(errorKey, { | ||
cause: { code: errorMessages[errorKey], message: errorKey }, | ||
cause: { | ||
code: SwapKitError.ErrorCode[errorKey], | ||
message: `${errorKey}${isErrorString ? "" : `: ${JSON.stringify(errorOrErrorKey.info)}`}`, | ||
}, | ||
}); | ||
Object.setPrototypeOf(this, SwapKitError.prototype); | ||
} | ||
} |
@@ -6,3 +6,2 @@ import { ExplorerUrl, RPCUrl } from "./network"; | ||
Avalanche = "AVAX", | ||
Binance = "BNB", | ||
BinanceSmartChain = "BSC", | ||
@@ -24,4 +23,7 @@ Bitcoin = "BTC", | ||
THORChain = "THOR", | ||
Solana = "SOL", | ||
} | ||
export type WalletChain = Exclude<Chain, Chain.Chainflip | Chain.Radix>; | ||
export enum ChainId { | ||
@@ -32,3 +34,2 @@ Arbitrum = "42161", | ||
AvalancheHex = "0xa86a", | ||
Binance = "Binance-Chain-Tigris", | ||
BinanceSmartChain = "56", | ||
@@ -56,2 +57,3 @@ BinanceSmartChainHex = "0x38", | ||
THORChainStagenet = "thorchain-stagenet-v2", | ||
Solana = "solana", | ||
} | ||
@@ -66,3 +68,2 @@ | ||
[ChainId.BinanceSmartChain]: Chain.BinanceSmartChain, | ||
[ChainId.Binance]: Chain.Binance, | ||
[ChainId.BitcoinCash]: Chain.BitcoinCash, | ||
@@ -88,2 +89,3 @@ [ChainId.Bitcoin]: Chain.Bitcoin, | ||
[ChainId.THORChain]: Chain.THORChain, | ||
[ChainId.Solana]: Chain.Solana, | ||
}; | ||
@@ -99,3 +101,2 @@ | ||
BCH = 8, | ||
BNB = 8, | ||
BSC = 18, | ||
@@ -112,7 +113,8 @@ BTC = 8, | ||
MATIC = 18, | ||
MAYA = 10, | ||
MAYA = 8, | ||
OP = 18, | ||
SOL = 9, | ||
THOR = 8, | ||
XRD = 18, | ||
ZEC = 8, | ||
XRD = 18, | ||
} | ||
@@ -153,19 +155,7 @@ | ||
export type CosmosChain = | ||
| Chain.Cosmos | ||
| Chain.THORChain | ||
| Chain.Binance | ||
| Chain.Maya | ||
| Chain.Kujira; | ||
export const CosmosChains = [ | ||
Chain.Cosmos, | ||
Chain.THORChain, | ||
Chain.Binance, | ||
Chain.Maya, | ||
Chain.Kujira, | ||
] as const; | ||
export type CosmosChain = Chain.Cosmos | Chain.THORChain | Chain.Maya | Chain.Kujira; | ||
export const CosmosChains = [Chain.Cosmos, Chain.THORChain, Chain.Maya, Chain.Kujira] as const; | ||
export const TCSupportedChains = [ | ||
Chain.Avalanche, | ||
Chain.Binance, | ||
Chain.BinanceSmartChain, | ||
@@ -172,0 +162,0 @@ Chain.Bitcoin, |
@@ -1,4 +0,3 @@ | ||
import type { AssetValue } from "../modules/assetValue.ts"; | ||
import type { Chain, CosmosChain, EVMChain, UTXOChain } from "./chains.ts"; | ||
import type { WalletOption } from "./wallet.ts"; | ||
import type { ChainWallet } from "./wallet.ts"; | ||
@@ -46,12 +45,8 @@ export type ConnectConfig = { | ||
}; | ||
/** | ||
* @optional for setting the chainflip broker url | ||
*/ | ||
chainflipBrokerUrl?: string; | ||
}; | ||
export type AddChainWalletParams<T extends Chain> = { | ||
address: string; | ||
balance: AssetValue[]; | ||
walletType: WalletOption; | ||
chain: T; | ||
[key: string]: Todo; | ||
}; | ||
type ApisType = { [key in UTXOChain]?: string | Todo } & { | ||
@@ -63,4 +58,4 @@ [key in EVMChain]?: string | Todo; | ||
export type ConnectWalletParams = { | ||
addChain: <T extends Chain>(params: AddChainWalletParams<T>) => void; | ||
export type ConnectWalletParams<M = { [key in string]: NotWorth }> = { | ||
addChain: <T extends Chain>(params: ChainWallet<T> & M) => void; | ||
apis: ApisType; | ||
@@ -67,0 +62,0 @@ config: ConnectConfig; |
@@ -16,3 +16,2 @@ import type { Chain } from "./chains"; | ||
BCH = "m/44'/145'/0'/0", | ||
BNB = "m/44'/714'/0'/0", | ||
BSC = "m/44'/60'/0'/0", | ||
@@ -31,4 +30,5 @@ BTC = "m/84'/0'/0'/0", | ||
OP = "m/44'/60'/0'/0", | ||
SOL = "m/44'/501'/0'/0", | ||
THOR = "m/44'/931'/0'/0", | ||
XRD = "////", | ||
THOR = "m/44'/931'/0'/0", | ||
} | ||
@@ -42,3 +42,2 @@ | ||
BCH: [44, 145, 0, 0, 0], | ||
BNB: [44, 714, 0, 0, 0], | ||
BSC: [44, 60, 0, 0, 0], | ||
@@ -55,2 +54,3 @@ BTC: [84, 0, 0, 0, 0], | ||
OP: [44, 60, 0, 0, 0], | ||
SOL: [44, 501, 0, 0, 0], | ||
THOR: [44, 931, 0, 0, 0], | ||
@@ -57,0 +57,0 @@ |
export enum RPCUrl { | ||
Arbitrum = "https://arb1.arbitrum.io/rpc", | ||
Avalanche = "https://node-router.thorswap.net/avalanche-c", | ||
Binance = "", | ||
BinanceSmartChain = "https://bsc-dataseed.binance.org", | ||
@@ -23,2 +22,3 @@ Bitcoin = "https://node-router.thorswap.net/bitcoin", | ||
THORChainStagenet = "https://stagenet-rpc.ninerealms.com", | ||
Solana = "https://mainnet.helius-rpc.com/?api-key=2cbe3ae6-cfc5-4141-a093-0055d0fa3d80", | ||
} | ||
@@ -29,3 +29,2 @@ | ||
Avalanche = "https://snowtrace.io", | ||
Binance = "https://explorer.binance.org", | ||
BinanceSmartChain = "https://bscscan.com", | ||
@@ -43,6 +42,7 @@ Bitcoin = "https://blockchair.com/bitcoin", | ||
Optimism = "https://optimistic.etherscan.io", | ||
Polkadot = "https://polkadot.subscan.io/", | ||
Polkadot = "https://polkadot.subscan.io", | ||
Polygon = "https://polygonscan.com", | ||
Radix = "https://dashboard.radixdlt.com", | ||
THORChain = "https://runescan.io", | ||
Solana = "https://solscan.io", | ||
} |
@@ -0,5 +1,22 @@ | ||
import type { CovalentApiType, EthplorerApiType } from "@swapkit/toolbox-evm"; | ||
import type { BlockchairApiType } from "@swapkit/toolbox-utxo"; | ||
import { z } from "zod"; | ||
import type { AssetValue } from "../modules/assetValue"; | ||
import type { Chain, CosmosChain, UTXOChain } from "./chains"; | ||
import type { QuoteResponseRoute } from "./quotes"; | ||
type CovalentChains = | ||
| Chain.BinanceSmartChain | ||
| Chain.Polygon | ||
| Chain.Avalanche | ||
| Chain.Arbitrum | ||
| Chain.Optimism; | ||
export type ChainApis = { [key in CovalentChains]?: CovalentApiType } & { | ||
[key in Chain.Ethereum]?: EthplorerApiType; | ||
} & { [key in CosmosChain]?: Todo } & { | ||
[key in UTXOChain]?: BlockchairApiType; | ||
}; | ||
export type GenericSwapParams = { | ||
@@ -40,6 +57,6 @@ buyAsset?: AssetValue; | ||
export enum MemoType { | ||
NAME_REGISTER = "~", | ||
BOND = "BOND", | ||
DEPOSIT = "+", | ||
LEAVE = "LEAVE", | ||
THORNAME_REGISTER = "~", | ||
UNBOND = "UNBOND", | ||
@@ -46,0 +63,0 @@ WITHDRAW = "-", |
import type { | ||
ChainflipList, | ||
CoinGeckoList, | ||
MayaList, | ||
PancakeswapETHList, | ||
OneInchList, | ||
PancakeswapList, | ||
PangolinList, | ||
StargateARBList, | ||
SushiswapList, | ||
ThorchainList, | ||
TraderjoeList, | ||
UniswapList, | ||
WoofiList, | ||
TraderjoeV1List, | ||
TraderjoeV2List, | ||
UniswapV2List, | ||
UniswapV3List, | ||
} from "@swapkit/tokens"; | ||
@@ -19,13 +18,18 @@ | ||
export type TokenNames = | ||
| (typeof ThorchainList)["tokens"][number]["identifier"] | ||
| (typeof CoinGeckoList)["tokens"][number]["identifier"] | ||
| (typeof ChainflipList)["tokens"][number]["identifier"] | ||
| (typeof MayaList)["tokens"][number]["identifier"] | ||
| (typeof PancakeswapETHList)["tokens"][number]["identifier"] | ||
| (typeof OneInchList)["tokens"][number]["identifier"] | ||
| (typeof PancakeswapList)["tokens"][number]["identifier"] | ||
| (typeof PangolinList)["tokens"][number]["identifier"] | ||
| (typeof StargateARBList)["tokens"][number]["identifier"] | ||
| (typeof SushiswapList)["tokens"][number]["identifier"] | ||
| (typeof TraderjoeList)["tokens"][number]["identifier"] | ||
| (typeof WoofiList)["tokens"][number]["identifier"] | ||
| (typeof UniswapList)["tokens"][number]["identifier"] | ||
| (typeof ChainflipList)["tokens"][number]["identifier"]; | ||
| (typeof ThorchainList)["tokens"][number]["identifier"] | ||
| (typeof TraderjoeV1List)["tokens"][number]["identifier"] | ||
| (typeof TraderjoeV2List)["tokens"][number]["identifier"] | ||
| (typeof UniswapV2List)["tokens"][number]["identifier"] | ||
| (typeof UniswapV3List)["tokens"][number]["identifier"]; | ||
// | (typeof CoinGeckoList)["tokens"][number]["identifier"] | ||
// | (typeof PancakeswapETHList)["tokens"][number]["identifier"] | ||
// | (typeof StargateARBList)["tokens"][number]["identifier"] | ||
// | (typeof TraderjoeList)["tokens"][number]["identifier"] | ||
// | (typeof WoofiList)["tokens"][number]["identifier"] | ||
// | (typeof UniswapList)["tokens"][number]["identifier"]; |
import type { CosmosWallets, ThorchainWallets } from "@swapkit/toolbox-cosmos"; | ||
import type { EVMWallets } from "@swapkit/toolbox-evm"; | ||
import type { SolanaWallet } from "@swapkit/toolbox-solana"; | ||
import type { SubstrateWallets } from "@swapkit/toolbox-substrate"; | ||
import type { UTXOWallets } from "@swapkit/toolbox-utxo"; | ||
import type { Eip1193Provider } from "ethers"; | ||
import type { AssetValue } from "../modules/assetValue"; | ||
import type { Chain } from "./chains"; | ||
import type { ConnectWalletParams } from "./commonTypes"; | ||
@@ -15,20 +18,25 @@ declare global { | ||
export type { CosmosWallets, ThorchainWallets, EVMWallets, SubstrateWallets, UTXOWallets }; | ||
export enum WalletOption { | ||
BRAVE = "BRAVE", | ||
COINBASE_MOBILE = "COINBASE_MOBILE", | ||
COINBASE_WEB = "COINBASE_WEB", | ||
EIP6963 = "EIP6963", | ||
EXODUS = "EXODUS", | ||
KEEPKEY = "KEEPKEY", | ||
KEPLR = "KEPLR", | ||
KEYSTORE = "KEYSTORE", | ||
KEEPKEY = "KEEPKEY", | ||
XDEFI = "XDEFI", | ||
LEDGER = "LEDGER", | ||
METAMASK = "METAMASK", | ||
COINBASE_WEB = "COINBASE_WEB", | ||
COINBASE_MOBILE = "COINBASE_MOBILE", | ||
OKX = "OKX", | ||
OKX_MOBILE = "OKX_MOBILE", | ||
PHANTOM = "PHANTOM", | ||
POLKADOT_JS = "POLKADOT_JS", | ||
RADIX_WALLET = "RADIX_WALLET", | ||
TREZOR = "TREZOR", | ||
TALISMAN = "TALISMAN", | ||
TRUSTWALLET_WEB = "TRUSTWALLET_WEB", | ||
LEDGER = "LEDGER", | ||
KEPLR = "KEPLR", | ||
OKX = "OKX", | ||
OKX_MOBILE = "OKX_MOBILE", | ||
BRAVE = "BRAVE", | ||
WALLETCONNECT = "WALLETCONNECT", | ||
EIP6963 = "EIP6963", | ||
EXODUS = "EXODUS", | ||
RADIX_WALLET = "RADIX_WALLET", | ||
XDEFI = "XDEFI", | ||
} | ||
@@ -42,20 +50,35 @@ | ||
export type ChainWallet = { | ||
chain: Chain; | ||
export type ChainWallet<T extends Chain> = { | ||
chain: T; | ||
address: string; | ||
balance: AssetValue[]; | ||
walletType: WalletOption; | ||
disconnect?: () => void; | ||
signMessage?: (message: string) => Promise<string>; | ||
}; | ||
export type EmptyWallet = { [key in Chain]?: unknown }; | ||
export type BaseWallet<T extends EmptyWallet | unknown> = { | ||
// @ts-expect-error | ||
[key in Chain]: ChainWallet & T[key]; | ||
export type BaseWallet<T extends EmptyWallet | Record<string, unknown>> = { | ||
[key in Chain]: ChainWallet<key> & (T extends EmptyWallet ? T[key] : never); | ||
}; | ||
export type Wallet = BaseWallet< | ||
EVMWallets & CosmosWallets & ThorchainWallets & UTXOWallets & SubstrateWallets | ||
export type FullWallet = BaseWallet< | ||
EVMWallets & UTXOWallets & CosmosWallets & ThorchainWallets & SubstrateWallets & SolanaWallet | ||
>; | ||
/** | ||
* @deprecated use FullWallet instead | ||
*/ | ||
export type Wallet = FullWallet; | ||
export type SwapKitWallet<ConnectParams extends Todo[]> = ( | ||
params: ConnectWalletParams, | ||
) => (...connectParams: ConnectParams) => boolean | Promise<boolean>; | ||
export type SwapKitPluginParams<Config = {}> = { | ||
getWallet: <T extends Chain>(chain: T) => FullWallet[T]; | ||
stagenet?: boolean; | ||
config: Config; | ||
}; | ||
export type EIP6963ProviderInfo = { | ||
@@ -62,0 +85,0 @@ walletId: string; |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
3
38
442617
6
5482
1
+ Added@swapkit/tokens@1.0.3
+ Addedpicocolors@1.0.1
+ Added@swapkit/tokens@1.0.3(transitive)
+ Addedpicocolors@1.0.1(transitive)
- Removedky@1.2.3
- Removed@swapkit/tokens@0.0.0-nightly-20240607015403(transitive)
- Removedky@1.2.3(transitive)