diff --git a/examples/algo-example/src/app/algo.wallet.examples.ts b/examples/algo-example/src/app/algo.wallet.examples.ts index 01c4b485d2..1fcc03ed53 100644 --- a/examples/algo-example/src/app/algo.wallet.examples.ts +++ b/examples/algo-example/src/app/algo.wallet.examples.ts @@ -10,6 +10,6 @@ export async function algoWalletExample() { // Generate an address from the private key. // https://apidoc.tatum.io/tag/Algorand#operation/AlgorandGenerateAddress - const addressFromPrivateKey = await algoSDK.wallet.generateAddressFromPrivatetKey(secret) + const addressFromPrivateKey = await algoSDK.wallet.generateAddressFromPrivateKey(secret) console.log(`addressFromPrivateKey is ${addressFromPrivateKey}`) } diff --git a/package.json b/package.json index fc3bee7ef4..64ee3f9314 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "tatumio", - "version": "2.2.101", + "version": "2.2.102", "license": "MIT", "repository": "https://github.com/tatumio/tatum-js", "scripts": { @@ -133,4 +133,4 @@ "@solana/web3.js": "1.56.2", "scrypt": "github:barrysteyn/node-scrypt#fb60a8d3c158fe115a624b5ffa7480f3a24b03fb" } -} \ No newline at end of file +} diff --git a/packages/blockchain/algo/src/lib/services/algo.tx.ts b/packages/blockchain/algo/src/lib/services/algo.tx.ts index b37439708b..a780faf257 100644 --- a/packages/blockchain/algo/src/lib/services/algo.tx.ts +++ b/packages/blockchain/algo/src/lib/services/algo.tx.ts @@ -75,7 +75,7 @@ export const algoTxService = (args: { algoWeb: AlgoWeb }, apiCalls: AlgoApiCalls const decoder = new base32.Decoder({ type: 'rfc4648' }) const from = isWithSignatureId(body) ? body.from - : algoWallet().generateAddressFromPrivatetKey(body.fromPrivateKey) + : algoWallet().generateAddressFromPrivateKey(body.fromPrivateKey) const txn = algosdk.makeAssetTransferTxnWithSuggestedParams( from, from, @@ -474,7 +474,7 @@ export const algoTxService = (args: { algoWeb: AlgoWeb }, apiCalls: AlgoApiCalls const vc = await ApiServices.ledger.virtualCurrency.getCurrency(account.currency) txData = await prepareTransferFTSignedTransaction({ body: { - from: algoWallet().generateAddressFromPrivatetKey(privateKey), + from: algoWallet().generateAddressFromPrivateKey(privateKey), fromPrivateKey: privateKey, to: body.address, amount: body.amount, diff --git a/packages/blockchain/algo/src/lib/services/algo.wallet.ts b/packages/blockchain/algo/src/lib/services/algo.wallet.ts index ba02e0ed32..96fba0729d 100644 --- a/packages/blockchain/algo/src/lib/services/algo.wallet.ts +++ b/packages/blockchain/algo/src/lib/services/algo.wallet.ts @@ -27,7 +27,7 @@ export const algoWallet = () => { * @param privateKey Private key to use * @returns blockchain address */ - generateAddressFromPrivatetKey(privateKey: string): string { + generateAddressFromPrivateKey(privateKey: string): string { const decoder = new base32.Decoder({ type: 'rfc4648' }) const secretKey = decoder.write(privateKey).buf const mn = algosdk.secretKeyToMnemonic(secretKey) diff --git a/packages/blockchain/algo/src/lib/services/tx/algo.tx.fungible.ts b/packages/blockchain/algo/src/lib/services/tx/algo.tx.fungible.ts index 403b25fba2..51f0d0d12b 100644 --- a/packages/blockchain/algo/src/lib/services/tx/algo.tx.fungible.ts +++ b/packages/blockchain/algo/src/lib/services/tx/algo.tx.fungible.ts @@ -36,7 +36,7 @@ export const prepareCreateFTSignedTransaction = async ({ const from = isWithSignatureId(body as DeployAlgoErc20KMS) ? (body as DeployAlgoErc20KMS).from - : algoWallet().generateAddressFromPrivatetKey((body as DeployAlgoErc20).fromPrivateKey) + : algoWallet().generateAddressFromPrivateKey((body as DeployAlgoErc20).fromPrivateKey) const decimals = body.digits || 0 /** @@ -92,7 +92,7 @@ export const prepareTransferFTSignedTransaction = async ({ const from = isWithSignatureId(body) ? body.from - : algoWallet().generateAddressFromPrivatetKey(body.fromPrivateKey) + : algoWallet().generateAddressFromPrivateKey(body.fromPrivateKey) const decimals = body.digits || 0 const txn = algosdk.makeAssetTransferTxnWithSuggestedParams( @@ -139,7 +139,7 @@ export const prepareBurnFTSignedTransaction = async ({ const from = isWithSignatureId(body) ? body.from - : algoWallet().generateAddressFromPrivatetKey(body.fromPrivateKey) + : algoWallet().generateAddressFromPrivateKey(body.fromPrivateKey) const txn = algosdk.makeAssetDestroyTxnWithSuggestedParams( from, diff --git a/packages/blockchain/algo/src/lib/services/tx/algo.tx.native.ts b/packages/blockchain/algo/src/lib/services/tx/algo.tx.native.ts index 1d4cfc7dc2..a4e78e5986 100644 --- a/packages/blockchain/algo/src/lib/services/tx/algo.tx.native.ts +++ b/packages/blockchain/algo/src/lib/services/tx/algo.tx.native.ts @@ -33,7 +33,7 @@ export const prepareSignedTransaction = async ({ const from = isWithSignatureId(body as TransferAlgoKMS | TransferAlgoBlockchainKMS) ? account - : algoWallet().generateAddressFromPrivatetKey(privateKey) + : algoWallet().generateAddressFromPrivateKey(privateKey) if ((body as TransferAlgoBlockchain).to) { const { balance } = await apiCalls.getBlockchainAccountBalance(from) diff --git a/packages/blockchain/algo/src/lib/services/tx/algo.tx.nft.ts b/packages/blockchain/algo/src/lib/services/tx/algo.tx.nft.ts index 8fe97bff28..5d213f5c83 100644 --- a/packages/blockchain/algo/src/lib/services/tx/algo.tx.nft.ts +++ b/packages/blockchain/algo/src/lib/services/tx/algo.tx.nft.ts @@ -38,7 +38,7 @@ export const prepareCreateNFTSignedTransaction = async ({ const from = isWithSignatureId(body) ? body.from - : algoWallet().generateAddressFromPrivatetKey(body.fromPrivateKey) + : algoWallet().generateAddressFromPrivateKey(body.fromPrivateKey) const decimals = (body as unknown as MintNftExpressAlgorand).attr?.decimals || 0 const total = new BigNumber((body as unknown as MintNftExpressAlgorand).attr?.total || 1).toNumber() @@ -91,7 +91,7 @@ export const prepareTransferNFTSignedTransaction = async ({ const from = isWithSignatureId(body as TransferNftAlgoKMS) ? (body as TransferNftAlgoKMS).from - : algoWallet().generateAddressFromPrivatetKey((body as TransferNftAlgo).fromPrivateKey) + : algoWallet().generateAddressFromPrivateKey((body as TransferNftAlgo).fromPrivateKey) const amount = new BigNumber((body as TransferNftAlgoExpress).amount || 1).toNumber() @@ -136,7 +136,7 @@ export const prepareBurnNFTSignedTransaction = async ({ const txn = algosdk.makeAssetDestroyTxnWithSuggestedParams( isWithSignatureId(body as BurnNftAlgoKMS) ? (body as BurnNftAlgoKMS).from - : algoWallet().generateAddressFromPrivatetKey((body as BurnNftAlgo).fromPrivateKey), + : algoWallet().generateAddressFromPrivateKey((body as BurnNftAlgo).fromPrivateKey), undefined, Number(body.contractAddress), { diff --git a/packages/blockchain/egld/src/lib/__tests__/egld.wallet.spec.ts b/packages/blockchain/egld/src/lib/__tests__/egld.wallet.spec.ts index 37552b75f9..86879a3857 100644 --- a/packages/blockchain/egld/src/lib/__tests__/egld.wallet.spec.ts +++ b/packages/blockchain/egld/src/lib/__tests__/egld.wallet.spec.ts @@ -1,5 +1,6 @@ import { REPLACE_ME_WITH_TATUM_API_KEY, TEST_DATA } from '@tatumio/shared-testing-common' import { TatumEgldSDK } from '../egld.sdk' +import { egldWallet } from '../services/egld.wallet' // Too unstable describe.skip('EgldSDK - tx', () => { @@ -33,3 +34,31 @@ describe.skip('EgldSDK - tx', () => { }) }) }) + +describe('egldWallet - generateAddressFromXPub', () => { + const wallet = egldWallet() + + it('should generate same address as generateAddress (testnet)', async () => { + const addressFromXPub = await wallet.generateAddressFromXPub(TEST_DATA.MNEMONIC, 3, true) + const addressFromGenerate = await wallet.generateAddress(true, TEST_DATA.MNEMONIC, 3) + + expect(addressFromXPub).toBe(addressFromGenerate) + expect(addressFromXPub).toBe('erd1ej4y5ygndu76vcvfzrv4h3vnrwy30gze0mtv4psv90awp7z08l2sqlc7fl') + }) + + it('should generate same address as generateAddress (mainnet)', async () => { + const addressFromXPub = await wallet.generateAddressFromXPub(TEST_DATA.MNEMONIC, 0, false) + const addressFromGenerate = await wallet.generateAddress(false, TEST_DATA.MNEMONIC, 0) + + expect(addressFromXPub).toBe(addressFromGenerate) + }) + + it('should generate same address for multiple derivation indices', async () => { + for (const i of [0, 1, 2, 5, 10]) { + const addressFromXPub = await wallet.generateAddressFromXPub(TEST_DATA.MNEMONIC, i, true) + const addressFromGenerate = await wallet.generateAddress(true, TEST_DATA.MNEMONIC, i) + + expect(addressFromXPub).toBe(addressFromGenerate) + } + }) +}) diff --git a/packages/blockchain/egld/src/lib/services/egld.wallet.ts b/packages/blockchain/egld/src/lib/services/egld.wallet.ts index 1f0fa3f4d8..2a43976948 100644 --- a/packages/blockchain/egld/src/lib/services/egld.wallet.ts +++ b/packages/blockchain/egld/src/lib/services/egld.wallet.ts @@ -14,8 +14,7 @@ const generatePrivateKey = async (testnet: boolean, mnemonic: string, i: number) const convertPrivateKey = (privKey: string) => { const publicKey = getPublicKey(Buffer.from(privKey, 'hex'), false).toString('hex') const words = bech32.toWords(Buffer.from(publicKey.slice(-64), 'hex')) - const address = bech32.encode('erd', words) - return address + return bech32.encode('erd', words) } export const egldWallet = () => { @@ -53,13 +52,41 @@ export const egldWallet = () => { }, /** - * Generate address from private key - * @param privateKey private key to use - * @returns blockchain private key to the address + * Generate address from mnemonic + * @param testnet testnet or mainnet version of address + * @param mnemonic mnemonic to generate address from + * @param i derivation index of address to generate + * @returns blockchain address */ generateAddress: async (testnet: boolean, mnemonic: string, i: number) => { const privateKey = await generatePrivateKey(testnet, mnemonic, i) return convertPrivateKey(privateKey) }, + + /** + * Generate address from private key + * @param privateKey private key to use + * @returns blockchain address + */ + generateAddressFromPrivateKey: (privateKey: string): string => { + return convertPrivateKey(privateKey) + }, + + /** + * Generate address from mnemonic + * Note: EGLD does not support xpub, so mnemonic is used instead for API consistency + * @param mnemonic mnemonic to generate address from + * @param i derivation index of address to generate. Up to 2^31 addresses can be generated. + * @param testnet testnet or mainnet version of address + * @returns blockchain address + */ + generateAddressFromXPub: async (mnemonic: string, i: number, testnet?: boolean): Promise => { + const path = (testnet ? COMMON_TESTNET_DERIVATION_PATH + "'" : DERIVATION_PATH.EGLD) + `/${i}'` + const seed = await mnemonicToSeed(mnemonic) + const { key } = derivePath(path, seed.toString('hex')) + const publicKey = getPublicKey(key, false).toString('hex') + const words = bech32.toWords(Buffer.from(publicKey.slice(-64), 'hex')) + return bech32.encode('erd', words) + }, } } diff --git a/packages/blockchain/tron/src/lib/services/tron.utils.ts b/packages/blockchain/tron/src/lib/services/tron.utils.ts index abc999ac90..4727f2a4b3 100644 --- a/packages/blockchain/tron/src/lib/services/tron.utils.ts +++ b/packages/blockchain/tron/src/lib/services/tron.utils.ts @@ -1,5 +1,8 @@ import { ec as EC } from 'elliptic' import { keccak_256 } from 'js-sha3' +// tronweb lib dont have any typings (not even in @types) +// @ts-ignore +import TronWeb from 'tronweb' const hexChar2byte = (c: string) => { let d = 0 @@ -95,3 +98,7 @@ export const generateAddress = (publicKey: Buffer) => byteArray2hexStr(computeAddress(hexStr2byteArray(generatePubKey(publicKey)))) export const isBase58 = (value: string): boolean => /^[A-HJ-NP-Za-km-z1-9]*$/.test(value) + +export const convertAddressFromHex = (address: string) => TronWeb.address.fromHex(address) + +export const convertAddressToHex = (address: string) => TronWeb.address.toHex(address) diff --git a/packages/blockchain/tron/src/lib/services/tron.wallet.ts b/packages/blockchain/tron/src/lib/services/tron.wallet.ts index 3b35fce641..f2d940110f 100644 --- a/packages/blockchain/tron/src/lib/services/tron.wallet.ts +++ b/packages/blockchain/tron/src/lib/services/tron.wallet.ts @@ -2,7 +2,7 @@ import { TronWallet, Wallet } from '@tatumio/api-client' import { Blockchain, DERIVATION_PATH } from '@tatumio/shared-core' import { BIP32Interface, fromBase58, fromPublicKey, fromSeed } from 'bip32' import { generateMnemonic, mnemonicToSeed } from 'bip39' -import { generateAddress, isBase58 } from './tron.utils' +import { convertAddressFromHex, convertAddressToHex, generateAddress, isBase58 } from './tron.utils' // tronweb lib dont have any typings (not even in @types) // @ts-ignore @@ -73,10 +73,12 @@ export const tronWallet = (args: { tronWeb: ITronWeb }) => { * @param privateKey private key to use * @returns blockchain private key to the address */ - generateAddressFromPrivatekey(privateKey: string): string { + generateAddressFromPrivateKey(privateKey: string): string { return TronWeb.address.fromPrivateKey(privateKey) }, custodial: tronCustodial(args), gasPump: tronGasPump(args), + convertAddressFromHex: convertAddressFromHex, + convertAddressToHex: convertAddressToHex, } } diff --git a/packages/shared/blockchain/evm-based/src/index.ts b/packages/shared/blockchain/evm-based/src/index.ts index cf7d433192..b98c330a79 100644 --- a/packages/shared/blockchain/evm-based/src/index.ts +++ b/packages/shared/blockchain/evm-based/src/index.ts @@ -1,22 +1,26 @@ export * from './lib/evm-based.utils' export * from './lib/evm-based.sdk' +export * from './lib/evm-based.sdk.errors' + export * from './lib/services/evm-based.web3' export * from './lib/services/evm-based.kms' export * from './lib/services/evm-based.custodial' export * from './lib/services/evm-based.smartContract' export * from './lib/services/evm-based.wallet' +export * from './lib/services/evm-based.marketplace' +export * from './lib/services/evm-based.auction' +export * from './lib/services/evm-based.gas.pump' + export * from './lib/transactions/erc20' export * from './lib/transactions/erc721' export * from './lib/transactions/multitoken' export * from './lib/transactions/custodial' export * from './lib/transactions/smartContract' export * from './lib/transactions/native' -export * from './lib/services/evm-based.marketplace' export * from './lib/transactions/marketplace' -export * from './lib/contracts' -export * from './lib/services/evm-based.auction' -export * from './lib/transactions/erc20' -export * from './lib/contracts' -export * from './lib/evm-based.sdk.errors' export * from './lib/transactions/gasPump' -export * from './lib/services/evm-based.gas.pump' + +export * from './lib/contracts' + +export * from './lib/dto/listing' +export * from './lib/dto/auction' diff --git a/packages/shared/blockchain/evm-based/src/lib/dto/auction.ts b/packages/shared/blockchain/evm-based/src/lib/dto/auction.ts new file mode 100644 index 0000000000..bc7e8f5b3c --- /dev/null +++ b/packages/shared/blockchain/evm-based/src/lib/dto/auction.ts @@ -0,0 +1,47 @@ +export interface Auction { + /* + address of the seller + */ + seller: string + /* + address of the token to sale + */ + nftAddress: string + /* + ID of the NFT + */ + tokenId: string + /* + if the auction is for ERC721 - true - or ERC1155 - false + */ + isErc721: boolean + /* + Block height of end of auction + */ + endedAt: string + /* + Block height, in which the auction started. + */ + startedAt: string + /* + optional - if the auction is settled in the ERC20 token or in native currency + */ + erc20Address?: string + /* + for ERC-1155 - how many tokens are for sale + */ + amount: string + /* + Ending price of the asset at the end of the auction + */ + endingPrice: string + /* + Actual highest bidder + */ + bidder?: string + + /* + Actual highest bid + */ + highestBid?: string +} diff --git a/packages/shared/blockchain/evm-based/src/lib/dto/listing.ts b/packages/shared/blockchain/evm-based/src/lib/dto/listing.ts new file mode 100644 index 0000000000..9f375d8549 --- /dev/null +++ b/packages/shared/blockchain/evm-based/src/lib/dto/listing.ts @@ -0,0 +1,57 @@ +enum ListingState { + INITIATED = '0', + SOLD = '1', + CANCELLED = '2', +} + +export interface MarketplaceListing { + /** + * ID of the listing + */ + listingId: string + + /** + * whether listing is for ERC721 or ERC1155 + */ + isErc721: boolean + + /** + * State of the listing, + */ + state: ListingState + + /** + * Address of the NFT asset contract + */ + nftAddress: string + + /** + * Address of the seller + */ + seller: string + + /** + * Address of the ERC20 token, which will be used for paying. 0x0 if native asset is used + */ + erc20Address: string + + /** + * TokenID to sell + */ + tokenId: string + + /** + * Amount of assets to sell. Valid only for ERC1155. + */ + amount: string + + /** + * Price to sell asset for. + */ + price: string + + /** + * Address of the buyer, if already exists. + */ + buyer: string +}