Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CU-86du15m7h - Plan, Structure and Implement BsLib support to multich… #67

Merged
merged 1 commit into from
Jul 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"changes": [
{
"packageName": "@cityofzion/blockchain-service",
"comment": "Adapt network to support multi network",
"type": "major"
}
],
"packageName": "@cityofzion/blockchain-service"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"changes": [
{
"packageName": "@cityofzion/bs-ethereum",
"comment": "Add support to EVM",
"type": "major"
}
],
"packageName": "@cityofzion/bs-ethereum"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"changes": [
{
"packageName": "@cityofzion/bs-neo-legacy",
"comment": "Adapt network to support multi network",
"type": "major"
}
],
"packageName": "@cityofzion/bs-neo-legacy"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"changes": [
{
"packageName": "@cityofzion/bs-neo3",
"comment": "Adapt network to support multi network",
"type": "major"
}
],
"packageName": "@cityofzion/bs-neo3"
}
6 changes: 3 additions & 3 deletions packages/blockchain-service/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@
"@typescript-eslint/parser": "^6.5.0",
"eslint": "^8.48.0",
"ts-node": "10.9.1",
"typescript": "4.9.5"
"typescript": "4.9.5",
"typed-emitter": "~2.1.0"
},
"dependencies": {
"@ledgerhq/hw-transport": "~6.30.5",
"axios": "1.5.1",
"typed-emitter": "~2.1.0"
"axios": "1.5.1"
}
}
4 changes: 2 additions & 2 deletions packages/blockchain-service/src/BSAggregator.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { AccountWithDerivationPath, BlockchainService, Network, PartialBy } from './interfaces'
import { AccountWithDerivationPath, BlockchainService, PartialNetwork } from './interfaces'

export class BSAggregator<
BSCustomName extends string = string,
Expand All @@ -12,7 +12,7 @@ export class BSAggregator<
this.#blockchainServices = Object.values(blockchainServices)
}

setNetwork(network: PartialBy<Network, 'url'>) {
setNetwork(network: PartialNetwork) {
this.#blockchainServices.forEach(bs => bs.setNetwork(network))
}

Expand Down
7 changes: 1 addition & 6 deletions packages/blockchain-service/src/CryptoCompareEDS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import {
Currency,
ExchangeDataService,
GetTokenPriceHistory,
NetworkType,
Token,
TokenPricesHistoryResponse,
TokenPricesResponse,
Expand All @@ -27,19 +26,15 @@ type CryptoCompareHistoryResponse = {
}

export class CryptoCompareEDS implements ExchangeDataService {
networkType: NetworkType
readonly #axiosInstance: AxiosInstance
readonly #tokens: Token[]

constructor(network: NetworkType, tokens: Token[] = []) {
this.networkType = network
constructor(tokens: Token[] = []) {
this.#tokens = tokens
this.#axiosInstance = axios.create({ baseURL: 'https://min-api.cryptocompare.com' })
}

async getTokenPrices(currency: Currency): Promise<TokenPricesResponse[]> {
if (this.networkType !== 'mainnet') throw new Error('Exchange is only available on mainnet')

const tokenSymbols = this.#tokens.map(token => token.symbol)
const { data: prices } = await this.#axiosInstance.get<CryptoCompareDataResponse>('/data/pricemultifull', {
params: {
Expand Down
40 changes: 24 additions & 16 deletions packages/blockchain-service/src/interfaces.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import Transport from '@ledgerhq/hw-transport'
import TypedEmitter from 'typed-emitter'

export type PartialBy<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>

export type Account = {
key: string
type: 'wif' | 'privateKey' | 'publicKey'
Expand All @@ -17,11 +15,19 @@ export interface Token {
hash: string
decimals: number
}
export type NetworkType = 'mainnet' | 'testnet' | 'custom'
export type Network = {
type: NetworkType

export type Network<T extends string = string> = {
id: T
name: string
url: string
}

export type PartialNetwork<T extends string = string> = {
id: T
name?: string
url?: string
}

export type IntentTransferParam = {
receiverAddress: string
tokenHash: string
Expand All @@ -37,15 +43,15 @@ export type TransferParam = {
isLedger?: boolean
}

export interface BlockchainService<BSCustomName extends string = string> {
export interface BlockchainService<BSCustomName extends string = string, BSAvailableNetworks extends string = string> {
readonly blockchainName: BSCustomName
readonly derivationPath: string
readonly feeToken: Token
exchangeDataService: ExchangeDataService
blockchainDataService: BlockchainDataService
tokens: Token[]
network: Network
setNetwork: (network: PartialBy<Network, 'url'>) => void
network: Network<BSAvailableNetworks>
setNetwork: (partialNetwork: PartialNetwork<BSAvailableNetworks>) => void
generateAccountFromMnemonic(mnemonic: string | string, index: number): AccountWithDerivationPath
generateAccountFromKey(key: string): Account
decrypt(keyOrJson: string, password: string): Promise<Account>
Expand Down Expand Up @@ -267,27 +273,27 @@ export type SwapControllerServiceEvents = {
lastAmountChanged: (lastAmountChanged: 'amountToUse' | 'amountToReceive' | null) => void | Promise<void>
}

export type SwapControllerServiceSwapArgs = {
export type SwapControllerServiceSwapArgs<T extends string> = {
amountToUse: string
amountToReceive: string
tokenToUse: Token
tokenToReceive: Token
address: string
deadline: string
network: Network
network: Network<T>
}

export type SwapControllerServiceSwapToUseArgs = {
export type SwapControllerServiceSwapToUseArgs<T extends string> = {
minimumReceived: string
type: 'swapTokenToUse'
} & SwapControllerServiceSwapArgs
} & SwapControllerServiceSwapArgs<T>

export type SwapControllerServiceSwapToReceiveArgs = {
export type SwapControllerServiceSwapToReceiveArgs<T extends string> = {
maximumSelling: string
type: 'swapTokenToReceive'
} & SwapControllerServiceSwapArgs
} & SwapControllerServiceSwapArgs<T>

export interface SwapControllerService {
export interface SwapControllerService<AvailableNetworkIds extends string> {
eventEmitter: TypedEmitter<SwapControllerServiceEvents>

setAccountToUse(account: Account | null): void
Expand All @@ -298,7 +304,9 @@ export interface SwapControllerService {
setDeadline(deadline: string): void
setSlippage(slippage: number): void
swap(isLedger?: boolean): void
buildSwapArgs(): SwapControllerServiceSwapToUseArgs | SwapControllerServiceSwapToReceiveArgs
buildSwapArgs():
| SwapControllerServiceSwapToUseArgs<AvailableNetworkIds>
| SwapControllerServiceSwapToReceiveArgs<AvailableNetworkIds>
setReserves(): void
startListeningBlockGeneration(): void
stopListeningBlockGeneration(): void
Expand Down
2 changes: 1 addition & 1 deletion packages/bs-ethereum/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,13 @@
"@ethersproject/json-wallets": "5.7.0",
"@ethersproject/bytes": "5.7.0",
"@ethersproject/bignumber": "5.7.0",
"@ledgerhq/hw-transport-node-hid": "~6.28.5",
"@ledgerhq/hw-transport": "~6.30.5",
"@ledgerhq/hw-app-eth": "~6.35.7",
"@ethersproject/abstract-signer": "~5.7.0",
"@ethersproject/properties": "~5.7.0"
},
"devDependencies": {
"@ledgerhq/hw-transport-node-hid": "~6.28.5",
"@types/jest": "29.5.3",
"@typescript-eslint/eslint-plugin": "^6.5.0",
"@typescript-eslint/parser": "^6.5.0",
Expand Down
49 changes: 30 additions & 19 deletions packages/bs-ethereum/src/BSEthereum.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,36 @@ import {
ExchangeDataService,
Network,
NftDataService,
PartialBy,
PartialNetwork,
Token,
TransferParam,
} from '@cityofzion/blockchain-service'
import { ethers } from 'ethers'
import * as ethersJsonWallets from '@ethersproject/json-wallets'
import * as ethersBytes from '@ethersproject/bytes'
import * as ethersBigNumber from '@ethersproject/bignumber'
import { DEFAULT_URL_BY_NETWORK_TYPE, DERIVATION_PATH, NATIVE_ASSETS, TOKENS } from './constants'
import { BitqueryEDSEthereum } from './BitqueryEDSEthereum'
import { GhostMarketNDSEthereum } from './GhostMarketNDSEthereum'
import { RpcBDSEthereum } from './RpcBDSEthereum'
import { BitqueryBDSEthereum } from './BitqueryBDSEthereum'
import { LedgerServiceEthereum, LedgerSigner } from './LedgerServiceEthereum'
import Transport from '@ledgerhq/hw-transport'
import {
AvailableNetworkIds,
BITQUERY_MIRROR_NETWORK_BY_NETWORK_ID,
DEFAULT_URL_BY_NETWORK_ID,
DERIVATION_PATH,
NATIVE_ASSET_BY_NETWORK_ID,
NETWORK_NAME_BY_NETWORK_ID,
} from './constants'

export class BSEthereum<BSCustomName extends string = string>
implements BlockchainService, BSWithNft, BSWithNameService, BSCalculableFee, BSWithLedger
implements
BlockchainService<BSCustomName, AvailableNetworkIds>,
BSWithNft,
BSWithNameService,
BSCalculableFee,
BSWithLedger
{
readonly blockchainName: BSCustomName
readonly feeToken: Token
Expand All @@ -37,36 +50,34 @@ export class BSEthereum<BSCustomName extends string = string>
ledgerService: LedgerServiceEthereum
tokens: Token[]
nftDataService!: NftDataService
network!: Network
network!: Network<AvailableNetworkIds>

constructor(
blockchainName: BSCustomName,
network: PartialBy<Network, 'url'>,
network: PartialNetwork<AvailableNetworkIds>,
getLedgerTransport?: (account: Account) => Promise<Transport>
) {
this.blockchainName = blockchainName
this.ledgerService = new LedgerServiceEthereum(getLedgerTransport)
this.derivationPath = DERIVATION_PATH
this.tokens = TOKENS[network.type]

this.feeToken = this.tokens.find(token => token.symbol === 'ETH')!
this.tokens = [NATIVE_ASSET_BY_NETWORK_ID[network.id]]
this.feeToken = NATIVE_ASSET_BY_NETWORK_ID[network.id]
this.setNetwork(network)
}

setNetwork(param: PartialBy<Network, 'url'>) {
setNetwork(partialNetwork: PartialNetwork<AvailableNetworkIds>) {
const network = {
type: param.type,
url: param.url ?? DEFAULT_URL_BY_NETWORK_TYPE[param.type],
id: partialNetwork.id,
name: partialNetwork.name ?? NETWORK_NAME_BY_NETWORK_ID[partialNetwork.id],
url: partialNetwork.url ?? DEFAULT_URL_BY_NETWORK_ID[partialNetwork.id],
}
this.network = network

if (network.type !== 'mainnet') {
this.blockchainDataService = new RpcBDSEthereum(network)
} else {
this.blockchainDataService = new BitqueryBDSEthereum(network)
}
const bitqueryNetwork = BITQUERY_MIRROR_NETWORK_BY_NETWORK_ID[partialNetwork.id]

this.blockchainDataService = bitqueryNetwork ? new BitqueryBDSEthereum(network) : new RpcBDSEthereum(network)

this.exchangeDataService = new BitqueryEDSEthereum(network.type)
this.exchangeDataService = new BitqueryEDSEthereum(network.id)
this.nftDataService = new GhostMarketNDSEthereum(network)
}

Expand Down Expand Up @@ -164,7 +175,7 @@ export class BSEthereum<BSCustomName extends string = string>

let transactionParams: ethers.utils.Deferrable<ethers.providers.TransactionRequest>

const isNative = NATIVE_ASSETS.some(asset => asset.hash === param.intent.tokenHash)
const isNative = NATIVE_ASSET_BY_NETWORK_ID[this.network.id].hash === param.intent.tokenHash
if (isNative) {
transactionParams = {
to: param.intent.receiverAddress,
Expand Down Expand Up @@ -204,7 +215,7 @@ export class BSEthereum<BSCustomName extends string = string>

let estimated: ethers.BigNumber

const isNative = NATIVE_ASSETS.some(asset => asset.hash === param.intent.tokenHash)
const isNative = NATIVE_ASSET_BY_NETWORK_ID[this.network.id].hash === param.intent.tokenHash
const decimals = param.intent.tokenDecimals ?? 18
const amount = ethersBigNumber.parseFixed(param.intent.amount, decimals)

Expand Down
Loading
Loading