edge-core-js
Version:
Edge account & wallet management library
202 lines (173 loc) • 6.04 kB
JavaScript
function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }import { makeMemoryDisklet } from 'disklet'
import { bridgifyObject, close, update, watchMethod } from 'yaob'
import { makePeriodicTask, } from '../../util/periodic-task'
import { snooze } from '../../util/snooze'
import { getMaxSpendableInner } from '../currency/wallet/max-spend'
import { makeLog } from '../log/log'
import { getCurrencyTools } from '../plugins/plugins-selectors'
let memoryWalletCount = 0
export const makeMemoryWalletInner = async (
ai,
config,
walletType,
opts = {}
) => {
const { keys } = opts
if (keys == null) throw new Error('No keys provided')
const walletId = `memorywallet-${memoryWalletCount++}`
const walletInfo = {
id: walletId,
type: walletType,
keys
}
const tools = await getCurrencyTools(ai, config.currencyInfo.pluginId)
const publicKeys = await tools.derivePublicKey(walletInfo)
walletInfo.keys = { ...publicKeys, ...walletInfo.keys }
const log = makeLog(ai.props.logBackend, `${walletId}-${walletType}`)
let balanceMap = new Map()
let detectedTokenIds = []
let syncRatio = 0
let needsUpdate = false
const updateWallet = () => {
if (needsUpdate) {
update(out)
needsUpdate = false
}
}
const updater = makePeriodicTask(async () => {
await snooze(1000) // one second
updateWallet()
}, 0)
const plugin = ai.props.state.plugins.currency[config.currencyInfo.pluginId]
const engine = await plugin.makeCurrencyEngine(walletInfo, {
callbacks: {
onAddressChanged: () => {},
onAddressesChecked: (progressRatio) => {
if (out.syncRatio === 1) return
if (progressRatio === 1) {
syncRatio = progressRatio
needsUpdate = true
}
},
onNewTokens: (tokenIds) => {
const sortedTokenIds = tokenIds.sort((a, b) => a.localeCompare(b))
if (detectedTokenIds.length !== sortedTokenIds.length) {
detectedTokenIds = sortedTokenIds
needsUpdate = true
return
}
for (let i = 0; i < sortedTokenIds.length; i++) {
if (detectedTokenIds[i] !== sortedTokenIds[i]) {
detectedTokenIds = sortedTokenIds
needsUpdate = true
return
}
}
},
onSeenTxCheckpoint: () => {},
onStakingStatusChanged: () => {},
onSubscribeAddresses: () => {},
onTokenBalanceChanged: (tokenId, balance) => {
if (balanceMap.get(tokenId) === balance) return
balanceMap = new Map(balanceMap)
balanceMap.set(tokenId, balance)
needsUpdate = true
},
onTransactions: () => {},
onTransactionsChanged: () => {},
onTxidsChanged: () => {},
onUnactivatedTokenIdsChanged: () => {},
onWcNewContractCall: () => {},
onBlockHeightChanged: () => {},
onBalanceChanged: () => {}
},
customTokens: { ...config.customTokens },
enabledTokenIds: [...Object.keys(config.allTokens)],
lightMode: true,
log,
userSettings: { ...(_nullishCoalesce(config.userSettings, () => ( {}))) },
walletLocalDisklet: makeMemoryDisklet(),
walletLocalEncryptedDisklet: makeMemoryDisklet()
})
const {
unsafeBroadcastTx = false,
unsafeMakeSpend = false,
unsafeSyncNetwork = false
} = plugin.currencyInfo
const privateKeys = { ...keys }
let syncNetworkTask
// Setup syncNetwork routine if defined by the currency engine:
if (engine.syncNetwork != null) {
// Get the private keys if required by the engine:
const doNetworkSync = async () => {
if (engine.syncNetwork != null) {
const delay = await engine.syncNetwork({
privateKeys: unsafeSyncNetwork ? { privateKeys: keys } : undefined
})
syncNetworkTask.setDelay(delay)
} else {
syncNetworkTask.stop()
}
}
syncNetworkTask = makePeriodicTask(doNetworkSync, 10000, {
onError: error => {
ai.props.log.error(error)
}
})
syncNetworkTask.start({ wait: false })
}
const out = bridgifyObject({
watch: watchMethod,
get balanceMap() {
return balanceMap
},
get detectedTokenIds() {
return detectedTokenIds
},
get syncRatio() {
return syncRatio
},
async changeEnabledTokenIds(tokenIds) {
if (engine.changeEnabledTokenIds != null) {
await engine.changeEnabledTokenIds(tokenIds)
}
},
async startEngine() {
await engine.startEngine()
_optionalChain([syncNetworkTask, 'optionalAccess', _ => _.start, 'call', _2 => _2({ wait: false })])
},
async getMaxSpendable(spendInfo) {
return await getMaxSpendableInner(
spendInfo,
plugin,
engine,
config.allTokens,
walletInfo
)
},
async makeSpend(spendInfo) {
return await engine.makeSpend(
spendInfo,
unsafeMakeSpend ? privateKeys : undefined
)
},
async signTx(tx) {
return await engine.signTx(tx, privateKeys)
},
async broadcastTx(tx) {
return await engine.broadcastTx(
tx,
unsafeBroadcastTx ? privateKeys : undefined
)
},
async saveTx() {},
async close() {
log.warn('killing memory wallet')
_optionalChain([syncNetworkTask, 'optionalAccess', _3 => _3.stop, 'call', _4 => _4()])
close(out)
await engine.killEngine()
}
})
updater.start({ wait: false })
return out
}