Skip to content

Commit 4f7231b

Browse files
authored
ALL-3155 Add BNB support (#1003)
1 parent 81b313d commit 4f7231b

File tree

10 files changed

+328
-4
lines changed

10 files changed

+328
-4
lines changed

β€ŽCHANGELOG.mdβ€Ž

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## [4.1.17] - 2023.10.26
2+
### Added
3+
- Added RPC support for the BNB network. Users can now make RPC calls to these network using the `Network.BNB` network.
4+
15
## [4.1.16] - 2023.10.24
26
### Added
37
- Added Beacon chain v1 support for the Ethereum

β€Žpackage.jsonβ€Ž

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@tatumio/tatum",
3-
"version": "4.1.16",
3+
"version": "4.1.17",
44
"description": "Tatum JS SDK",
55
"author": "Tatum",
66
"repository": "https://github.com/tatumio/tatum-js",

β€Žsrc/dto/Network.tsβ€Ž

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ export enum Network {
88
AVALANCHE_P = 'avax-p-mainnet',
99
AVALANCHE_X = 'avax-x-mainnet',
1010
BINANCE_SMART_CHAIN = 'bsc-mainnet',
11+
BNB = 'bnb-beacon-chain-mainnet',
1112
BITCOIN = 'bitcoin-mainnet',
1213
BITCOIN_CASH = 'bitcoin-cash-mainnet',
1314
CARDANO = 'cardano-mainnet',
@@ -235,6 +236,7 @@ export const EOS_LOAD_BALANCER_NETWORKS = [Network.EOS]
235236
export const XRP_LOAD_BALANCER_NETWORKS = [Network.XRP, Network.XRP_TESTNET]
236237
export const NATIVE_EVM_LOAD_BALANCER_NETWORKS = [Network.KLAYTN, Network.KLAYTN_BAOBAB]
237238
export const SOLANA_NETWORKS = [Network.SOLANA, Network.SOLANA_DEVNET]
239+
export const BNB_LOAD_BALANCER_NETWORKS = [Network.BNB]
238240

239241
export const LOAD_BALANCER_NETWORKS = [
240242
...UTXO_LOAD_BALANCER_NETWORKS,
@@ -244,6 +246,7 @@ export const LOAD_BALANCER_NETWORKS = [
244246
...XRP_LOAD_BALANCER_NETWORKS,
245247
...NATIVE_EVM_LOAD_BALANCER_NETWORKS,
246248
...SOLANA_NETWORKS,
249+
...BNB_LOAD_BALANCER_NETWORKS,
247250
]
248251

249252
export const EVM_ARCHIVE_NON_ARCHIVE_LOAD_BALANCER_NETWORKS = [
@@ -291,7 +294,6 @@ export const isEosNetwork = (network: Network) => EOS_NETWORKS.includes(network)
291294

292295
export const isLoadBalancerNetwork = (network: Network) => LOAD_BALANCER_NETWORKS.includes(network)
293296

294-
295297
export const isEvmLoadBalancerNetwork = (network: Network) => EVM_LOAD_BALANCER_NETWORKS.includes(network)
296298

297299
export const isEvmArchiveNonArchiveLoadBalancerNetwork = (network: Network) =>
@@ -309,6 +311,8 @@ export const isXrpLoadBalancerNetwork = (network: Network) => XRP_LOAD_BALANCER_
309311
export const isNativeEvmLoadBalancerNetwork = (network: Network) =>
310312
NATIVE_EVM_LOAD_BALANCER_NETWORKS.includes(network)
311313

314+
export const isBnbLoadBalancerNetwork = (network: Network) => BNB_LOAD_BALANCER_NETWORKS.includes(network)
315+
312316
export const isSameGetBlockNetwork = (network: Network) =>
313317
isUtxoBasedNetwork(network) ||
314318
isEvmBasedNetwork(network) ||

β€Žsrc/dto/rpc/BnbRpcSuite.tsβ€Ž

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/* eslint-disable @typescript-eslint/no-explicit-any */
2+
import { JsonRpcResponse } from '../JsonRpcResponse.dto'
3+
4+
export interface Height {
5+
height: string
6+
}
7+
8+
export interface AbciQuery {
9+
path: string,
10+
data: string
11+
height?: string
12+
prove?: boolean
13+
}
14+
15+
export interface Validators {
16+
height?: string
17+
page?: string
18+
perPage?: string
19+
}
20+
21+
export interface Tx { hash: string, prove?: boolean }
22+
23+
export interface TxSearch { query: string, prove?: boolean, page?: string }
24+
25+
export interface Broadcast { tx: string }
26+
27+
export interface Blockchain { minHeight?: string, maxHeight?: string }
28+
29+
export interface UnconfirmedTxs { limit?: string }
30+
31+
export interface BnbRpcInterface {
32+
status(): Promise<JsonRpcResponse<any>>
33+
abciInfo(): Promise<JsonRpcResponse<any>>
34+
abciQuery(params: AbciQuery): Promise<JsonRpcResponse<any>>
35+
block(params?: Height): Promise<JsonRpcResponse<any>>
36+
blockResult(params?: Height): Promise<JsonRpcResponse<any>>
37+
blockchain(params?: Blockchain): Promise<JsonRpcResponse<any>>
38+
commit(params?: Height): Promise<JsonRpcResponse<any>>
39+
tx(params: Tx): Promise<JsonRpcResponse<any>>
40+
broadcastTxAsync(params: Broadcast): Promise<JsonRpcResponse<any>>
41+
broadcastTxCommit(params: Broadcast): Promise<JsonRpcResponse<any>>
42+
broadcastTxSync(params: Broadcast): Promise<JsonRpcResponse<any>>
43+
txSearch(params: TxSearch): Promise<JsonRpcResponse<any>>
44+
validators(params?: Validators): Promise<JsonRpcResponse<any>>
45+
unconfirmedTxs(params: UnconfirmedTxs): Promise<JsonRpcResponse<any>>
46+
genesis(): Promise<JsonRpcResponse<any>>
47+
health(): Promise<JsonRpcResponse<any>>
48+
netInfo(): Promise<JsonRpcResponse<any>>
49+
numUnconfirmedTxs(): Promise<JsonRpcResponse<any>>
50+
}
51+
52+
export interface JsonBnbRpcCall {
53+
id: number | string
54+
jsonrpc: string
55+
method: string
56+
params?: Params
57+
}
58+
59+
export interface Params {
60+
[key: string]: unknown;
61+
}
62+
63+
export interface AbstractBnbRpcInterface {
64+
rawRpcCall(body: JsonBnbRpcCall): Promise<JsonRpcResponse<any>>
65+
destroy(): void
66+
getRpcNodeUrl(): string
67+
}
68+
69+
export interface BnbRpcSuite extends BnbRpcInterface, AbstractBnbRpcInterface {}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import * as process from 'process'
2+
import { Bnb, Network, TatumSDK } from '../../../service'
3+
import { e2eUtil } from '../../e2e.util'
4+
5+
const getBnbRpc = async () =>
6+
await TatumSDK.init<Bnb>({
7+
network: Network.BNB,
8+
apiKey: {
9+
v4: process.env.V4_API_KEY_MAINNET
10+
},
11+
verbose: e2eUtil.isVerbose,
12+
})
13+
14+
// Testnet is not available
15+
describe('Bnb', () => {
16+
describe('mainnet', () => {
17+
it('block', async () => {
18+
const tatum = await getBnbRpc()
19+
const { result } = await tatum.rpc.block()
20+
await tatum.destroy()
21+
expect(result).toBeDefined()
22+
})
23+
24+
it('abciInfo', async () => {
25+
const tatum = await getBnbRpc()
26+
const { result } = await tatum.rpc.abciInfo()
27+
await tatum.destroy()
28+
expect(result).toBeDefined()
29+
})
30+
31+
it('blockchain', async () => {
32+
const tatum = await getBnbRpc()
33+
const { result } = await tatum.rpc.blockchain()
34+
await tatum.destroy()
35+
expect(result).toBeDefined()
36+
})
37+
38+
it('health', async () => {
39+
const tatum = await getBnbRpc()
40+
const { result } = await tatum.rpc.health()
41+
await tatum.destroy()
42+
expect(result).toBeDefined()
43+
})
44+
45+
it('genesis', async () => {
46+
const tatum = await getBnbRpc()
47+
const { result } = await tatum.rpc.genesis()
48+
await tatum.destroy()
49+
expect(result).toBeDefined()
50+
})
51+
52+
it('validators', async () => {
53+
const tatum = await getBnbRpc()
54+
const { result } = await tatum.rpc.validators()
55+
await tatum.destroy()
56+
expect(result).toBeDefined()
57+
})
58+
59+
it('unconfirmedTxs', async () => {
60+
const tatum = await getBnbRpc()
61+
const { result } = await tatum.rpc.unconfirmedTxs({ limit: '1' })
62+
await tatum.destroy()
63+
expect(result).toBeDefined()
64+
})
65+
66+
it('raw rpc call', async () => {
67+
const tatum = await getBnbRpc()
68+
const { result } = await tatum.rpc.rawRpcCall({ method: 'block', id: 1, jsonrpc: '2.0', params: {} })
69+
await tatum.destroy()
70+
expect(result).toBeDefined()
71+
})
72+
})
73+
})
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
/* eslint-disable @typescript-eslint/no-explicit-any */
2+
import { JsonRpcResponse } from '../../../dto'
3+
import { Height, AbciQuery, BnbRpcInterface, Blockchain, Tx, Broadcast, TxSearch } from '../../../dto/rpc/BnbRpcSuite'
4+
import { PostI } from '../../../dto/PostI'
5+
import { Utils } from '../../../util'
6+
7+
export abstract class AbstractBnbRpc implements BnbRpcInterface {
8+
protected abstract post<T>(post: PostI): Promise<T>
9+
10+
sendRpcCall<T, U>(method: string, params?: T): Promise<U> {
11+
const body = {
12+
id: 1,
13+
jsonrpc: '2.0',
14+
method,
15+
params: params ? Utils.convertObjCamelToSnake(params) : {},
16+
}
17+
return this.post({ body, path: '' })
18+
}
19+
20+
status(): Promise<JsonRpcResponse<any>> {
21+
return this.sendRpcCall('status')
22+
}
23+
24+
abciInfo(): Promise<JsonRpcResponse<any>> {
25+
return this.sendRpcCall('abci_info')
26+
}
27+
28+
abciQuery(params: AbciQuery): Promise<JsonRpcResponse<any>> {
29+
return this.sendRpcCall('abci_query', params)
30+
}
31+
32+
block(params?: Height): Promise<JsonRpcResponse<any>> {
33+
return this.sendRpcCall('block', params)
34+
}
35+
36+
blockResult(params?: Height): Promise<JsonRpcResponse<any>> {
37+
return this.sendRpcCall('block_result', params)
38+
}
39+
40+
blockchain(params?: Blockchain): Promise<JsonRpcResponse<any>> {
41+
return this.sendRpcCall('blockchain', params)
42+
}
43+
44+
commit(params?: Height): Promise<JsonRpcResponse<any>> {
45+
return this.sendRpcCall('commit', params)
46+
}
47+
48+
tx(params: Tx): Promise<JsonRpcResponse<any>> {
49+
return this.sendRpcCall('tx', params)
50+
}
51+
52+
broadcastTxAsync(params: Broadcast): Promise<JsonRpcResponse<any>> {
53+
return this.sendRpcCall('broadcast_tx_async', params)
54+
}
55+
56+
broadcastTxCommit(params: Broadcast): Promise<JsonRpcResponse<any>> {
57+
return this.sendRpcCall('broadcast_tx_commit', params)
58+
}
59+
60+
broadcastTxSync(params: Broadcast): Promise<JsonRpcResponse<any>> {
61+
return this.sendRpcCall('broadcast_tx_sync', params)
62+
}
63+
64+
txSearch(params: TxSearch): Promise<JsonRpcResponse<any>> {
65+
return this.sendRpcCall('tx_search', params)
66+
}
67+
68+
validators(params: Height): Promise<JsonRpcResponse<any>> {
69+
return this.sendRpcCall('validators', params)
70+
}
71+
72+
unconfirmedTxs(params: { limit: string }): Promise<JsonRpcResponse<any>> {
73+
return this.sendRpcCall('unconfirmed_txs', params)
74+
}
75+
76+
genesis(): Promise<JsonRpcResponse<any>> {
77+
return this.sendRpcCall('genesis')
78+
}
79+
80+
health(): Promise<JsonRpcResponse<any>> {
81+
return this.sendRpcCall('health')
82+
}
83+
84+
netInfo(): Promise<JsonRpcResponse<any>> {
85+
return this.sendRpcCall('net_info')
86+
}
87+
88+
numUnconfirmedTxs(): Promise<JsonRpcResponse<any>> {
89+
return this.sendRpcCall('num_unconfirmed_txs')
90+
}
91+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/* eslint-disable @typescript-eslint/no-explicit-any */
2+
import { Container, Service } from 'typedi'
3+
import { LoadBalancer } from '../generic'
4+
import { AbstractBnbRpc } from './AbstractBnbRpc'
5+
import { BnbRpcSuite, JsonBnbRpcCall } from '../../../dto/rpc/BnbRpcSuite'
6+
import { JsonRpcResponse } from '../../../dto'
7+
import { PostI } from '../../../dto/PostI'
8+
9+
@Service({
10+
factory: (data: { id: string }) => {
11+
return new BnbLoadBalancerRpc(data.id)
12+
},
13+
transient: true,
14+
})
15+
export class BnbLoadBalancerRpc extends AbstractBnbRpc implements BnbRpcSuite {
16+
protected readonly loadBalancer: LoadBalancer
17+
18+
constructor(id: string) {
19+
super()
20+
this.loadBalancer = Container.of(id).get(LoadBalancer)
21+
}
22+
23+
public destroy() {
24+
this.loadBalancer.destroy()
25+
}
26+
27+
getRpcNodeUrl(): string {
28+
return this.loadBalancer.getActiveNormalUrlWithFallback().url
29+
}
30+
31+
rawRpcCall(body: JsonBnbRpcCall): Promise<JsonRpcResponse<any>> {
32+
return this.loadBalancer.post({ body, path: '' })
33+
}
34+
35+
protected post<T>(post: PostI): Promise<T> {
36+
return this.loadBalancer.post(post)
37+
}
38+
}

β€Žsrc/service/tatum/tatum.other.tsβ€Ž

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { Notification } from '../notification'
1010
import { Rates } from '../rate'
1111
import { Token } from '../token'
1212
import { TatumSdkChain } from './tatum'
13+
import { BnbRpcSuite } from '../../dto/rpc/BnbRpcSuite'
1314

1415
export abstract class BaseOther extends TatumSdkChain {
1516
ipfs: Ipfs
@@ -22,6 +23,19 @@ export abstract class BaseOther extends TatumSdkChain {
2223
}
2324
}
2425

26+
export class Bnb extends BaseOther {
27+
rpc: BnbRpcSuite
28+
notification: Notification
29+
address: Address
30+
31+
constructor(id: string) {
32+
super(id)
33+
this.rpc = Utils.getRpc<BnbRpcSuite>(id, Container.of(id).get(CONFIG))
34+
this.notification = Container.of(id).get(Notification)
35+
this.address = Container.of(id).get(Address)
36+
}
37+
}
38+
2539
export class Xrp extends BaseOther {
2640
rpc: XrpRpcInterface
2741
notification: Notification

β€Žsrc/util/constant.tsβ€Ž

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,7 @@ export const Constant = {
163163
[Network.HAQQ]: 18,
164164
[Network.HAQQ_TESTNET]: 18,
165165
[Network.CHILIZ]: 18,
166+
[Network.BNB]: 18,
166167
},
167168
CURRENCY_NAMES: {
168169
[Network.BITCOIN]: 'BTC',
@@ -256,6 +257,7 @@ export const Constant = {
256257
[Network.HAQQ]: 'HAQQ',
257258
[Network.HAQQ_TESTNET]: 'HAQQ',
258259
[Network.CHILIZ]: 'CHILIZ',
260+
[Network.BNB]: 'BNB',
259261
},
260262
RPC: {
261263
MAINNETS: [

0 commit comments

Comments
Β (0)