153 lines
3.9 KiB
JavaScript
153 lines
3.9 KiB
JavaScript
export function mixin(child, ...parents) {
|
|
// child is modified directly, assigning fields from parents that are missing in child. parents fields are
|
|
// assigned by parents order, highest priority first
|
|
for( const parent of parents ) {
|
|
for ( const key in parent) {
|
|
if (parent.hasOwnProperty(key) && !child.hasOwnProperty(key) && parent[key] !== undefined) {
|
|
child[key] = parent[key];
|
|
}
|
|
}
|
|
}
|
|
return child;
|
|
}
|
|
|
|
export function prototype(parent, child) {
|
|
const result = Object.create(parent);
|
|
Object.assign(result, child)
|
|
return result
|
|
}
|
|
|
|
export function invokeCallback(cbs, prop, ...args) {
|
|
if (prop in cbs) cbs[prop].call(cbs, ...args)
|
|
}
|
|
|
|
export function invokeCallbacks(callbacks, prop, ...args) {
|
|
if (!callbacks) return
|
|
callbacks.forEach((cb)=>invokeCallback(cb, prop, ...args))
|
|
}
|
|
|
|
|
|
export function encodeIEE754(value) {
|
|
const buffer = new ArrayBuffer(4);
|
|
const view = new DataView(buffer);
|
|
view.setFloat32(0, value, false /* big endian */);
|
|
return view.getUint32(0, false);
|
|
}
|
|
|
|
|
|
export function decodeIEE754(value) {
|
|
const buffer = new ArrayBuffer(4);
|
|
const view = new DataView(buffer);
|
|
view.setUint32(0, value, false)
|
|
return view.getFloat32(0, false)
|
|
}
|
|
|
|
|
|
export function buildMetadataMap(metadata) {
|
|
const metadataMap = {}
|
|
for (const [chain, info] of Object.entries(metadata)) {
|
|
const map = {}
|
|
for (const poolMeta of info.p)
|
|
map[poolMeta.a] = poolMeta
|
|
for (const tokenMeta of info.t)
|
|
map[tokenMeta.a] = tokenMeta
|
|
metadataMap[Number(chain)] = map
|
|
}
|
|
// console.log('metadataMap', metadataMap)
|
|
return metadataMap
|
|
}
|
|
|
|
|
|
//
|
|
// AsyncCache
|
|
//
|
|
|
|
export class AsyncCache {
|
|
// fetch(key) returns a value
|
|
constructor(fetch) {
|
|
this.cache = {}
|
|
this.fetchLocks = {}
|
|
this.fetch = fetch
|
|
}
|
|
|
|
async get(key) {
|
|
if (this.cache[key]) {
|
|
return this.cache[key]
|
|
}
|
|
if (this.fetchLocks[key]) {
|
|
return await this.fetchLocks[key]
|
|
}
|
|
const fetchPromise = this.fetch(key)
|
|
this.fetchLocks[key] = fetchPromise
|
|
const result = await fetchPromise
|
|
this.cache[key] = result
|
|
delete this.fetchLocks[key]
|
|
return result
|
|
}
|
|
}
|
|
|
|
|
|
export class AsyncAbiCache extends AsyncCache {
|
|
constructor(fetch) {
|
|
super(async (key)=>{
|
|
const result = await fetch(key)
|
|
return result.abi
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
export class AsyncURLCache extends AsyncAbiCache {
|
|
constructor(urlForKey) {
|
|
super(async (key) => {
|
|
const URL = this.urlForKey(key)
|
|
const response = await fetch(URL)
|
|
if (!response.ok)
|
|
throw new Error(`Could not fetch ${URL} (status ${response.status})`)
|
|
return await response.json()
|
|
})
|
|
this.urlForKey = urlForKey
|
|
}
|
|
}
|
|
|
|
|
|
export class AbiURLCache extends AsyncURLCache {
|
|
constructor(baseUrl) {
|
|
super((name)=>{
|
|
return this.baseUrl+abiPath(name)
|
|
})
|
|
this.baseUrl = baseUrl.endsWith('/') ? baseUrl : baseUrl + '/'
|
|
}
|
|
}
|
|
|
|
|
|
const files = {
|
|
// If a contract is in a file different than its name, put the exception here
|
|
// 'IVaultImpl' : 'IVault', // for example
|
|
// 'IERC20Metadata' : 'interfaces/IERC20Metadata',
|
|
}
|
|
|
|
export function abiPath(name) {
|
|
const file = files[name]
|
|
return `${file??name}.sol/${name}.json`
|
|
}
|
|
|
|
|
|
export function parseFill(obj) {
|
|
let [tx, time, filledIn, filledOut, fee] = obj
|
|
time = new Date(time * 1000)
|
|
filledIn = BigInt(filledIn)
|
|
filledOut = BigInt(filledOut)
|
|
fee = BigInt(fee)
|
|
return {tx, time, filledIn, filledOut, fee}
|
|
}
|
|
|
|
export function timestamp(date = null) {
|
|
if (date === null)
|
|
date = new Date()
|
|
return Math.round(date.getTime() / 1000)
|
|
}
|
|
|
|
export function dateString(datetime) {
|
|
return datetime.toLocaleString({dateStyle: 'medium', timeStyle: 'short'})
|
|
} |