Files
web/src/common.js
2025-01-16 20:17:03 -04:00

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'})
}