Skip to content

Commit

Permalink
ALL-2165 Rename com to io
Browse files Browse the repository at this point in the history
  • Loading branch information
Hathoriel committed Jul 19, 2023
2 parents 993e0ad + 41397f5 commit c655c9b
Show file tree
Hide file tree
Showing 10 changed files with 206 additions and 112 deletions.
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
## [3.0.0] - 2023.07.19
### Changed
- Updated npm package name from @tatumcom/js to @tatumio/tatum.
- Updated npm token to ensure correct package retrieval.
- Made changes to the readme page for improved documentation.

## [1.5.11] - 2023.07.13
### Changed
- Fix rpc calls without api key & Added haqq archive/non-archive calls

## [1.5.10] - 2023.07.10
### Changed
- Selected Archive/Non-Archive node for Ethereum RPC calls based on method
Expand Down
2 changes: 1 addition & 1 deletion docs/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@

Welcome to the Tatum SDK documentation! Use the following links to navigate to the desired parts of our documentation:

- [Getting Started with Tatum SDK](https://docs.tatum.com)
- [Getting Started with Tatum SDK](https://docs.tatum.io)
- [Structure](https://github.com/tatumio/tatum-js/blob/master/docs/structure.md)
- [RPC submodule](https://github.com/tatumio/tatum-js/blob/master/docs/rpc.md)
16 changes: 8 additions & 8 deletions docs/rpc.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# RPC
All RPC calls are implemented in the `tatum.rpc.*` submodule.

See the [RPC API Reference](https://docs.tatum.com/docs/rpc-api-reference) for more about supported chains and methods.
See the [RPC API Reference](https://docs.tatum.io/docs/rpc-api-reference) for more about supported chains and methods.

## Load Balancer

Expand Down Expand Up @@ -51,14 +51,14 @@ When you need to stop load balancer, you should can call `destroy` method. This
The list of nodes is dynamically fetched from the remote server and it is defined for every blockchain.

```
https://rpc.tatum.com/${network}/list.json
https://rpc.tatum.io/${network}/list.json
```
Networks enum is available in the [Network.ts](https://github.com/tatumio/tatum-js/blob/master/src/dto/Network.ts)

For instance if we will need Bitcoin mainnet nodes, we will use this URL:

```
curl https://rpc.tatum.com/bitcoin-mainnet/list.json
curl https://rpc.tatum.io/bitcoin-mainnet/list.json
```

The response is a list of nodes with their url, type (0 - normal, 1 - archive) and location.
Expand All @@ -68,27 +68,27 @@ The response is a list of nodes with their url, type (0 - normal, 1 - archive) a
{
"location": "Sydney",
"type": 0,
"url": "https://02-sydney-007-01.rpc.tatum.com./"
"url": "https://02-sydney-007-01.rpc.tatum.io/"
},
{
"location": "Tokyo",
"type": 0,
"url": "https://02-tokyo-007-02.rpc.tatum.com./"
"url": "https://02-tokyo-007-02.rpc.tatum.io/"
},
{
"location": "Dallas",
"type": 0,
"url": "https://02-dallas-007-03.rpc.tatum.com./"
"url": "https://02-dallas-007-03.rpc.tatum.io/"
},
{
"location": "Sao Paulo",
"type": 0,
"url": "https://02-saopaulo-007-04.rpc.tatum.com./"
"url": "https://02-saopaulo-007-04.rpc.tatum.io/"
},
{
"location": "Warsaw",
"type": 0,
"url": "https://01-warsaw-007-05.rpc.tatum.com./"
"url": "https://01-warsaw-007-05.rpc.tatum.io/"
}
]
```
Expand Down
2 changes: 2 additions & 0 deletions src/dto/Network.ts
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,8 @@ export const LOAD_BALANCER_NETWORKS = [...UTXO_LOAD_BALANCER_NETWORKS, ...EVM_LO
export const EVM_ARCHIVE_NON_ARCHIVE_LOAD_BALANCER_NETWORKS = [
Network.ETHEREUM,
Network.ETHEREUM_SEPOLIA,
Network.HAQQ,
Network.HAQQ_TESTNET,
]

export const SOLANA_NETWORKS = [Network.SOLANA, Network.SOLANA_DEVNET]
Expand Down
242 changes: 148 additions & 94 deletions src/service/address/address.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@ import {
TokenDetails,
isDataApiEvmEnabledNetwork,
isDataApiUtxoEnabledNetwork,
isEvmBasedNetwork,
isEvmBasedNetwork, isTronNetwork
} from '../../dto'
import { CONFIG, Constant, ErrorUtils, ResponseDto, Utils } from '../../util'
import { EvmRpc, GenericRpc } from '../rpc'
import { EvmRpc, GenericRpc, TronRpc } from '../rpc'
import { Network, TatumConfig } from '../tatum'
import { AddressBalance, AddressTransaction, GetAddressTransactionsQuery } from './address.dto'
import { decodeUInt256 } from '../../util/decode'

@Service({
factory: (data: { id: string }) => {
Expand Down Expand Up @@ -40,22 +41,23 @@ export class Address {
}: AddressBalanceDetails): Promise<ResponseDto<AddressBalance[]>> {
const chain = this.config.network
return ErrorUtils.tryFail(async () => {
const [nativeBalances, tokenBalances] = await Promise.all([
this.getNativeBalance(addresses),
isDataApiEvmEnabledNetwork(chain) &&
this.connector
.get<{ result: AddressBalance[] }, ApiBalanceRequest>({
path: `data/balances`,
params: {
pageSize,
offset: page,
excludeMetadata: true,
chain,
addresses: addresses.join(','),
},
})
.then((r) => r.result),
])

const fullBalances = isTronNetwork(chain) ? await this.getFullBalance(addresses) : { nativeBalance: '0', tokenBalances: [] }
const nativeBalances = isTronNetwork(chain) ? [fullBalances.nativeBalance] : await this.getNativeBalance(addresses)
const tokenBalances = isTronNetwork(chain) ? fullBalances.tokenBalances : isDataApiEvmEnabledNetwork(chain) &&
await this.connector
.get<{ result: AddressBalance[] }, ApiBalanceRequest>({
path: `data/balances`,
params: {
pageSize,
offset: page,
excludeMetadata: true,
chain,
addresses: addresses.join(','),
},
})
.then((r) => r.result)

const result: AddressBalance[] = []
for (const [i, nativeBalance] of nativeBalances.entries()) {
result.push({
Expand All @@ -69,7 +71,8 @@ export class Address {
if (!tokenBalances) {
return result
}
return [...result, ...(await this.processTokenBalanceDetails(tokenBalances, chain))]
const serializedTokenBalances = isTronNetwork(chain) ? tokenBalances : await this.processTokenBalanceDetails(tokenBalances, chain)
return [...result, ...serializedTokenBalances]
})
}

Expand All @@ -86,40 +89,61 @@ export class Address {
page = 0,
}: GetAddressTransactionsQuery): Promise<ResponseDto<AddressTransaction[]>> {
const chain = this.config.network
let path
return ErrorUtils.tryFail(async () => {
if (isDataApiEvmEnabledNetwork(chain)) {
return this.connector
.get<{ result: AddressTransaction[] }>({
path: `data/transactions`,
params: {
chain,
addresses: address,
transactionTypes: transactionTypes?.join(),
transactionSubtype: transactionDirection,
blockFrom: fromBlock,
blockTo: toBlock,
pageSize,
offset: page,
},
})
.then((r) => r.result)
}
let path
if ([Network.BITCOIN, Network.BITCOIN_TESTNET].includes(chain)) {
path = `bitcoin/transaction/address/${address}`
} else if ([Network.LITECOIN, Network.LITECOIN_TESTNET].includes(chain)) {
path = `litecoin/transaction/address/${address}`
} else if ([Network.DOGECOIN, Network.DOGECOIN_TESTNET].includes(chain)) {
path = `dogecoin/transaction/address/${address}`
}
if (!path) {
// TODO: implement for other networks - TRON, XRP, CARDANO, SOL, XLM etc etc
throw new Error(`Not supported for ${chain} network.`)
switch (true) {
case isDataApiEvmEnabledNetwork(chain):
return this.connector
.get<{ result: AddressTransaction[] }>({
path: `data/transactions`,
params: {
chain,
addresses: address,
transactionTypes: transactionTypes?.join(),
transactionSubtype: transactionDirection,
blockFrom: fromBlock,
blockTo: toBlock,
pageSize,
offset: page,
},
})
.then((r) => r.result)
case [Network.BITCOIN, Network.BITCOIN_TESTNET].includes(chain):
path = `bitcoin/transaction/address/${address}`
break
case [Network.LITECOIN, Network.LITECOIN_TESTNET].includes(chain):
path = `litecoin/transaction/address/${address}`
break
case [Network.DOGECOIN, Network.DOGECOIN_TESTNET].includes(chain):
path = `dogecoin/transaction/address/${address}`
break
default:
throw new Error(`Not supported for ${chain} network.`)
}
return this.processUtxoBasedTxs(path, pageSize, page, transactionDirection, chain, address)
})
}

private async processTRC20TokenBalanceDetails(tokenBalances: {[key: string]: string}) {
const balances = Object.entries(tokenBalances[0])
const serializedTokenBalance: Array<unknown> = []
for (let i = 0; i < balances.length; i++) {
const asset = await Utils.getRpc<TronRpc>(this.id, this.config).triggerConstantContract(
balances[i][0], balances[i][0], 'symbol()', '', { visible: true }
).then(r => decodeUInt256(r.constant_result[0]))
const decimals = await Utils.getRpc<TronRpc>(this.id, this.config).triggerConstantContract(
balances[i][0], balances[i][0], 'decimals()', '', { visible: true }
).then(r => decodeUInt256(r.constant_result[0]))
const balance = balances[i][1]
serializedTokenBalance.push({
asset,
decimals,
balance
})
}
return serializedTokenBalance
}

private async processTokenBalanceDetails(tokenBalances: AddressBalance[], chain: Network) {
const result: AddressBalance[] = []
// Processing token details
Expand Down Expand Up @@ -173,8 +197,8 @@ export class Address {
blockNumber: number
time: number
hash: string
inputs: Array<{ coin: { address: string; value: number | string } }>
outputs: Array<{ address: string; value: string | number }>
inputs: Array<{ coin: { address: string, value: number | string } }>
outputs: Array<{ address: string, value: string | number }>
}>
>({
path,
Expand Down Expand Up @@ -232,61 +256,91 @@ export class Address {
})
}

private async getNativeBalance(addresses: string[]): Promise<string[]> {
private async getFullBalance(addresses: string[]): Promise<{nativeBalance: string, tokenBalances: []}> {
const network = this.config.network
if (isEvmBasedNetwork(network)) {
const rpc = Utils.getRpc<EvmRpc>(this.id, network)
const result = await Promise.all(
addresses.map((a, i) => rpc.rawRpcCall(Utils.prepareRpcCall('eth_getBalance', [a, 'pending'], i))),
)
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
return result.map((e) => new BigNumber(e.result).dividedBy(10 ** Constant.DECIMALS[network]).toString())
switch (true) {
case [Network.TRON, Network.TRON_SHASTA].includes(network):
if (addresses.length !== 1) {
throw new Error(`UTXO based networks like ${network} support only one address per call.`)
}
return this.connector
.get<{
balance: number,
createTime: number
trc10: [{
key: string,
value: number,
}]
trc20: {[key: string]: string}
freeNetLimit: number,
bandwidth: number,
}>({
path: `tron/account/${addresses[0]}`,
})
.then(async (r) =>
{
return Object.create({
nativeBalance: r.balance.toString(),
tokenBalances: await this.processTRC20TokenBalanceDetails(r.trc20),
})
})
}
if ([Network.SOLANA, Network.SOLANA_DEVNET].includes(network)) {
const rpc = Utils.getRpc<GenericRpc>(this.id, network)
return rpc
.rawBatchRpcCall(
addresses.map((a, i) => Utils.prepareRpcCall('getBalance', [a, { commitment: 'processed' }], i)),
)
.then((r) =>
r.map((e) => new BigNumber(e.result.value).dividedBy(10 ** Constant.DECIMALS[network]).toString()),
)
} else if ([Network.XRP, Network.XRP_TESTNET].includes(network)) {
if (addresses.length !== 1) {
throw new Error(`UTXO based networks like ${network} support only one address per call.`)
}
const rpc = Utils.getRpc<GenericRpc>(this.id, network)
return rpc
.rawRpcCall(
throw new Error(`Unsupported network ${network} for now.`)
}

private async getNativeBalance(addresses: string[]): Promise<string[]> {
const network = this.config.network
switch (true) {
case isEvmBasedNetwork(network):
return Promise.all(
addresses.map((a, i) => Utils.getRpc<EvmRpc>(this.id, this.config).rawRpcCall(Utils.prepareRpcCall('eth_getBalance', [a, 'pending'], i))),
).then(r => r.map((e) =>
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
new BigNumber(e.result).dividedBy(10 ** Constant.DECIMALS[network]).toString()))
case [Network.SOLANA, Network.SOLANA_DEVNET].includes(network):
return Utils.getRpc<GenericRpc>(this.id, this.config)
.rawBatchRpcCall(
addresses.map((a, i) => Utils.prepareRpcCall('getBalance', [a, { commitment: 'processed' }], i)),
)
.then((r) =>
r.map((e) => new BigNumber(e.result.value).dividedBy(10 ** Constant.DECIMALS[network]).toString()),
)
case [Network.XRP, Network.XRP_TESTNET].includes(network):
if (addresses.length !== 1) {
throw new Error(`UTXO based networks like ${network} support only one address per call.`)
}
return Utils.getRpc<GenericRpc>(this.id, this.config).rawRpcCall(
Utils.prepareRpcCall('account_info', [
{
account: addresses[0],
ledger_index: 'current',
},
]),
)
.then((r) => [
new BigNumber(r.result.account_data?.Balance || 0)
.dividedBy(10 ** Constant.DECIMALS[network])
.toString(),
])
} else if (isDataApiUtxoEnabledNetwork(network)) {
if (addresses.length !== 1) {
throw new Error(`UTXO based networks like ${network} support only one address per call.`)
}
return this.connector
.get<Array<{ value: number }>>({
path: 'data/utxos',
params: {
chain: network,
address: addresses[0],
totalValue: 200000000000,
},
})
.then((r) => [r.reduce((acc, val) => acc + val.value, 0).toString()])
.then((r) => [
new BigNumber(r.result.account_data?.Balance || 0)
.dividedBy(10 ** Constant.DECIMALS[network])
.toString(),
])
case isDataApiUtxoEnabledNetwork(network):
if (addresses.length !== 1) {
throw new Error(`UTXO based networks like ${network} support only one address per call.`)
}
return this.connector
.get<Array<{ value: number }>>({
path: 'data/utxos',
params: {
chain: network,
address: addresses[0],
totalValue: 200000000000,
},
})
.then((r) => [r.reduce((acc, val) => acc + val.value, 0).toString()])
case [Network.TRON, Network.TRON_SHASTA].includes(network):
throw new Error(`Use 'getFullBalance' method for network ${network}.`)
}
// TODO: implement for other networks - TRON, XLM etc etc
// TODO: implement for other networks - XLM etc etc
throw new Error(`Unsupported network ${network} for now.`)
}
}
Loading

0 comments on commit c655c9b

Please sign in to comment.