bitgo
Version:
BitGo JavaScript SDK
156 lines (142 loc) • 4.97 kB
text/typescript
//
// BitGo JavaScript SDK
//
// Copyright 2014, BitGo, Inc. All Rights Reserved.
//
import pjson = require('../package.json');
import * as _ from 'lodash';
import { BaseCoin, CoinFactory, common, UnsupportedCoinError } from '@bitgo/sdk-core';
import { BitGoAPI, BitGoAPIOptions } from '@bitgo/sdk-api';
import {
createTokenMapUsingTrimmedConfigDetails,
TrimmedAmsTokenConfig,
createToken,
getFormattedTokenConfigForCoin,
coins,
BaseCoin as StaticsBaseCoin,
} from '@bitgo/statics';
import { GlobalCoinFactory, registerCoinConstructors, getTokenConstructor, getCoinConstructor } from './v2/coinFactory';
// constructor params used exclusively for BitGo class
export type BitGoOptions = BitGoAPIOptions & {
useAms?: boolean;
};
export class BitGo extends BitGoAPI {
private _coinFactory: CoinFactory;
private _useAms: boolean;
/**
* Constructor for BitGo Object
*/
constructor(params: BitGoOptions = {}) {
super(params);
if (
!common.validateParams(
params,
[],
[
'clientId',
'clientSecret',
'refreshToken',
'accessToken',
'userAgent',
'customRootURI',
'customBitcoinNetwork',
'serverXpub',
'stellarFederationServerUrl',
]
) ||
(params.useProduction && !_.isBoolean(params.useProduction)) ||
(params.useAms && !_.isBoolean(params.useAms))
) {
throw new Error('invalid argument');
}
if (!params.clientId !== !params.clientSecret) {
throw new Error('invalid argument - must provide both client id and secret');
}
this._useAms = !!params.useAms;
this._version = pjson.version;
this._userAgent = params.userAgent || 'BitGoJS/' + this.version();
this._coinFactory = new CoinFactory();
}
/**
* Initialize the coin factory with token configurations
* @param tokenConfigMap - A map of token metadata from AMS
*/
initCoinFactory(tokenConfigMap: Record<string, TrimmedAmsTokenConfig[]>): void {
const coinMap = createTokenMapUsingTrimmedConfigDetails(tokenConfigMap);
this._coinFactory = new CoinFactory();
registerCoinConstructors(this._coinFactory, coinMap);
}
/**
* Fetch all the tokens and initialize the coin factory
*/
async registerAllTokens(): Promise<void> {
if (!this._useAms) {
throw new Error('registerAllTokens is only supported when useAms is set to true');
}
// Fetch mainnet assets for prod and adminProd environments, testnet assets for all other environments
const assetEnvironment = ['prod', 'adminProd'].includes(this.getEnv()) ? 'mainnet' : 'testnet';
const url = this.url(`/assets/list/${assetEnvironment}`);
const tokenConfigMap = (await this.executeAssetRequest(url)) as Record<string, TrimmedAmsTokenConfig[]>;
this.initCoinFactory(tokenConfigMap);
}
/**
* Create a basecoin object
* @param coinName
*/
coin(coinName: string): BaseCoin {
if (this._useAms) {
return this._coinFactory.getInstance(this, coinName);
}
return GlobalCoinFactory.getInstance(this, coinName);
}
/**
* Register a token in the coin factory
* @param tokenConfig - The token metadata from AMS
*/
async registerToken(tokenName: string): Promise<void> {
if (!this._useAms) {
throw new Error('registerToken is only supported when useAms is set to true');
}
//do not register a coin/token if it's already registered
if (this._coinFactory.hasCoin(tokenName)) {
return;
}
// Get the coin/token details only if it's not present in statics library
let staticsBaseCoin: Readonly<StaticsBaseCoin> | undefined;
if (coins.has(tokenName)) {
staticsBaseCoin = coins.get(tokenName);
} else {
const url = this.url(`/assets/name/${tokenName}`);
const tokenConfig = (await this.executeAssetRequest(url)) as TrimmedAmsTokenConfig;
staticsBaseCoin = createToken(tokenConfig);
}
if (!staticsBaseCoin) {
throw new UnsupportedCoinError(tokenName);
}
if (staticsBaseCoin.isToken) {
const formattedTokenConfig = getFormattedTokenConfigForCoin(staticsBaseCoin);
if (!formattedTokenConfig) {
throw new UnsupportedCoinError(tokenName);
}
const tokenConstructor = getTokenConstructor(formattedTokenConfig);
if (!tokenConstructor) {
throw new UnsupportedCoinError(tokenName);
}
this._coinFactory.registerToken(staticsBaseCoin, tokenConstructor);
} else {
const coinConstructor = getCoinConstructor(tokenName);
if (!coinConstructor) {
throw new UnsupportedCoinError(tokenName);
}
this._coinFactory.registerToken(staticsBaseCoin, coinConstructor);
}
}
/**
* Create a basecoin object for a virtual token
* @param tokenName
*/
async token(tokenName: string): Promise<BaseCoin> {
await this.fetchConstants();
return this.coin(tokenName);
}
}