Skip to content

Commit

Permalink
Improve how PoR loads underlying adapters from the env
Browse files Browse the repository at this point in the history
  • Loading branch information
krebernisak committed Jan 12, 2021
1 parent f24c1ff commit 6e53693
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 47 deletions.
18 changes: 14 additions & 4 deletions bootstrap/src/lib/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
AdapterRequest,
AdapterResponse,
WrappedAdapterResponse,
AdapterImplementation,
} from '@chainlink/types'
import { v4 as uuidv4 } from 'uuid'

Expand Down Expand Up @@ -43,7 +44,8 @@ export const toAsync = (
execute(data, (statusCode: number, data: AdapterResponse) => resolve({ statusCode, data })),
)

export const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms))
export const delay = (ms: number): Promise<number> =>
new Promise((resolve) => setTimeout(resolve, ms))

/**
* Return a value used for exponential backoff in milliseconds.
Expand Down Expand Up @@ -94,7 +96,8 @@ const getEnvName = (name: string, prefix = '') => {
// Only case-insensitive alphanumeric and underscore (_) are allowed for env vars
const isEnvNameValid = (name: string) => /^[_a-z0-9]+$/i.test(name)

export const getEnv = (name: string, prefix = '') => process.env[getEnvName(name, prefix)]
export const getEnv = (name: string, prefix = ''): string | undefined =>
process.env[getEnvName(name, prefix)]

// Custom error for required env variable.
export class RequiredEnvError extends Error {
Expand All @@ -110,7 +113,7 @@ export class RequiredEnvError extends Error {
* @throws {RequiredEnvError} Will throw an error if environment variable is not defined.
* @returns {string}
*/
export const getRequiredEnv = (name: string, prefix = '') => {
export const getRequiredEnv = (name: string, prefix = ''): string => {
const val = getEnv(name, prefix)
if (!val) throw new RequiredEnvError(getEnvName(name, prefix))
return val
Expand Down Expand Up @@ -139,7 +142,6 @@ export const wrapExecute = (execute: Execute) => async (
*
* @returns Map of the array grouped by the grouping function.
*/

export function groupBy<K, V>(list: Array<V>, keyGetter: (input: V) => K): Map<K, Array<V>> {
const map = new Map<K, Array<V>>()
list.forEach((item) => {
Expand All @@ -153,3 +155,11 @@ export function groupBy<K, V>(list: Array<V>, keyGetter: (input: V) => K): Map<K
})
return map
}

/**
* Predicate used to find adapter by name
*
* @param name string adapter name
*/
export const byName = (name?: string) => (a: AdapterImplementation): boolean =>
a.NAME.toUpperCase() === name?.toUpperCase()
49 changes: 24 additions & 25 deletions composite/proof-of-reserves/src/balance.ts
Original file line number Diff line number Diff line change
@@ -1,43 +1,42 @@
import { Execute, Implementations } from '@chainlink/types'
import { Execute, AdapterImplementation } from '@chainlink/types'
import { util } from '@chainlink/ea-bootstrap'
// balance adapters
import amberdata from '@chainlink/amberdata-adapter'
import blockchainCom from '@chainlink/blockchain.com-adapter'
import blockchair from '@chainlink/blockchair-adapter'
import blockcypher from '@chainlink/blockcypher-adapter'
import btc_com from '@chainlink/btc.com-adapter'
import btcCom from '@chainlink/btc.com-adapter'
import cryptoapis from '@chainlink/cryptoapis-adapter'
import sochain from '@chainlink/sochain-adapter'

export type BitcoinIndexerOptions = { type?: BitcoinIndexer }
export enum BitcoinIndexer {
Amberdata = 'amberdata',
BlockchainCom = 'blockchain_com',
Blockcypher = 'blockcypher',
Blockchair = 'blockchair',
BtcCom = 'btc_com',
Cryptoapis = 'cryptoapis',
SoChain = 'sochain',
}
const implLookup: Implementations<BitcoinIndexer> = {
[amberdata.NAME]: amberdata,
[blockchainCom.NAME]: blockchainCom,
[blockcypher.NAME]: blockcypher,
[blockchair.NAME]: blockchair,
[btc_com.NAME]: btc_com,
[cryptoapis.NAME]: cryptoapis,
[sochain.NAME]: sochain,
const ENV_BTC_INDEXER_ADAPTER = 'BTC_INDEXER_ADAPTER'

const adapters: AdapterImplementation[] = [
amberdata,
blockchainCom,
blockcypher,
blockchair,
btcCom,
cryptoapis,
sochain,
]

export type BitcoinIndexer = typeof adapters[number]['NAME']
export type BitcoinIndexerOptions = {
type?: BitcoinIndexer
}

const isBitcoinIndexer = (envVar?: string): envVar is BitcoinIndexer =>
Object.values(BitcoinIndexer).includes(envVar as any)
const isBitcoinIndexer = (envVal?: string): envVal is BitcoinIndexer =>
!!(envVal && adapters.find(util.byName(envVal)))

export const getBitcoinIndexer = (): BitcoinIndexer | undefined => {
const bitcoinIndexer = process.env.BTC_INDEXER_ADAPTER
return isBitcoinIndexer(bitcoinIndexer) ? (bitcoinIndexer as BitcoinIndexer) : undefined
const envVal = util.getEnv(ENV_BTC_INDEXER_ADAPTER)
return isBitcoinIndexer(envVal) ? envVal : undefined
}

export const getImpl = (options: BitcoinIndexerOptions): Execute => {
const prefix = options.type?.toUpperCase()
const impl = options.type && implLookup[options.type?.toUpperCase()]
const impl = adapters.find(util.byName(options.type))
if (!impl) throw Error(`Unknown balance adapter type: ${options.type}`)

return (data) => {
Expand Down
29 changes: 15 additions & 14 deletions composite/proof-of-reserves/src/protocol.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,29 @@
import { Execute, Implementations } from '@chainlink/types'
import { Execute, AdapterImplementation } from '@chainlink/types'
import { util } from '@chainlink/ea-bootstrap'
// protocol adapters
import renVM from '@chainlink/renvm-address-set-adapter'
import wBTC from '@chainlink/wbtc-address-set-adapter'

export type ProtocolOptions = { type?: Protocol }
export enum Protocol {
WBTC = 'wbtc',
RenVM = 'renvm',
}
const implLookup: Implementations<Protocol> = {
[wBTC.NAME]: wBTC,
[renVM.NAME]: renVM,
const ENV_PROTOCOL_ADAPTER = 'PROTOCOL_ADAPTER'

const adapters: AdapterImplementation[] = [wBTC, renVM]

export type Protocol = typeof adapters[number]['NAME']
export type ProtocolOptions = {
type?: Protocol
}

const isProtocol = (envVar?: string): envVar is Protocol =>
Object.values(Protocol).includes(envVar as any)
const isProtocol = (envVal?: string): envVal is Protocol =>
!!(envVal && adapters.find(util.byName(envVal)))

export const getProtocol = (): Protocol | undefined => {
const protocol = process.env.PROTOCOL_ADAPTER
return isProtocol(protocol) ? (protocol as Protocol) : undefined
const envVal = util.getEnv(ENV_PROTOCOL_ADAPTER)
return isProtocol(envVal) ? envVal : undefined
}

export const getImpl = (options: ProtocolOptions): Execute => {
const prefix = options.type?.toUpperCase()
const impl = options.type && implLookup[options.type?.toUpperCase()]
const impl = adapters.find(util.byName(options.type))
if (!impl) throw Error(`Unknown protocol adapter type: ${options.type}`)

return (data) => {
Expand Down
4 changes: 0 additions & 4 deletions typings/@chainlink/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,10 +91,6 @@ declare module '@chainlink/types' {
makeConfig: ConfigFactory
} & ExecuteHandlers

export interface Implementations<t> {
[type: string]: AdapterImplementation
}

/* IMPLEMENTATIONS */
export type Address = {
address: string
Expand Down

0 comments on commit 6e53693

Please sign in to comment.