@cityofzion/bs-ethereum 1.1.0 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/BSEthereum.d.ts +2 -2
- package/dist/BSEthereum.js +12 -7
- package/dist/BitqueryBDSEthereum.d.ts +2 -3
- package/dist/BitqueryBDSEthereum.js +34 -50
- package/dist/BitqueryEDSEthereum.d.ts +2 -3
- package/dist/BitqueryEDSEthereum.js +27 -27
- package/dist/GhostMarketNDSEthereum.d.ts +1 -1
- package/dist/GhostMarketNDSEthereum.js +23 -11
- package/dist/LedgerServiceEthereum.d.ts +4 -2
- package/dist/LedgerServiceEthereum.js +13 -5
- package/dist/RpcBDSEthereum.d.ts +1 -1
- package/dist/RpcBDSEthereum.js +21 -7
- package/dist/constants.d.ts +2 -2
- package/dist/constants.js +3 -3
- package/package.json +6 -5
- package/.eslintignore +0 -13
- package/.eslintrc.cjs +0 -22
- package/.rush/temp/operation/build/all.log +0 -1
- package/.rush/temp/operation/build/state.json +0 -3
- package/.rush/temp/package-deps_build.json +0 -30
- package/.rush/temp/shrinkwrap-deps.json +0 -531
- package/CHANGELOG.json +0 -126
- package/CHANGELOG.md +0 -68
- package/bs-ethereum.build.log +0 -1
- package/dist/graphql.d.ts +0 -124
- package/dist/graphql.js +0 -160
- package/jest.config.ts +0 -13
- package/jest.setup.ts +0 -1
- package/src/BSEthereum.ts +0 -208
- package/src/BitqueryBDSEthereum.ts +0 -231
- package/src/BitqueryEDSEthereum.ts +0 -67
- package/src/GhostMarketNDSEthereum.ts +0 -125
- package/src/LedgerServiceEthereum.ts +0 -44
- package/src/RpcBDSEthereum.ts +0 -88
- package/src/__tests__/BSEthereum.spec.ts +0 -172
- package/src/__tests__/BitqueryBDSEthereum.spec.ts +0 -106
- package/src/__tests__/BitqueryEDSEthereum.spec.ts +0 -55
- package/src/__tests__/GhostMarketNDSEthereum.spec.ts +0 -49
- package/src/__tests__/RpcBDSEthereum.spec.ts +0 -62
- package/src/assets/tokens/common.json +0 -8
- package/src/constants.ts +0 -36
- package/src/graphql.ts +0 -288
- package/src/index.ts +0 -6
- package/tsconfig.build.json +0 -4
- package/tsconfig.json +0 -15
|
@@ -1,231 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
BalanceResponse,
|
|
3
|
-
ContractResponse,
|
|
4
|
-
NetworkType,
|
|
5
|
-
Token,
|
|
6
|
-
TransactionsByAddressParams,
|
|
7
|
-
TransactionsByAddressResponse,
|
|
8
|
-
TransactionResponse,
|
|
9
|
-
TransactionTransferAsset,
|
|
10
|
-
TransactionTransferNft,
|
|
11
|
-
Network,
|
|
12
|
-
} from '@cityofzion/blockchain-service'
|
|
13
|
-
import { Client, fetchExchange } from '@urql/core'
|
|
14
|
-
import fetch from 'node-fetch'
|
|
15
|
-
import { BITQUERY_NETWORK_BY_NETWORK_TYPE, BITQUERY_URL, NATIVE_ASSETS, TOKENS } from './constants'
|
|
16
|
-
import {
|
|
17
|
-
BitqueryTransaction,
|
|
18
|
-
bitqueryGetBalanceQuery,
|
|
19
|
-
bitqueryGetTokenInfoQuery,
|
|
20
|
-
bitqueryGetTransactionQuery,
|
|
21
|
-
bitqueryGetTransactionsByAddressQuery,
|
|
22
|
-
} from './graphql'
|
|
23
|
-
import { RpcBDSEthereum } from './RpcBDSEthereum'
|
|
24
|
-
|
|
25
|
-
export class BitqueryBDSEthereum extends RpcBDSEthereum {
|
|
26
|
-
private readonly client: Client
|
|
27
|
-
private readonly networkType: Exclude<NetworkType, 'custom'>
|
|
28
|
-
|
|
29
|
-
maxTimeToConfirmTransactionInMs: number = 1000 * 60 * 8
|
|
30
|
-
|
|
31
|
-
constructor(network: Network, apiKey: string) {
|
|
32
|
-
super(network)
|
|
33
|
-
|
|
34
|
-
if (network.type === 'custom') throw new Error('Custom network not supported')
|
|
35
|
-
this.networkType = network.type
|
|
36
|
-
|
|
37
|
-
this.client = new Client({
|
|
38
|
-
url: BITQUERY_URL,
|
|
39
|
-
exchanges: [fetchExchange],
|
|
40
|
-
fetch,
|
|
41
|
-
fetchOptions: {
|
|
42
|
-
headers: {
|
|
43
|
-
'X-API-KEY': apiKey,
|
|
44
|
-
},
|
|
45
|
-
},
|
|
46
|
-
})
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
async getTransaction(hash: string): Promise<TransactionResponse> {
|
|
50
|
-
const result = await this.client
|
|
51
|
-
.query(bitqueryGetTransactionQuery, {
|
|
52
|
-
hash,
|
|
53
|
-
network: BITQUERY_NETWORK_BY_NETWORK_TYPE[this.networkType],
|
|
54
|
-
})
|
|
55
|
-
.toPromise()
|
|
56
|
-
if (result.error) throw new Error(result.error.message)
|
|
57
|
-
if (!result.data || !result.data.ethereum.transfers.length) throw new Error('Transaction not found')
|
|
58
|
-
|
|
59
|
-
const transfers = result.data.ethereum.transfers.map(this.parseTransactionTransfer)
|
|
60
|
-
|
|
61
|
-
const {
|
|
62
|
-
block: {
|
|
63
|
-
height,
|
|
64
|
-
timestamp: { unixtime },
|
|
65
|
-
},
|
|
66
|
-
transaction: { gasValue, hash: transactionHash },
|
|
67
|
-
} = result.data.ethereum.transfers[0]
|
|
68
|
-
|
|
69
|
-
return {
|
|
70
|
-
block: height,
|
|
71
|
-
time: unixtime,
|
|
72
|
-
hash: transactionHash,
|
|
73
|
-
fee: String(gasValue),
|
|
74
|
-
transfers,
|
|
75
|
-
notifications: [],
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
async getTransactionsByAddress({
|
|
80
|
-
address,
|
|
81
|
-
page = 1,
|
|
82
|
-
}: TransactionsByAddressParams): Promise<TransactionsByAddressResponse> {
|
|
83
|
-
const limit = 10
|
|
84
|
-
const offset = limit * (page - 1)
|
|
85
|
-
|
|
86
|
-
const result = await this.client
|
|
87
|
-
.query(bitqueryGetTransactionsByAddressQuery, {
|
|
88
|
-
address,
|
|
89
|
-
limit,
|
|
90
|
-
offset,
|
|
91
|
-
network: BITQUERY_NETWORK_BY_NETWORK_TYPE[this.networkType],
|
|
92
|
-
})
|
|
93
|
-
.toPromise()
|
|
94
|
-
|
|
95
|
-
if (result.error) throw new Error(result.error.message)
|
|
96
|
-
if (!result.data) throw new Error('Address does not have transactions')
|
|
97
|
-
|
|
98
|
-
const totalCount =
|
|
99
|
-
(result.data.ethereum.sentCount[0].count ?? 0) + (result.data.ethereum.receiverCount[0].count ?? 0)
|
|
100
|
-
const mixedTransfers = [...(result?.data?.ethereum?.sent ?? []), ...(result?.data?.ethereum?.received ?? [])]
|
|
101
|
-
|
|
102
|
-
const transactions = new Map<string, TransactionResponse>()
|
|
103
|
-
|
|
104
|
-
mixedTransfers.forEach(transfer => {
|
|
105
|
-
const transactionTransfer = this.parseTransactionTransfer(transfer)
|
|
106
|
-
|
|
107
|
-
const existingTransaction = transactions.get(transfer.transaction.hash)
|
|
108
|
-
if (existingTransaction) {
|
|
109
|
-
existingTransaction.transfers.push(transactionTransfer)
|
|
110
|
-
return
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
transactions.set(transfer.transaction.hash, {
|
|
114
|
-
block: transfer.block.height,
|
|
115
|
-
hash: transfer.transaction.hash,
|
|
116
|
-
time: transfer.block.timestamp.unixtime,
|
|
117
|
-
fee: String(transfer.transaction.gasValue),
|
|
118
|
-
transfers: [transactionTransfer],
|
|
119
|
-
notifications: [],
|
|
120
|
-
})
|
|
121
|
-
})
|
|
122
|
-
|
|
123
|
-
return {
|
|
124
|
-
totalCount,
|
|
125
|
-
limit: limit * 2,
|
|
126
|
-
transactions: Array.from(transactions.values()),
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
async getContract(): Promise<ContractResponse> {
|
|
131
|
-
throw new Error("Bitquery doesn't support contract info")
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
async getTokenInfo(hash: string): Promise<Token> {
|
|
135
|
-
const localToken = TOKENS[this.networkType].find(token => token.hash === hash)
|
|
136
|
-
if (localToken) return localToken
|
|
137
|
-
|
|
138
|
-
const result = await this.client
|
|
139
|
-
.query(bitqueryGetTokenInfoQuery, {
|
|
140
|
-
hash,
|
|
141
|
-
network: BITQUERY_NETWORK_BY_NETWORK_TYPE[this.networkType],
|
|
142
|
-
})
|
|
143
|
-
.toPromise()
|
|
144
|
-
|
|
145
|
-
if (result.error) throw new Error(result.error.message)
|
|
146
|
-
if (!result.data || result.data.ethereum.smartContractCalls.length <= 0) throw new Error('Token not found')
|
|
147
|
-
|
|
148
|
-
const {
|
|
149
|
-
address: { address },
|
|
150
|
-
currency: { decimals, name, symbol, tokenType },
|
|
151
|
-
} = result.data.ethereum.smartContractCalls[0].smartContract
|
|
152
|
-
|
|
153
|
-
if (tokenType !== 'ERC20') throw new Error('Token is not ERC20')
|
|
154
|
-
|
|
155
|
-
return {
|
|
156
|
-
hash: address,
|
|
157
|
-
name,
|
|
158
|
-
symbol,
|
|
159
|
-
decimals,
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
async getBalance(address: string): Promise<BalanceResponse[]> {
|
|
164
|
-
const result = await this.client
|
|
165
|
-
.query(bitqueryGetBalanceQuery, {
|
|
166
|
-
address,
|
|
167
|
-
network: BITQUERY_NETWORK_BY_NETWORK_TYPE[this.networkType],
|
|
168
|
-
})
|
|
169
|
-
.toPromise()
|
|
170
|
-
|
|
171
|
-
if (result.error) throw new Error(result.error.message)
|
|
172
|
-
const data = result.data?.ethereum.address[0].balances ?? []
|
|
173
|
-
const ethBalance = result.data?.ethereum.address[0].balance ?? 0
|
|
174
|
-
const ethToken = NATIVE_ASSETS.find(asset => asset.symbol === 'ETH')!
|
|
175
|
-
|
|
176
|
-
const balances: BalanceResponse[] = [
|
|
177
|
-
{
|
|
178
|
-
amount: ethBalance.toString(),
|
|
179
|
-
token: ethToken,
|
|
180
|
-
},
|
|
181
|
-
]
|
|
182
|
-
|
|
183
|
-
data.forEach(({ value, currency: { address, decimals, name, symbol } }) => {
|
|
184
|
-
if (value < 0 || address === ethToken.hash) return
|
|
185
|
-
|
|
186
|
-
balances.push({
|
|
187
|
-
amount: value.toString(),
|
|
188
|
-
token: {
|
|
189
|
-
hash: address,
|
|
190
|
-
symbol,
|
|
191
|
-
name,
|
|
192
|
-
decimals,
|
|
193
|
-
},
|
|
194
|
-
})
|
|
195
|
-
})
|
|
196
|
-
|
|
197
|
-
return balances
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
private parseTransactionTransfer({
|
|
201
|
-
amount,
|
|
202
|
-
currency: { tokenType, address, decimals, name, symbol },
|
|
203
|
-
entityId,
|
|
204
|
-
sender,
|
|
205
|
-
receiver,
|
|
206
|
-
}: BitqueryTransaction): TransactionTransferAsset | TransactionTransferNft {
|
|
207
|
-
if (tokenType === 'ERC721') {
|
|
208
|
-
return {
|
|
209
|
-
from: sender.address,
|
|
210
|
-
to: receiver.address,
|
|
211
|
-
tokenId: entityId,
|
|
212
|
-
contractHash: address,
|
|
213
|
-
type: 'nft',
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
return {
|
|
218
|
-
from: sender.address,
|
|
219
|
-
to: receiver.address,
|
|
220
|
-
contractHash: address,
|
|
221
|
-
amount: amount.toString(),
|
|
222
|
-
token: {
|
|
223
|
-
decimals: decimals,
|
|
224
|
-
hash: address,
|
|
225
|
-
name: name,
|
|
226
|
-
symbol: symbol,
|
|
227
|
-
},
|
|
228
|
-
type: 'token',
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
}
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
import { Currency, ExchangeDataService, NetworkType, TokenPricesResponse } from '@cityofzion/blockchain-service'
|
|
2
|
-
import { Client, fetchExchange } from '@urql/core'
|
|
3
|
-
import fetch from 'node-fetch'
|
|
4
|
-
import { BITQUERY_URL } from './constants'
|
|
5
|
-
import dayjs from 'dayjs'
|
|
6
|
-
import utc from 'dayjs/plugin/utc'
|
|
7
|
-
import { bitqueryGetPricesQuery } from './graphql'
|
|
8
|
-
|
|
9
|
-
dayjs.extend(utc)
|
|
10
|
-
export class BitqueryEDSEthereum implements ExchangeDataService {
|
|
11
|
-
private readonly client: Client
|
|
12
|
-
private readonly networkType: NetworkType
|
|
13
|
-
|
|
14
|
-
constructor(networkType: NetworkType, apiKey: string) {
|
|
15
|
-
this.networkType = networkType
|
|
16
|
-
|
|
17
|
-
this.client = new Client({
|
|
18
|
-
url: BITQUERY_URL,
|
|
19
|
-
exchanges: [fetchExchange],
|
|
20
|
-
fetch,
|
|
21
|
-
fetchOptions: {
|
|
22
|
-
headers: {
|
|
23
|
-
'X-API-KEY': apiKey,
|
|
24
|
-
},
|
|
25
|
-
},
|
|
26
|
-
})
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
async getTokenPrices(currency: Currency): Promise<TokenPricesResponse[]> {
|
|
30
|
-
if (this.networkType !== 'mainnet') throw new Error('Exchange is only available on mainnet')
|
|
31
|
-
|
|
32
|
-
const twoDaysAgo = dayjs.utc().subtract(2, 'day').startOf('date').toISOString()
|
|
33
|
-
|
|
34
|
-
const result = await this.client
|
|
35
|
-
.query(bitqueryGetPricesQuery, { after: twoDaysAgo, network: 'ethereum' })
|
|
36
|
-
.toPromise()
|
|
37
|
-
if (result.error) {
|
|
38
|
-
throw new Error(result.error.message)
|
|
39
|
-
}
|
|
40
|
-
if (!result.data) {
|
|
41
|
-
throw new Error('There is no price data')
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
let currencyRatio: number = 1
|
|
45
|
-
if (currency !== 'USD') {
|
|
46
|
-
currencyRatio = await this.getCurrencyRatio(currency)
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
const prices = result.data.ethereum.dexTrades.map(
|
|
50
|
-
(trade): TokenPricesResponse => ({
|
|
51
|
-
symbol: trade.baseCurrency.symbol,
|
|
52
|
-
price: trade.quotePrice * currencyRatio,
|
|
53
|
-
hash: trade.baseCurrency.address,
|
|
54
|
-
})
|
|
55
|
-
)
|
|
56
|
-
|
|
57
|
-
return prices
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
private async getCurrencyRatio(currency: Currency): Promise<number> {
|
|
61
|
-
const request = await fetch(`https://api.flamingo.finance/fiat/exchange-rate?pair=USD_${currency}`, {
|
|
62
|
-
method: 'GET',
|
|
63
|
-
})
|
|
64
|
-
const data = await request.json()
|
|
65
|
-
return data
|
|
66
|
-
}
|
|
67
|
-
}
|
|
@@ -1,125 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
NftResponse,
|
|
3
|
-
NftsResponse,
|
|
4
|
-
NetworkType,
|
|
5
|
-
NftDataService,
|
|
6
|
-
GetNftParam,
|
|
7
|
-
GetNftsByAddressParams,
|
|
8
|
-
} from '@cityofzion/blockchain-service'
|
|
9
|
-
import qs from 'query-string'
|
|
10
|
-
|
|
11
|
-
import { GHOSTMARKET_CHAIN_BY_NETWORK_TYPE, GHOSTMARKET_URL_BY_NETWORK_TYPE } from './constants'
|
|
12
|
-
import fetch from 'node-fetch'
|
|
13
|
-
|
|
14
|
-
type GhostMarketNFT = {
|
|
15
|
-
tokenId: string
|
|
16
|
-
contract: {
|
|
17
|
-
chain?: string
|
|
18
|
-
hash: string
|
|
19
|
-
symbol: string
|
|
20
|
-
}
|
|
21
|
-
creator: {
|
|
22
|
-
address: string
|
|
23
|
-
offchainName?: string
|
|
24
|
-
}
|
|
25
|
-
apiUrl?: string
|
|
26
|
-
ownerships: {
|
|
27
|
-
owner: {
|
|
28
|
-
address?: string
|
|
29
|
-
}
|
|
30
|
-
}[]
|
|
31
|
-
collection: {
|
|
32
|
-
name?: string
|
|
33
|
-
logoUrl?: string
|
|
34
|
-
}
|
|
35
|
-
metadata: {
|
|
36
|
-
description: string
|
|
37
|
-
mediaType: string
|
|
38
|
-
mediaUri: string
|
|
39
|
-
mintDate: number
|
|
40
|
-
mintNumber: number
|
|
41
|
-
name: string
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
type GhostMarketAssets = {
|
|
46
|
-
assets: GhostMarketNFT[]
|
|
47
|
-
next: string
|
|
48
|
-
}
|
|
49
|
-
export class GhostMarketNDSEthereum implements NftDataService {
|
|
50
|
-
private networkType: NetworkType
|
|
51
|
-
|
|
52
|
-
constructor(networkType: NetworkType) {
|
|
53
|
-
this.networkType = networkType
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
async getNftsByAddress({ address, size = 18, cursor }: GetNftsByAddressParams): Promise<NftsResponse> {
|
|
57
|
-
const url = this.getUrlWithParams({
|
|
58
|
-
size,
|
|
59
|
-
owners: [address],
|
|
60
|
-
cursor: cursor,
|
|
61
|
-
})
|
|
62
|
-
|
|
63
|
-
const request = await fetch(url, { method: 'GET' })
|
|
64
|
-
const data = (await request.json()) as GhostMarketAssets
|
|
65
|
-
const nfts = data.assets ?? []
|
|
66
|
-
|
|
67
|
-
return { nextCursor: data.next, items: nfts.map(this.parse.bind(this)) }
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
async getNft({ contractHash, tokenId }: GetNftParam): Promise<NftResponse> {
|
|
71
|
-
const url = this.getUrlWithParams({
|
|
72
|
-
contract: contractHash,
|
|
73
|
-
tokenIds: [tokenId],
|
|
74
|
-
})
|
|
75
|
-
|
|
76
|
-
const request = await fetch(url, { method: 'GET' })
|
|
77
|
-
const data = (await request.json()) as GhostMarketAssets
|
|
78
|
-
|
|
79
|
-
return this.parse(data.assets[0])
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
private treatGhostMarketImage(srcImage?: string) {
|
|
83
|
-
if (!srcImage) {
|
|
84
|
-
return
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
if (srcImage.startsWith('ipfs://')) {
|
|
88
|
-
const [, imageId] = srcImage.split('://')
|
|
89
|
-
|
|
90
|
-
return `https://ghostmarket.mypinata.cloud/ipfs/${imageId}`
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
return srcImage
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
private getUrlWithParams(params: any) {
|
|
97
|
-
const parameters = qs.stringify(
|
|
98
|
-
{
|
|
99
|
-
chain: GHOSTMARKET_CHAIN_BY_NETWORK_TYPE[this.networkType],
|
|
100
|
-
...params,
|
|
101
|
-
},
|
|
102
|
-
{ arrayFormat: 'bracket' }
|
|
103
|
-
)
|
|
104
|
-
return `${GHOSTMARKET_URL_BY_NETWORK_TYPE[this.networkType]}/assets?${parameters}`
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
private parse(data: GhostMarketNFT) {
|
|
108
|
-
const nftResponse: NftResponse = {
|
|
109
|
-
collectionImage: this.treatGhostMarketImage(data.collection?.logoUrl),
|
|
110
|
-
id: data.tokenId,
|
|
111
|
-
contractHash: data.contract.hash,
|
|
112
|
-
symbol: data.contract.symbol,
|
|
113
|
-
collectionName: data.collection?.name,
|
|
114
|
-
image: this.treatGhostMarketImage(data.metadata.mediaUri),
|
|
115
|
-
isSVG: String(data.metadata.mediaType).includes('svg+xml'),
|
|
116
|
-
name: data.metadata.name,
|
|
117
|
-
creator: {
|
|
118
|
-
address: data.creator.address,
|
|
119
|
-
name: data.creator.offchainName,
|
|
120
|
-
},
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
return nftResponse
|
|
124
|
-
}
|
|
125
|
-
}
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import { LedgerService } from '@cityofzion/blockchain-service'
|
|
2
|
-
import Transport from '@ledgerhq/hw-transport'
|
|
3
|
-
import LedgerEthereumApp, { ledgerService as LedgerEthereumAppService } from '@ledgerhq/hw-app-eth'
|
|
4
|
-
import { ethers } from 'ethers'
|
|
5
|
-
|
|
6
|
-
export class LedgerServiceEthereum implements LedgerService {
|
|
7
|
-
private readonly defaultPath = "44'/60'/0'/0/0"
|
|
8
|
-
|
|
9
|
-
async getAddress(transport: Transport): Promise<string> {
|
|
10
|
-
const ledgerApp = new LedgerEthereumApp(transport)
|
|
11
|
-
const { address } = await ledgerApp.getAddress(this.defaultPath)
|
|
12
|
-
|
|
13
|
-
return address
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
async getPublicKey(transport: Transport): Promise<string> {
|
|
17
|
-
const ledgerApp = new LedgerEthereumApp(transport)
|
|
18
|
-
const { publicKey } = await ledgerApp.getAddress(this.defaultPath)
|
|
19
|
-
|
|
20
|
-
return '0x' + publicKey
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
async getSignTransactionFunction(transport: Transport) {
|
|
24
|
-
return async (transaction: ethers.providers.TransactionRequest): Promise<string> => {
|
|
25
|
-
const ledgerApp = new LedgerEthereumApp(transport)
|
|
26
|
-
|
|
27
|
-
const unsignedTransaction: ethers.utils.UnsignedTransaction = {
|
|
28
|
-
...transaction,
|
|
29
|
-
nonce: transaction.nonce ? ethers.BigNumber.from(transaction.nonce).toNumber() : undefined,
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const serializedUnsignedTransaction = ethers.utils.serializeTransaction(unsignedTransaction).substring(2)
|
|
33
|
-
|
|
34
|
-
const resolution = await LedgerEthereumAppService.resolveTransaction(serializedUnsignedTransaction, {}, {})
|
|
35
|
-
const signature = await ledgerApp.signTransaction(this.defaultPath, serializedUnsignedTransaction, resolution)
|
|
36
|
-
|
|
37
|
-
return ethers.utils.serializeTransaction(unsignedTransaction, {
|
|
38
|
-
v: ethers.BigNumber.from('0x' + signature.v).toNumber(),
|
|
39
|
-
r: '0x' + signature.r,
|
|
40
|
-
s: '0x' + signature.s,
|
|
41
|
-
})
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
}
|
package/src/RpcBDSEthereum.ts
DELETED
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
BalanceResponse,
|
|
3
|
-
BlockchainDataService,
|
|
4
|
-
ContractResponse,
|
|
5
|
-
Network,
|
|
6
|
-
Token,
|
|
7
|
-
TransactionResponse,
|
|
8
|
-
TransactionsByAddressParams,
|
|
9
|
-
TransactionsByAddressResponse,
|
|
10
|
-
} from '@cityofzion/blockchain-service'
|
|
11
|
-
import { ethers } from 'ethers'
|
|
12
|
-
import { TOKENS } from './constants'
|
|
13
|
-
|
|
14
|
-
export class RpcBDSEthereum implements BlockchainDataService {
|
|
15
|
-
private readonly network: Network
|
|
16
|
-
|
|
17
|
-
maxTimeToConfirmTransactionInMs: number = 1000 * 60 * 5
|
|
18
|
-
|
|
19
|
-
constructor(network: Network) {
|
|
20
|
-
this.network = network
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
async getTransaction(hash: string): Promise<TransactionResponse> {
|
|
24
|
-
const provider = new ethers.providers.JsonRpcProvider(this.network.url)
|
|
25
|
-
|
|
26
|
-
const transaction = await provider.getTransaction(hash)
|
|
27
|
-
if (!transaction || !transaction.blockHash || !transaction.to) throw new Error('Transaction not found')
|
|
28
|
-
|
|
29
|
-
const block = await provider.getBlock(transaction.blockHash)
|
|
30
|
-
if (!block) throw new Error('Block not found')
|
|
31
|
-
|
|
32
|
-
const tokens = TOKENS[this.network.type]
|
|
33
|
-
const token = tokens.find(token => token.symbol === 'ETH')!
|
|
34
|
-
|
|
35
|
-
return {
|
|
36
|
-
block: block.number,
|
|
37
|
-
time: block.timestamp,
|
|
38
|
-
hash: transaction.hash,
|
|
39
|
-
transfers: [
|
|
40
|
-
{
|
|
41
|
-
type: 'token',
|
|
42
|
-
amount: ethers.utils.formatEther(transaction.value),
|
|
43
|
-
contractHash: '-',
|
|
44
|
-
from: transaction.from,
|
|
45
|
-
to: transaction.to,
|
|
46
|
-
token,
|
|
47
|
-
},
|
|
48
|
-
],
|
|
49
|
-
notifications: [],
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
async getTransactionsByAddress(_params: TransactionsByAddressParams): Promise<TransactionsByAddressResponse> {
|
|
54
|
-
throw new Error("RPC doesn't support get transactions history of address")
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
async getContract(): Promise<ContractResponse> {
|
|
58
|
-
throw new Error("RPC doesn't support contract info")
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
async getTokenInfo(hash: string): Promise<Token> {
|
|
62
|
-
const tokens = TOKENS[this.network.type]
|
|
63
|
-
const token = tokens.find(token => token.hash === hash)
|
|
64
|
-
if (!token) throw new Error('Token not found')
|
|
65
|
-
|
|
66
|
-
return token
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
async getBalance(address: string): Promise<BalanceResponse[]> {
|
|
70
|
-
const provider = new ethers.providers.JsonRpcProvider(this.network.url)
|
|
71
|
-
const balance = await provider.getBalance(address)
|
|
72
|
-
|
|
73
|
-
const tokens = TOKENS[this.network.type]
|
|
74
|
-
const token = tokens.find(token => token.symbol === 'ETH')!
|
|
75
|
-
|
|
76
|
-
return [
|
|
77
|
-
{
|
|
78
|
-
amount: ethers.utils.formatEther(balance),
|
|
79
|
-
token,
|
|
80
|
-
},
|
|
81
|
-
]
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
async getBlockHeight(): Promise<number> {
|
|
85
|
-
const provider = new ethers.providers.JsonRpcProvider(this.network.url)
|
|
86
|
-
return await provider.getBlockNumber()
|
|
87
|
-
}
|
|
88
|
-
}
|