UNPKG

@mimicry/sdk

Version:

A node SDK designed to simplify interaction with the Mimicry Protocol smart contracts.

197 lines (173 loc) 6.34 kB
import { Contract, Signer, ContractTransactionResponse } from 'ethers'; import { IOHLCV } from 'candlestick-convert'; import { CurrencyInfo, MarketInfo, Skew, Value } from '../types'; import { CurrencySymbol, Direction, OracleType, Timeframe } from '../enums'; import { Currency } from './currency'; import { Oracle } from './oracle'; import { OpenMarketsOracle } from './vendors/oracles/openMarketsOracle'; import { bigIntToValue } from '../utils/bigIntToValue'; import { numberToBigInt } from '../utils/numberToBigInt'; import * as MarketABI from './abi/market.json'; export class Market { private contract: Contract; private signer: Signer; private metadata?: any; private oracle?: Oracle; constructor(_contract: Contract, _signer: Signer) { this.contract = _contract; this.signer = _signer; } static async initialize(_address: string, _signer: Signer): Promise<Market> { if (__DEV__) { console.log(`Initialize Market: ${_address}`); } const contract = new Contract(_address, MarketABI.abi as any, _signer); return new Market(contract, _signer); } // ---- MARKET INFO --------------------------------------------------------- public async getInfo(): Promise<MarketInfo> { const metadata = await this.getMetadata(); const currencyInfo = await this.getCurrencyInfo(metadata.currency); const info: MarketInfo = { name: metadata.name, address: await this.getAddress(), description: metadata.description, image: metadata.image, metric: metadata.metric, referenceValue: await this.getReferenceValue(currencyInfo), skew: await this.getSkew(), }; return info; } public async getMetadata(force: boolean = false): Promise<any> { if (this.metadata && !force) { return this.metadata; } const url = await this.contract.metadataURI(); if (__DEV__) { console.log(`Market Metadata URL: ${url}`); } const response = await fetch(url); const json = await response.json(); this.metadata = json; return json; } public async getAddress(): Promise<string> { return await this.contract.getAddress(); } public async getSkew(): Promise<Skew> { const positionValues = await this.contract.calculatePositionValues(); const currencyInfo = await this.getCurrencyInfo(CurrencySymbol.USD); const long: Value = bigIntToValue(positionValues[0], currencyInfo); const short: Value = bigIntToValue(positionValues[1], currencyInfo); return { currency: currencyInfo, long: long.amount, short: short.amount, }; } // ---- ORACLE -------------------------------------------------------------- public async getReferenceValue(_currencyInfo: CurrencyInfo): Promise<Value> { return bigIntToValue(await this.contract.getIndexValue(), _currencyInfo); } public async getOracle(): Promise<Oracle> { if (this.oracle) { return this.oracle; } const metadata = await this.getMetadata(); if (metadata.oracle.type !== OracleType.OMO) { throw new Error('Only OMO oracles are supported'); } const oracle = await OpenMarketsOracle.initialize( metadata.oracle, this.signer ); this.oracle = oracle; return oracle; } public async getTicks(): Promise<any> { const oracle = await this.getOracle(); return await oracle.getTicks(); } public async getOHLCV(_timeframe: Timeframe): Promise<IOHLCV[]> { const oracle = await this.getOracle(); return await oracle.getOHLCV(_timeframe); } // ---- CURRENCY INFO ------------------------------------------------------- public async getCurrencyInfo( _address: string | CurrencySymbol ): Promise<CurrencyInfo> { if (_address === 'usd') { // TODO: Remove this hack when metadata has decimals return { name: 'US Dollar', symbol: CurrencySymbol.USD, decimals: BigInt(0), }; } else if (_address === CurrencySymbol.USD) { return { name: 'US Dollar', symbol: CurrencySymbol.USD, decimals: BigInt(8), }; } const currency = await Currency.initialize(_address, this.signer); return await currency.getInfo(); } // ---- POSITIONS ----------------------------------------------------------- public async getPositionValue(_positionId: number): Promise<Value> { const currencyInfo = await this.getCurrencyInfo(CurrencySymbol.USD); return bigIntToValue( await this.contract.getPositionValue(_positionId), currencyInfo ); } public async closePosition( _positionId: number ): Promise<ContractTransactionResponse> { if (await !this.contract.isPositionEditable(_positionId)) { throw new Error('Position is not editable.'); } if (await !this.contract.isPositionLiquidated(_positionId)) { throw new Error('Position has been liquidated.'); } const tx = await this.contract.closePosition(_positionId); return await tx.wait(); } public async openPosition( _direction: Direction, _currency: Currency, _amount: number ): Promise<ContractTransactionResponse[]> { const txApproveReceipt = await _currency.approveSpending( await this.getAddress(), _amount ); const currencyInfo = await _currency.getInfo(); const amount = numberToBigInt(_amount, currencyInfo); const tx = await this.contract.openPosition( _direction, currencyInfo.address, amount ); const txOpenPositionReceipt = await tx.wait(); return [txApproveReceipt, txOpenPositionReceipt]; } // public async increasePosition( // _positionId: number, // _amount: BigInt // ): Promise<ContractTransactionResponse> { // // TODO: Get the currency used to open the position // // TODO: Account for spending approvals // if (await !this.contract.isPositionEditable(_positionId)) { // throw new Error('Position is not editable.'); // } // const tx = await this.contract.increasePosition(_positionId, _amount); // return await tx.wait(); // } // ---- VALUE TRANSFERS ----------------------------------------------------- public async commitValueTransfer(): Promise<ContractTransactionResponse> { const tx = await this.contract.commitValueTransfer(); return await tx.wait(); } }