From 28fb20972829fa3d5326763653af3a443d74826b Mon Sep 17 00:00:00 2001 From: Asia Date: Tue, 8 Aug 2023 11:00:35 +0200 Subject: [PATCH] bazar integration test --- package.json | 3 +- src/__tests__/integration/basic/bazar.test.ts | 418 ++++ src/__tests__/integration/data/bazar-asset.js | 238 +++ src/__tests__/integration/data/bazar-u.js | 1803 ++++++++++++++++ src/__tests__/integration/data/bazar-ucm.js | 1843 +++++++++++++++++ yarn.lock | 29 +- 6 files changed, 4329 insertions(+), 5 deletions(-) create mode 100644 src/__tests__/integration/basic/bazar.test.ts create mode 100644 src/__tests__/integration/data/bazar-asset.js create mode 100644 src/__tests__/integration/data/bazar-u.js create mode 100644 src/__tests__/integration/data/bazar-ucm.js diff --git a/package.json b/package.json index fdd3a9e9..c8bbc75a 100644 --- a/package.json +++ b/package.json @@ -119,10 +119,11 @@ "ts-jest": "^28.0.7", "ts-node": "^10.2.1", "typescript": "^4.9.5", + "warp-contracts-rc": "npm:warp-contracts@1.4.15-rc.4", "warp-contracts-plugin-deploy": "1.0.8", "warp-contracts-plugin-vm2": "1.0.1", "warp-contracts-plugin-vrf": "^1.0.3", - "warp-contracts-sqlite": "^1.0.3-beta.1", + "warp-contracts-sqlite": "^1.0.2", "ws": "^8.11.0" }, "resolutions": { diff --git a/src/__tests__/integration/basic/bazar.test.ts b/src/__tests__/integration/basic/bazar.test.ts new file mode 100644 index 00000000..655587dc --- /dev/null +++ b/src/__tests__/integration/basic/bazar.test.ts @@ -0,0 +1,418 @@ +import fs from 'fs'; + +import ArLocal from 'arlocal'; +import Arweave from 'arweave'; +import { JWKInterface } from 'arweave/node/lib/wallet'; +import path from 'path'; +import { Warp, Contract, LoggerFactory, WarpFactory, defaultCacheOptions, Tag } from 'warp-contracts-rc'; +import { DeployPlugin } from 'warp-contracts-plugin-deploy'; +import { SqliteContractCache } from 'warp-contracts-sqlite'; +import { VM2Plugin } from 'warp-contracts-plugin-vm2'; + +describe('Testing Bazar', () => { + let uSrc: string; + let ucmSrc: string; + let assetSrc: string; + + let wallet: JWKInterface; + let walletAddress: string; + let wallet2: JWKInterface; + let walletAddress2: string; + + let ucmInitialState: any; + let assetInitialState: any; + let uInitialState: any; + + let arweave: Arweave; + let arlocal: ArLocal; + let warp: Warp; + let warpSqlite: Warp; + let ucmContractTxId: string; + let assetContractTxId: string; + let uContractTxId: string; + let ucmContract: Contract; + let assetContract: Contract; + let uContract: Contract; + let ucmContractSqlite: Contract; + let assetContractSqlite: Contract; + let uContractSqlite: Contract; + let allowAssetTxId: string; + let ucmCreateOrderSellResultTxId: string; + let uAllowTxId: string; + + beforeAll(async () => { + // note: each tests suit (i.e. file with tests that Jest is running concurrently + // with another files has to have ArLocal set to a different port!) + arlocal = new ArLocal(1400, false); + await arlocal.start(); + LoggerFactory.INST.logLevel('error'); + + warp = WarpFactory.forLocal(1400).use(new DeployPlugin()); + warpSqlite = WarpFactory.forLocal(1400).useStateCache( + new SqliteContractCache( + { + ...defaultCacheOptions, + dbLocation: `./cache/bazar/sqlite/state` + }, + { + maxEntriesPerContract: 1000 + } + ) + ); + + ({ arweave } = warp); + ({ jwk: wallet, address: walletAddress } = await warp.generateWallet()); + ({ jwk: wallet2, address: walletAddress2 } = await warp.generateWallet()); + + uSrc = fs.readFileSync(path.join(__dirname, '../data/bazar-u.js'), 'utf8'); + ucmSrc = fs.readFileSync(path.join(__dirname, '../data/bazar-ucm.js'), 'utf8'); + assetSrc = fs.readFileSync(path.join(__dirname, '../data/bazar-asset.js'), 'utf8'); + + assetInitialState = { + name: 'Warp Test', + ticker: 'ATOMIC', + balances: { + [walletAddress]: 1000 + }, + claimable: [], + description: 'Warp Heavy Testing.' + }; + + uInitialState = { + name: 'U', + owner: 'jnioZFibZSCcV8o-HkBXYPYEYNib4tqfexP0kCBXX_M', + ticker: 'U', + balances: { + [walletAddress]: 3381632, + [walletAddress2]: 4000666 + }, + settings: [ + ['isTradeable', true], + ['communityLogo', 'J3WXX4OGa6wP5E9oLhNyqlN4deYI7ARjrd5se740ftE'] + ], + claimable: [], + divisibility: 1000000 + }; + + // deploying asset contract using the new SDK. + ({ contractTxId: assetContractTxId } = await warp.deploy({ + wallet, + initState: JSON.stringify(assetInitialState), + src: assetSrc + })); + + // deploying u contract using the new SDK. + ({ contractTxId: uContractTxId } = await warp.deploy({ + wallet, + initState: JSON.stringify(uInitialState), + src: uSrc + })); + + ucmInitialState = { + U: uContractTxId, + name: 'Universal Content Marketplace - Warp Testing', + pairs: [], + ticker: 'PIXL - Warp Testing', + creator: 'jnioZFibZSCcV8o-HkBXYPYEYNib4tqfexP0kCBXX_M', + streaks: {}, + balances: {}, + canEvolve: true, + claimable: [], + lastReward: 0, + contributors: { + tiers: { + one: { + members: { + 'A_nS8Da8uIK6RlC2UkZik2xQ83Lt1jMGin-SCQvoMI4': { + amount: 10, + lastMint: 0 + }, + HnKoL7ftH0BU3eUveKayuLpKu0XPnRehgBPu1GitZsQ: { + amount: 10, + lastMint: 0 + }, + uf_FqRvLqjnFMc8ZzGkF4qWKuNmUIQcYP0tPlCGORQk: { + amount: 10, + lastMint: 0 + }, + 'vh-NTHVvlKZqRxc8LyyTNok65yQ55a_PJ1zWLb9G2JI': { + amount: 10, + lastMint: 0 + } + }, + percent: 50 + }, + two: { + members: { + '9x24zjvs9DA5zAz2DmqBWAg6XcxrrE-8w3EkpwRm4e4': { + amount: 10, + lastMint: 0 + }, + 'OVr8G0X_CaJWfvVdD-ya0My7q6Mzda5Tfa_hqmK3lGA': { + amount: 10, + lastMint: 0 + }, + 'P4oNuLO_5VQb9RIsPGzbPb0HZz-RwfrakxIaXn24KJ0': { + amount: 10, + lastMint: 0 + } + }, + percent: 17 + }, + four: { + members: { + aVkNOVJow0eBcQDzW0Os0NNsAeFtoWE5zAlDpvQ5FDo: { + amount: 10, + lastMint: 0 + } + }, + percent: 30 + }, + three: { + members: { + '89tR0-C1m3_sCWCoVCChg4gFYKdiH5_ZDyZpdJ2DDRw': { + amount: 10, + lastMint: 0 + }, + 'DMyJZy6_C9a-HCfX0A1uogh92VBV1CjUwifXr7NaGsY': { + amount: 10, + lastMint: 0 + }, + 'SMft-XozLyxl0ztM-gPSYKvlZVCBiiftNIb4kGFI7wg': { + amount: 10, + lastMint: 0 + }, + 'vLRHFqCw1uHu75xqB4fCDW-QxpkpJxBtFD9g4QYUbfw': { + amount: 10, + lastMint: 0 + } + }, + percent: 3 + } + }, + percent: 10 + }, + divisibility: 6, + originHeight: 1232615, + transferable: true, + recentRewards: {} + }; + + // deploying UCM contract using the new SDK. + ({ contractTxId: ucmContractTxId } = await warp.deploy({ + wallet, + initState: JSON.stringify(ucmInitialState), + src: ucmSrc + })); + + // connecting to the UCM contract + ucmContract = warp.contract(ucmContractTxId).connect(wallet).setEvaluationOptions({ + internalWrites: true, + unsafeClient: 'skip', + allowBigInt: true + }); + + // connecting to the U contract + uContract = warp.contract(uContractTxId).connect(wallet).setEvaluationOptions({ + internalWrites: true, + unsafeClient: 'skip', + allowBigInt: true + }); + + // connecting to the asset contract + assetContract = warp.contract(assetContractTxId).connect(wallet).setEvaluationOptions({ + internalWrites: true, + unsafeClient: 'skip', + allowBigInt: true + }); + + // connecting to the UCM contract + ucmContractSqlite = warpSqlite.contract(ucmContractTxId).connect(wallet).setEvaluationOptions({ + internalWrites: true, + unsafeClient: 'skip', + allowBigInt: true + }); + + // connecting to the U contract + uContractSqlite = warpSqlite.contract(uContractTxId).connect(wallet).setEvaluationOptions({ + internalWrites: true, + unsafeClient: 'skip', + allowBigInt: true + }); + + // connecting to the asset contract + assetContractSqlite = warpSqlite.contract(assetContractTxId).connect(wallet).setEvaluationOptions({ + internalWrites: true, + unsafeClient: 'skip', + allowBigInt: true + }); + }); + + afterAll(async () => { + await arlocal.stop(); + }); + + it('should add pair in ucm', async () => { + const result = await ucmContract.writeInteraction({ + function: 'addPair', + pair: [assetContractTxId, uContractTxId] + }); + + const { cachedValue } = await ucmContractSqlite.readState(); + + expect(cachedValue.state.pairs[0].pair).toEqual([assetContractTxId, uContractTxId]); + expect(cachedValue.validity[result!!.originalTxId]).toBe(true); + }); + + it('should set allowance on asset contract', async () => { + const result = await assetContract.writeInteraction( + { + function: 'allow', + target: ucmContractTxId, + qty: 100 + }, + { tags: [new Tag('Indexed-By', 'ucm')] } + ); + + allowAssetTxId = result!!.originalTxId; + + const { cachedValue } = await assetContractSqlite.readState(); + expect(JSON.stringify(cachedValue.state['claimable'][0])).toBe( + JSON.stringify({ + from: walletAddress, + to: ucmContractTxId, + qty: 100, + txID: result?.originalTxId + }) + ); + expect(cachedValue.validity[result!!.originalTxId]).toBe(true); + }); + + it('should set asset for sale', async () => { + const result = await ucmContract.writeInteraction({ + function: 'createOrder', + pair: [assetContractTxId, uContractTxId], + transaction: allowAssetTxId, + qty: 100, + price: 20000 + }); + + ucmCreateOrderSellResultTxId = result!!.originalTxId; + + const { cachedValue: cachedValueUcm } = await ucmContractSqlite.readState(); + // const { cachedValue: cachedValueAsset } = await assetContractSqlite.readState(); + + expect(JSON.stringify(cachedValueUcm.state.pairs[0].orders[0])).toBe( + JSON.stringify({ + id: ucmCreateOrderSellResultTxId, + transfer: allowAssetTxId, + creator: walletAddress, + token: assetContractTxId, + price: 20000, + quantity: 100, + originalQuantity: 100 + }) + ); + const cachedAssetState = (await warpSqlite.stateEvaluator.getCache().getLast(assetContractTxId)) as any; + expect(cachedAssetState.cachedValue.state.balances[ucmContractTxId]).toBe(100); + expect(cachedAssetState?.cachedValue.state.balances[walletAddress]).toBe(900); + expect(cachedAssetState.cachedValue.state['claimable'].length).toBe(0); + + expect(cachedValueUcm.validity[result!!.originalTxId]).toBe(true); + expect(cachedAssetState.cachedValue.validity[result!!.originalTxId]).toBe(true); + }); + + it('should correctly cancel order', async () => { + const result = await ucmContract.writeInteraction({ + function: 'cancelOrder', + orderID: ucmCreateOrderSellResultTxId + }); + + const { cachedValue } = await ucmContractSqlite.readState(); + + expect(cachedValue.state.pairs[0].orders.length).toEqual(0); + + // const { cachedValue: cachedValueAsset } = await assetContractSqlite.readState(); + const cachedAssetState = (await warpSqlite.stateEvaluator.getCache().getLast(assetContractTxId)) as any; + expect(cachedAssetState.cachedValue.state.balances[ucmContractTxId]).toBe(0); + expect(cachedAssetState.cachedValue.state.balances[walletAddress]).toBe(1000); + + expect(cachedAssetState.cachedValue.validity[result!!.originalTxId]).toBe(true); + expect(cachedValue.validity[result!!.originalTxId]).toBe(true); + }); + + it('should correctly set asset for sale and set allowance on U', async () => { + const allowResult = await assetContract.writeInteraction( + { + function: 'allow', + target: ucmContractTxId, + qty: 100 + }, + { tags: [new Tag('Indexed-By', 'ucm')] } + ); + + const result = await ucmContract.writeInteraction({ + function: 'createOrder', + pair: [assetContractTxId, uContractTxId], + transaction: allowResult?.originalTxId, + qty: 100, + price: 20000 + }); + + const wallet2uContract = warp.contract(uContractTxId).connect(wallet2).setEvaluationOptions({ + internalWrites: true, + unsafeClient: 'skip', + allowBigInt: true + }); + const uAllowResult = await wallet2uContract.writeInteraction({ + function: 'allow', + qty: 20000, + target: ucmContractTxId + }); + + uAllowTxId = uAllowResult!!.originalTxId; + + const { cachedValue } = await uContractSqlite.readState(); + expect(JSON.stringify(cachedValue.state['claimable'][0])).toBe( + JSON.stringify({ + from: walletAddress2, + to: ucmContractTxId, + qty: 20000, + txID: uAllowResult?.originalTxId + }) + ); + expect(cachedValue.validity[uAllowResult!!.originalTxId]).toBe(true); + }); + + it('should sell asset', async () => { + const wallet2UcmContract = warp.contract(ucmContractTxId).connect(wallet2).setEvaluationOptions({ + internalWrites: true, + unsafeClient: 'skip', + allowBigInt: true + }); + const wallet2UcmContractSqlite = warpSqlite.contract(ucmContractTxId).connect(wallet2).setEvaluationOptions({ + internalWrites: true, + unsafeClient: 'skip', + allowBigInt: true + }); + await wallet2UcmContract.writeInteraction({ + function: 'createOrder', + pair: [uContractTxId, assetContractTxId], + transaction: uAllowTxId, + qty: 20000 + }); + + // const { cachedValue: uCachedValue } = await uContractSqlite.readState(); + // const { cachedValue: assetCachedValue } = await assetContractSqlite.readState(); + const { cachedValue: ucmCachedValue } = await wallet2UcmContractSqlite.readState(); + const cachedAssetState = (await warpSqlite.stateEvaluator.getCache().getLast(assetContractTxId)) as any; + const cachedUState = (await warpSqlite.stateEvaluator.getCache().getLast(uContractTxId)) as any; + + expect(cachedUState.cachedValue.state['claimable'].length).toBe(0); + expect(cachedAssetState.cachedValue.state.balances[ucmContractTxId]).toBe(99); + expect(cachedAssetState.cachedValue.state.balances[walletAddress]).toBe(900); + expect(cachedAssetState.cachedValue.state.balances[walletAddress2]).toBe(1); + expect(cachedUState.cachedValue.state.balances[walletAddress2]).toBe(3980666); + expect(ucmCachedValue.state['pairs'][0]['orders'][0]['quantity']).toBe(99); + }); +}); diff --git a/src/__tests__/integration/data/bazar-asset.js b/src/__tests__/integration/data/bazar-asset.js new file mode 100644 index 00000000..1e00fa1a --- /dev/null +++ b/src/__tests__/integration/data/bazar-asset.js @@ -0,0 +1,238 @@ +// src/write/constructor.js +function constructor(state, action) { + if (action.input.args) { + state = action.input.args; + } + if (!state.claimable) { + state.claimable = []; + } + if (!state.balances) { + state.balances = {}; + } + if (!action.input?.args?.balances) { + state.balances[action.caller] = 100; + } + state.name = action.input?.args?.name ? action.input.args.name : "AtomicAsset"; + state.ticker = action.input?.args?.ticker ? action.input.args.ticker : "AA"; + return { state }; +} + +// src/lib/either.js +var Right = (x) => ({ + isLeft: false, + chain: (f) => f(x), + ap: (other) => other.map(x), + alt: (other) => Right(x), + extend: (f) => f(Right(x)), + concat: (other) => other.fold( + (x2) => other, + (y) => Right(x.concat(y)) + ), + traverse: (of2, f) => f(x).map(Right), + map: (f) => Right(f(x)), + fold: (_, g) => g(x), + toString: () => `Right(${x})`, + extract: () => x +}); +var Left = (x) => ({ + isLeft: true, + chain: (_) => Left(x), + ap: (_) => Left(x), + extend: (_) => Left(x), + alt: (other) => other, + concat: (_) => Left(x), + traverse: (of2, _) => of2(Left(x)), + map: (_) => Left(x), + fold: (f, _) => f(x), + toString: () => `Left(${x})`, + extract: () => x +}); +var of = Right; +var fromNullable = (x) => x != null ? Right(x) : Left(x); + +// src/read/balance.js +var balance = (state, action) => of({ state, action }).chain(validate).map(readBalance); +function validate({ state, action }) { + if (!action.input.target) { + action.input.target = action.caller; + } + if (action.input.target.length !== 43) { + return Left("Target is not valid"); + } + return Right({ state, action }); +} +function readBalance({ state, action }) { + return { + result: { + target: action.input.target, + balance: state.balances[action.input.target] || 0 + } + }; +} + +// src/write/allow.js +var allow = (state, action) => of({ state, action }).chain(validate2).map(update); +function update({ state, action }) { + state.balances[action.caller] -= action.input.qty; + if (!state.claimable) { + state.claimable = []; + } + state.claimable.push({ + from: action.caller, + to: action.input.target, + qty: action.input.qty, + txID: SmartWeave.transaction.id + }); + return { state }; +} +function validate2({ state, action }) { + if (!Number.isInteger(action.input.qty) || action.input.qty === void 0) { + return Left("Invalid value for quantity. Must be an integer."); + } + if (!action?.input?.target) { + return Left("No target specified."); + } + if (action.input.target.length !== 43) { + return Left("Target is not valid!"); + } + if (action.input.target === SmartWeave.transaction.id) { + return Left("Cant setup claim to transfer a balance to itself"); + } + if (action.caller === action.input.target) { + return Left("Invalid balance transfer"); + } + if (!state.balances[action.caller]) { + return Left("Caller does not have a balance"); + } + if (state.balances[action.caller] < action.input.qty) { + return Left("Caller balance is not high enough."); + } + return Right({ state, action }); +} + +// src/write/claim.js +var claim = (state, action) => of({ state, action }).chain(validate3).map(update2); +function update2({ state, action, idx }) { + if (!state.balances[action.caller]) { + state.balances[action.caller] = 0; + } + state.balances[action.caller] += action.input.qty; + state.claimable.splice(idx, 1); + return { state }; +} +function validate3({ state, action }) { + if (!action.input.txID) { + return Left("txID is not found."); + } + if (!action.input.qty) { + return Left("claim quantity is not specified."); + } + const idx = state.claimable.findIndex( + (c) => c.txID === action.input.txID + ); + if (idx < 0) { + return Left("claimable not found."); + } + if (state.claimable[idx].qty !== action.input.qty) { + return Left("claimable qty is not equal to claim qty."); + } + if (state.claimable[idx].to !== action.caller) { + return Left("claim is not addressed to caller."); + } + return Right({ state, action, idx }); +} + +// src/write/transfer.js +var transfer = (state, action) => of({ state, action }).chain(validate4).map(update3); +function update3({ state, action }) { + state.balances[action.caller] -= action.input.qty; + state.balances[action.input.target] += action.input.qty; + return { state }; +} +function validate4({ state, action }) { + if (!action.caller || action.caller.length !== 43) { + return Left("Caller is not valid"); + } + if (!action.input.qty || typeof action.input.qty !== "number") { + return Left("qty is not defined or is not a number"); + } + if (!action.input.target || action.input.target.length !== 43) { + return Left("target is not valid"); + } + if (action.caller === action.input.target) { + return Left("target cannot be caller"); + } + if (!state.balances[action.input.target]) { + state.balances[action.input.target] = 0; + } + if (!state.balances[action.caller]) { + state.balances[action.caller] = 0; + } + if (state.balances[action.caller] < action.input.qty) { + return Left("not enough balance to transfer"); + } + return Right({ state, action }); +} + +// src/write/reject.js +function reject(state, action) { + return fromNullable({ state, action }).chain(validate5).map(update4); +} +function update4({ state, action }) { + const claim2 = state.claimable.find((c) => c.txID === action.input.tx); + if (!state.balances[claim2.from]) { + state.balances[claim2.from] = 0; + } + state.balances[claim2.from] += claim2.qty; + state.claimable = state.claimable.filter((c) => c.txID !== claim2.txID); + return { state }; +} +function validate5({ state, action }) { + if (!action.input.tx) { + return Left("tx is required!"); + } + if (!action.input.qty) { + return Left("qty is required!"); + } + if (action.input.tx.length !== 43) { + return Left("tx is not valid"); + } + if (!Number.isInteger(action.input.qty)) { + return Left("qty must be an integer"); + } + if (state.claimable.filter((c) => c.txID === action.input.tx).length !== 1) { + return Left("claim not found"); + } + if (state.claimable.filter((c) => c.txID === action.input.tx)[0]?.to !== action.caller) { + return Left("claim in not addressed to caller"); + } + return Right({ state, action }); +} + +// src/contract.js +export async function handle(state, action) { + switch (action.input?.function) { + case "noop": + return { state }; + case "__init": + return constructor(state, action); + case "balance": + return balance(state, action).fold(handleError, identity); + case "transfer": + return transfer(state, action).fold(handleError, identity); + case "allow": + return allow(state, action).fold(handleError, identity); + case "reject": + return reject(state, action).fold(handleError, identity); + case "claim": + return claim(state, action).fold(handleError, identity); + default: + throw new ContractError("Function not found"); + } +} +function identity(v) { + return v; +} +function handleError(msg) { + throw new ContractError(msg); +} diff --git a/src/__tests__/integration/data/bazar-u.js b/src/__tests__/integration/data/bazar-u.js new file mode 100644 index 00000000..c0918adf --- /dev/null +++ b/src/__tests__/integration/data/bazar-u.js @@ -0,0 +1,1803 @@ +// src/read/balance.js +async function balance(state, action) { + const addr = action?.input?.target || action.caller; + return { + result: { + target: addr, + ticker: state.ticker, + balance: state.balances[addr] || 0 + } + }; +} + +// src/hyper-either.js +var Right = (x) => ({ + isLeft: false, + chain: (f) => f(x), + ap: (other) => other.map(x), + alt: (other) => Right(x), + extend: (f) => f(Right(x)), + concat: (other) => + other.fold( + (x2) => other, + (y) => Right(x.concat(y)) + ), + traverse: (of2, f) => f(x).map(Right), + map: (f) => Right(f(x)), + fold: (_, g) => g(x), + toString: () => `Right(${x})`, + extract: () => x +}); +var Left = (x) => ({ + isLeft: true, + chain: (_) => Left(x), + ap: (_) => Left(x), + extend: (_) => Left(x), + alt: (other) => other, + concat: (_) => Left(x), + traverse: (of2, _) => of2(Left(x)), + map: (_) => Left(x), + fold: (f, _) => f(x), + toString: () => `Left(${x})`, + extract: () => x +}); +var of = Right; +var fromNullable = (x) => (x != null ? Right(x) : Left(x)); + +// node_modules/bignumber.js/bignumber.mjs +var isNumeric = /^-?(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?$/i; +var mathceil = Math.ceil; +var mathfloor = Math.floor; +var bignumberError = '[BigNumber Error] '; +var tooManyDigits = bignumberError + 'Number primitive has more than 15 significant digits: '; +var BASE = 1e14; +var LOG_BASE = 14; +var MAX_SAFE_INTEGER = 9007199254740991; +var POWS_TEN = [1, 10, 100, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13]; +var SQRT_BASE = 1e7; +var MAX = 1e9; +function clone(configObject) { + var div, + convertBase, + parseNumeric, + P = (BigNumber2.prototype = { constructor: BigNumber2, toString: null, valueOf: null }), + ONE = new BigNumber2(1), + DECIMAL_PLACES = 20, + ROUNDING_MODE = 4, + TO_EXP_NEG = -7, + TO_EXP_POS = 21, + MIN_EXP = -1e7, + MAX_EXP = 1e7, + CRYPTO = false, + MODULO_MODE = 1, + POW_PRECISION = 0, + FORMAT = { + prefix: '', + groupSize: 3, + secondaryGroupSize: 0, + groupSeparator: ',', + decimalSeparator: '.', + fractionGroupSize: 0, + fractionGroupSeparator: '\xA0', + // non-breaking space + suffix: '' + }, + ALPHABET = '0123456789abcdefghijklmnopqrstuvwxyz', + alphabetHasNormalDecimalDigits = true; + function BigNumber2(v, b) { + var alphabet, + c, + caseChanged, + e, + i, + isNum, + len, + str, + x = this; + if (!(x instanceof BigNumber2)) return new BigNumber2(v, b); + if (b == null) { + if (v && v._isBigNumber === true) { + x.s = v.s; + if (!v.c || v.e > MAX_EXP) { + x.c = x.e = null; + } else if (v.e < MIN_EXP) { + x.c = [(x.e = 0)]; + } else { + x.e = v.e; + x.c = v.c.slice(); + } + return; + } + if ((isNum = typeof v == 'number') && v * 0 == 0) { + x.s = 1 / v < 0 ? ((v = -v), -1) : 1; + if (v === ~~v) { + for (e = 0, i = v; i >= 10; i /= 10, e++); + if (e > MAX_EXP) { + x.c = x.e = null; + } else { + x.e = e; + x.c = [v]; + } + return; + } + str = String(v); + } else { + if (!isNumeric.test((str = String(v)))) return parseNumeric(x, str, isNum); + x.s = str.charCodeAt(0) == 45 ? ((str = str.slice(1)), -1) : 1; + } + if ((e = str.indexOf('.')) > -1) str = str.replace('.', ''); + if ((i = str.search(/e/i)) > 0) { + if (e < 0) e = i; + e += +str.slice(i + 1); + str = str.substring(0, i); + } else if (e < 0) { + e = str.length; + } + } else { + intCheck(b, 2, ALPHABET.length, 'Base'); + if (b == 10 && alphabetHasNormalDecimalDigits) { + x = new BigNumber2(v); + return round(x, DECIMAL_PLACES + x.e + 1, ROUNDING_MODE); + } + str = String(v); + if ((isNum = typeof v == 'number')) { + if (v * 0 != 0) return parseNumeric(x, str, isNum, b); + x.s = 1 / v < 0 ? ((str = str.slice(1)), -1) : 1; + if (BigNumber2.DEBUG && str.replace(/^0\.0*|\./, '').length > 15) { + throw Error(tooManyDigits + v); + } + } else { + x.s = str.charCodeAt(0) === 45 ? ((str = str.slice(1)), -1) : 1; + } + alphabet = ALPHABET.slice(0, b); + e = i = 0; + for (len = str.length; i < len; i++) { + if (alphabet.indexOf((c = str.charAt(i))) < 0) { + if (c == '.') { + if (i > e) { + e = len; + continue; + } + } else if (!caseChanged) { + if ( + (str == str.toUpperCase() && (str = str.toLowerCase())) || + (str == str.toLowerCase() && (str = str.toUpperCase())) + ) { + caseChanged = true; + i = -1; + e = 0; + continue; + } + } + return parseNumeric(x, String(v), isNum, b); + } + } + isNum = false; + str = convertBase(str, b, 10, x.s); + if ((e = str.indexOf('.')) > -1) str = str.replace('.', ''); + else e = str.length; + } + for (i = 0; str.charCodeAt(i) === 48; i++); + for (len = str.length; str.charCodeAt(--len) === 48; ); + if ((str = str.slice(i, ++len))) { + len -= i; + if (isNum && BigNumber2.DEBUG && len > 15 && (v > MAX_SAFE_INTEGER || v !== mathfloor(v))) { + throw Error(tooManyDigits + x.s * v); + } + if ((e = e - i - 1) > MAX_EXP) { + x.c = x.e = null; + } else if (e < MIN_EXP) { + x.c = [(x.e = 0)]; + } else { + x.e = e; + x.c = []; + i = (e + 1) % LOG_BASE; + if (e < 0) i += LOG_BASE; + if (i < len) { + if (i) x.c.push(+str.slice(0, i)); + for (len -= LOG_BASE; i < len; ) { + x.c.push(+str.slice(i, (i += LOG_BASE))); + } + i = LOG_BASE - (str = str.slice(i)).length; + } else { + i -= len; + } + for (; i--; str += '0'); + x.c.push(+str); + } + } else { + x.c = [(x.e = 0)]; + } + } + BigNumber2.clone = clone; + BigNumber2.ROUND_UP = 0; + BigNumber2.ROUND_DOWN = 1; + BigNumber2.ROUND_CEIL = 2; + BigNumber2.ROUND_FLOOR = 3; + BigNumber2.ROUND_HALF_UP = 4; + BigNumber2.ROUND_HALF_DOWN = 5; + BigNumber2.ROUND_HALF_EVEN = 6; + BigNumber2.ROUND_HALF_CEIL = 7; + BigNumber2.ROUND_HALF_FLOOR = 8; + BigNumber2.EUCLID = 9; + BigNumber2.config = BigNumber2.set = function (obj) { + var p, v; + if (obj != null) { + if (typeof obj == 'object') { + if (obj.hasOwnProperty((p = 'DECIMAL_PLACES'))) { + v = obj[p]; + intCheck(v, 0, MAX, p); + DECIMAL_PLACES = v; + } + if (obj.hasOwnProperty((p = 'ROUNDING_MODE'))) { + v = obj[p]; + intCheck(v, 0, 8, p); + ROUNDING_MODE = v; + } + if (obj.hasOwnProperty((p = 'EXPONENTIAL_AT'))) { + v = obj[p]; + if (v && v.pop) { + intCheck(v[0], -MAX, 0, p); + intCheck(v[1], 0, MAX, p); + TO_EXP_NEG = v[0]; + TO_EXP_POS = v[1]; + } else { + intCheck(v, -MAX, MAX, p); + TO_EXP_NEG = -(TO_EXP_POS = v < 0 ? -v : v); + } + } + if (obj.hasOwnProperty((p = 'RANGE'))) { + v = obj[p]; + if (v && v.pop) { + intCheck(v[0], -MAX, -1, p); + intCheck(v[1], 1, MAX, p); + MIN_EXP = v[0]; + MAX_EXP = v[1]; + } else { + intCheck(v, -MAX, MAX, p); + if (v) { + MIN_EXP = -(MAX_EXP = v < 0 ? -v : v); + } else { + throw Error(bignumberError + p + ' cannot be zero: ' + v); + } + } + } + if (obj.hasOwnProperty((p = 'CRYPTO'))) { + v = obj[p]; + if (v === !!v) { + if (v) { + if (typeof crypto != 'undefined' && crypto && (crypto.getRandomValues || crypto.randomBytes)) { + CRYPTO = v; + } else { + CRYPTO = !v; + throw Error(bignumberError + 'crypto unavailable'); + } + } else { + CRYPTO = v; + } + } else { + throw Error(bignumberError + p + ' not true or false: ' + v); + } + } + if (obj.hasOwnProperty((p = 'MODULO_MODE'))) { + v = obj[p]; + intCheck(v, 0, 9, p); + MODULO_MODE = v; + } + if (obj.hasOwnProperty((p = 'POW_PRECISION'))) { + v = obj[p]; + intCheck(v, 0, MAX, p); + POW_PRECISION = v; + } + if (obj.hasOwnProperty((p = 'FORMAT'))) { + v = obj[p]; + if (typeof v == 'object') FORMAT = v; + else throw Error(bignumberError + p + ' not an object: ' + v); + } + if (obj.hasOwnProperty((p = 'ALPHABET'))) { + v = obj[p]; + if (typeof v == 'string' && !/^.?$|[+\-.\s]|(.).*\1/.test(v)) { + alphabetHasNormalDecimalDigits = v.slice(0, 10) == '0123456789'; + ALPHABET = v; + } else { + throw Error(bignumberError + p + ' invalid: ' + v); + } + } + } else { + throw Error(bignumberError + 'Object expected: ' + obj); + } + } + return { + DECIMAL_PLACES, + ROUNDING_MODE, + EXPONENTIAL_AT: [TO_EXP_NEG, TO_EXP_POS], + RANGE: [MIN_EXP, MAX_EXP], + CRYPTO, + MODULO_MODE, + POW_PRECISION, + FORMAT, + ALPHABET + }; + }; + BigNumber2.isBigNumber = function (v) { + if (!v || v._isBigNumber !== true) return false; + if (!BigNumber2.DEBUG) return true; + var i, + n, + c = v.c, + e = v.e, + s = v.s; + out: if ({}.toString.call(c) == '[object Array]') { + if ((s === 1 || s === -1) && e >= -MAX && e <= MAX && e === mathfloor(e)) { + if (c[0] === 0) { + if (e === 0 && c.length === 1) return true; + break out; + } + i = (e + 1) % LOG_BASE; + if (i < 1) i += LOG_BASE; + if (String(c[0]).length == i) { + for (i = 0; i < c.length; i++) { + n = c[i]; + if (n < 0 || n >= BASE || n !== mathfloor(n)) break out; + } + if (n !== 0) return true; + } + } + } else if (c === null && e === null && (s === null || s === 1 || s === -1)) { + return true; + } + throw Error(bignumberError + 'Invalid BigNumber: ' + v); + }; + BigNumber2.maximum = BigNumber2.max = function () { + return maxOrMin(arguments, P.lt); + }; + BigNumber2.minimum = BigNumber2.min = function () { + return maxOrMin(arguments, P.gt); + }; + BigNumber2.random = (function () { + var pow2_53 = 9007199254740992; + var random53bitInt = + (Math.random() * pow2_53) & 2097151 + ? function () { + return mathfloor(Math.random() * pow2_53); + } + : function () { + return ((Math.random() * 1073741824) | 0) * 8388608 + ((Math.random() * 8388608) | 0); + }; + return function (dp) { + var a, + b, + e, + k, + v, + i = 0, + c = [], + rand = new BigNumber2(ONE); + if (dp == null) dp = DECIMAL_PLACES; + else intCheck(dp, 0, MAX); + k = mathceil(dp / LOG_BASE); + if (CRYPTO) { + if (crypto.getRandomValues) { + a = crypto.getRandomValues(new Uint32Array((k *= 2))); + for (; i < k; ) { + v = a[i] * 131072 + (a[i + 1] >>> 11); + if (v >= 9e15) { + b = crypto.getRandomValues(new Uint32Array(2)); + a[i] = b[0]; + a[i + 1] = b[1]; + } else { + c.push(v % 1e14); + i += 2; + } + } + i = k / 2; + } else if (crypto.randomBytes) { + a = crypto.randomBytes((k *= 7)); + for (; i < k; ) { + v = + (a[i] & 31) * 281474976710656 + + a[i + 1] * 1099511627776 + + a[i + 2] * 4294967296 + + a[i + 3] * 16777216 + + (a[i + 4] << 16) + + (a[i + 5] << 8) + + a[i + 6]; + if (v >= 9e15) { + crypto.randomBytes(7).copy(a, i); + } else { + c.push(v % 1e14); + i += 7; + } + } + i = k / 7; + } else { + CRYPTO = false; + throw Error(bignumberError + 'crypto unavailable'); + } + } + if (!CRYPTO) { + for (; i < k; ) { + v = random53bitInt(); + if (v < 9e15) c[i++] = v % 1e14; + } + } + k = c[--i]; + dp %= LOG_BASE; + if (k && dp) { + v = POWS_TEN[LOG_BASE - dp]; + c[i] = mathfloor(k / v) * v; + } + for (; c[i] === 0; c.pop(), i--); + if (i < 0) { + c = [(e = 0)]; + } else { + for (e = -1; c[0] === 0; c.splice(0, 1), e -= LOG_BASE); + for (i = 1, v = c[0]; v >= 10; v /= 10, i++); + if (i < LOG_BASE) e -= LOG_BASE - i; + } + rand.e = e; + rand.c = c; + return rand; + }; + })(); + BigNumber2.sum = function () { + var i = 1, + args = arguments, + sum = new BigNumber2(args[0]); + for (; i < args.length; ) sum = sum.plus(args[i++]); + return sum; + }; + convertBase = (function () { + var decimal = '0123456789'; + function toBaseOut(str, baseIn, baseOut, alphabet) { + var j, + arr = [0], + arrL, + i = 0, + len = str.length; + for (; i < len; ) { + for (arrL = arr.length; arrL--; arr[arrL] *= baseIn); + arr[0] += alphabet.indexOf(str.charAt(i++)); + for (j = 0; j < arr.length; j++) { + if (arr[j] > baseOut - 1) { + if (arr[j + 1] == null) arr[j + 1] = 0; + arr[j + 1] += (arr[j] / baseOut) | 0; + arr[j] %= baseOut; + } + } + } + return arr.reverse(); + } + return function (str, baseIn, baseOut, sign, callerIsToString) { + var alphabet, + d, + e, + k, + r, + x, + xc, + y, + i = str.indexOf('.'), + dp = DECIMAL_PLACES, + rm = ROUNDING_MODE; + if (i >= 0) { + k = POW_PRECISION; + POW_PRECISION = 0; + str = str.replace('.', ''); + y = new BigNumber2(baseIn); + x = y.pow(str.length - i); + POW_PRECISION = k; + y.c = toBaseOut(toFixedPoint(coeffToString(x.c), x.e, '0'), 10, baseOut, decimal); + y.e = y.c.length; + } + xc = toBaseOut( + str, + baseIn, + baseOut, + callerIsToString ? ((alphabet = ALPHABET), decimal) : ((alphabet = decimal), ALPHABET) + ); + e = k = xc.length; + for (; xc[--k] == 0; xc.pop()); + if (!xc[0]) return alphabet.charAt(0); + if (i < 0) { + --e; + } else { + x.c = xc; + x.e = e; + x.s = sign; + x = div(x, y, dp, rm, baseOut); + xc = x.c; + r = x.r; + e = x.e; + } + d = e + dp + 1; + i = xc[d]; + k = baseOut / 2; + r = r || d < 0 || xc[d + 1] != null; + r = + rm < 4 + ? (i != null || r) && (rm == 0 || rm == (x.s < 0 ? 3 : 2)) + : i > k || (i == k && (rm == 4 || r || (rm == 6 && xc[d - 1] & 1) || rm == (x.s < 0 ? 8 : 7))); + if (d < 1 || !xc[0]) { + str = r ? toFixedPoint(alphabet.charAt(1), -dp, alphabet.charAt(0)) : alphabet.charAt(0); + } else { + xc.length = d; + if (r) { + for (--baseOut; ++xc[--d] > baseOut; ) { + xc[d] = 0; + if (!d) { + ++e; + xc = [1].concat(xc); + } + } + } + for (k = xc.length; !xc[--k]; ); + for (i = 0, str = ''; i <= k; str += alphabet.charAt(xc[i++])); + str = toFixedPoint(str, e, alphabet.charAt(0)); + } + return str; + }; + })(); + div = (function () { + function multiply(x, k, base) { + var m, + temp, + xlo, + xhi, + carry = 0, + i = x.length, + klo = k % SQRT_BASE, + khi = (k / SQRT_BASE) | 0; + for (x = x.slice(); i--; ) { + xlo = x[i] % SQRT_BASE; + xhi = (x[i] / SQRT_BASE) | 0; + m = khi * xlo + xhi * klo; + temp = klo * xlo + (m % SQRT_BASE) * SQRT_BASE + carry; + carry = ((temp / base) | 0) + ((m / SQRT_BASE) | 0) + khi * xhi; + x[i] = temp % base; + } + if (carry) x = [carry].concat(x); + return x; + } + function compare2(a, b, aL, bL) { + var i, cmp; + if (aL != bL) { + cmp = aL > bL ? 1 : -1; + } else { + for (i = cmp = 0; i < aL; i++) { + if (a[i] != b[i]) { + cmp = a[i] > b[i] ? 1 : -1; + break; + } + } + } + return cmp; + } + function subtract(a, b, aL, base) { + var i = 0; + for (; aL--; ) { + a[aL] -= i; + i = a[aL] < b[aL] ? 1 : 0; + a[aL] = i * base + a[aL] - b[aL]; + } + for (; !a[0] && a.length > 1; a.splice(0, 1)); + } + return function (x, y, dp, rm, base) { + var cmp, + e, + i, + more, + n, + prod, + prodL, + q, + qc, + rem, + remL, + rem0, + xi, + xL, + yc0, + yL, + yz, + s = x.s == y.s ? 1 : -1, + xc = x.c, + yc = y.c; + if (!xc || !xc[0] || !yc || !yc[0]) { + return new BigNumber2( + // Return NaN if either NaN, or both Infinity or 0. + !x.s || !y.s || (xc ? yc && xc[0] == yc[0] : !yc) + ? NaN + : // Return ±0 if x is ±0 or y is ±Infinity, or return ±Infinity as y is ±0. + (xc && xc[0] == 0) || !yc + ? s * 0 + : s / 0 + ); + } + q = new BigNumber2(s); + qc = q.c = []; + e = x.e - y.e; + s = dp + e + 1; + if (!base) { + base = BASE; + e = bitFloor(x.e / LOG_BASE) - bitFloor(y.e / LOG_BASE); + s = (s / LOG_BASE) | 0; + } + for (i = 0; yc[i] == (xc[i] || 0); i++); + if (yc[i] > (xc[i] || 0)) e--; + if (s < 0) { + qc.push(1); + more = true; + } else { + xL = xc.length; + yL = yc.length; + i = 0; + s += 2; + n = mathfloor(base / (yc[0] + 1)); + if (n > 1) { + yc = multiply(yc, n, base); + xc = multiply(xc, n, base); + yL = yc.length; + xL = xc.length; + } + xi = yL; + rem = xc.slice(0, yL); + remL = rem.length; + for (; remL < yL; rem[remL++] = 0); + yz = yc.slice(); + yz = [0].concat(yz); + yc0 = yc[0]; + if (yc[1] >= base / 2) yc0++; + do { + n = 0; + cmp = compare2(yc, rem, yL, remL); + if (cmp < 0) { + rem0 = rem[0]; + if (yL != remL) rem0 = rem0 * base + (rem[1] || 0); + n = mathfloor(rem0 / yc0); + if (n > 1) { + if (n >= base) n = base - 1; + prod = multiply(yc, n, base); + prodL = prod.length; + remL = rem.length; + while (compare2(prod, rem, prodL, remL) == 1) { + n--; + subtract(prod, yL < prodL ? yz : yc, prodL, base); + prodL = prod.length; + cmp = 1; + } + } else { + if (n == 0) { + cmp = n = 1; + } + prod = yc.slice(); + prodL = prod.length; + } + if (prodL < remL) prod = [0].concat(prod); + subtract(rem, prod, remL, base); + remL = rem.length; + if (cmp == -1) { + while (compare2(yc, rem, yL, remL) < 1) { + n++; + subtract(rem, yL < remL ? yz : yc, remL, base); + remL = rem.length; + } + } + } else if (cmp === 0) { + n++; + rem = [0]; + } + qc[i++] = n; + if (rem[0]) { + rem[remL++] = xc[xi] || 0; + } else { + rem = [xc[xi]]; + remL = 1; + } + } while ((xi++ < xL || rem[0] != null) && s--); + more = rem[0] != null; + if (!qc[0]) qc.splice(0, 1); + } + if (base == BASE) { + for (i = 1, s = qc[0]; s >= 10; s /= 10, i++); + round(q, dp + (q.e = i + e * LOG_BASE - 1) + 1, rm, more); + } else { + q.e = e; + q.r = +more; + } + return q; + }; + })(); + function format(n, i, rm, id) { + var c0, e, ne, len, str; + if (rm == null) rm = ROUNDING_MODE; + else intCheck(rm, 0, 8); + if (!n.c) return n.toString(); + c0 = n.c[0]; + ne = n.e; + if (i == null) { + str = coeffToString(n.c); + str = + id == 1 || (id == 2 && (ne <= TO_EXP_NEG || ne >= TO_EXP_POS)) + ? toExponential(str, ne) + : toFixedPoint(str, ne, '0'); + } else { + n = round(new BigNumber2(n), i, rm); + e = n.e; + str = coeffToString(n.c); + len = str.length; + if (id == 1 || (id == 2 && (i <= e || e <= TO_EXP_NEG))) { + for (; len < i; str += '0', len++); + str = toExponential(str, e); + } else { + i -= ne; + str = toFixedPoint(str, e, '0'); + if (e + 1 > len) { + if (--i > 0) for (str += '.'; i--; str += '0'); + } else { + i += e - len; + if (i > 0) { + if (e + 1 == len) str += '.'; + for (; i--; str += '0'); + } + } + } + } + return n.s < 0 && c0 ? '-' + str : str; + } + function maxOrMin(args, method) { + var n, + i = 1, + m = new BigNumber2(args[0]); + for (; i < args.length; i++) { + n = new BigNumber2(args[i]); + if (!n.s) { + m = n; + break; + } else if (method.call(m, n)) { + m = n; + } + } + return m; + } + function normalise(n, c, e) { + var i = 1, + j = c.length; + for (; !c[--j]; c.pop()); + for (j = c[0]; j >= 10; j /= 10, i++); + if ((e = i + e * LOG_BASE - 1) > MAX_EXP) { + n.c = n.e = null; + } else if (e < MIN_EXP) { + n.c = [(n.e = 0)]; + } else { + n.e = e; + n.c = c; + } + return n; + } + parseNumeric = (function () { + var basePrefix = /^(-?)0([xbo])(?=\w[\w.]*$)/i, + dotAfter = /^([^.]+)\.$/, + dotBefore = /^\.([^.]+)$/, + isInfinityOrNaN = /^-?(Infinity|NaN)$/, + whitespaceOrPlus = /^\s*\+(?=[\w.])|^\s+|\s+$/g; + return function (x, str, isNum, b) { + var base, + s = isNum ? str : str.replace(whitespaceOrPlus, ''); + if (isInfinityOrNaN.test(s)) { + x.s = isNaN(s) ? null : s < 0 ? -1 : 1; + } else { + if (!isNum) { + s = s.replace(basePrefix, function (m, p1, p2) { + base = (p2 = p2.toLowerCase()) == 'x' ? 16 : p2 == 'b' ? 2 : 8; + return !b || b == base ? p1 : m; + }); + if (b) { + base = b; + s = s.replace(dotAfter, '$1').replace(dotBefore, '0.$1'); + } + if (str != s) return new BigNumber2(s, base); + } + if (BigNumber2.DEBUG) { + throw Error(bignumberError + 'Not a' + (b ? ' base ' + b : '') + ' number: ' + str); + } + x.s = null; + } + x.c = x.e = null; + }; + })(); + function round(x, sd, rm, r) { + var d, + i, + j, + k, + n, + ni, + rd, + xc = x.c, + pows10 = POWS_TEN; + if (xc) { + out: { + for (d = 1, k = xc[0]; k >= 10; k /= 10, d++); + i = sd - d; + if (i < 0) { + i += LOG_BASE; + j = sd; + n = xc[(ni = 0)]; + rd = (n / pows10[d - j - 1]) % 10 | 0; + } else { + ni = mathceil((i + 1) / LOG_BASE); + if (ni >= xc.length) { + if (r) { + for (; xc.length <= ni; xc.push(0)); + n = rd = 0; + d = 1; + i %= LOG_BASE; + j = i - LOG_BASE + 1; + } else { + break out; + } + } else { + n = k = xc[ni]; + for (d = 1; k >= 10; k /= 10, d++); + i %= LOG_BASE; + j = i - LOG_BASE + d; + rd = j < 0 ? 0 : (n / pows10[d - j - 1]) % 10 | 0; + } + } + r = + r || + sd < 0 || // Are there any non-zero digits after the rounding digit? + // The expression n % pows10[d - j - 1] returns all digits of n to the right + // of the digit at j, e.g. if n is 908714 and j is 2, the expression gives 714. + xc[ni + 1] != null || + (j < 0 ? n : n % pows10[d - j - 1]); + r = + rm < 4 + ? (rd || r) && (rm == 0 || rm == (x.s < 0 ? 3 : 2)) + : rd > 5 || + (rd == 5 && + (rm == 4 || + r || + (rm == 6 && // Check whether the digit to the left of the rounding digit is odd. + (i > 0 ? (j > 0 ? n / pows10[d - j] : 0) : xc[ni - 1]) % 10 & 1) || + rm == (x.s < 0 ? 8 : 7))); + if (sd < 1 || !xc[0]) { + xc.length = 0; + if (r) { + sd -= x.e + 1; + xc[0] = pows10[(LOG_BASE - (sd % LOG_BASE)) % LOG_BASE]; + x.e = -sd || 0; + } else { + xc[0] = x.e = 0; + } + return x; + } + if (i == 0) { + xc.length = ni; + k = 1; + ni--; + } else { + xc.length = ni + 1; + k = pows10[LOG_BASE - i]; + xc[ni] = j > 0 ? mathfloor((n / pows10[d - j]) % pows10[j]) * k : 0; + } + if (r) { + for (;;) { + if (ni == 0) { + for (i = 1, j = xc[0]; j >= 10; j /= 10, i++); + j = xc[0] += k; + for (k = 1; j >= 10; j /= 10, k++); + if (i != k) { + x.e++; + if (xc[0] == BASE) xc[0] = 1; + } + break; + } else { + xc[ni] += k; + if (xc[ni] != BASE) break; + xc[ni--] = 0; + k = 1; + } + } + } + for (i = xc.length; xc[--i] === 0; xc.pop()); + } + if (x.e > MAX_EXP) { + x.c = x.e = null; + } else if (x.e < MIN_EXP) { + x.c = [(x.e = 0)]; + } + } + return x; + } + function valueOf(n) { + var str, + e = n.e; + if (e === null) return n.toString(); + str = coeffToString(n.c); + str = e <= TO_EXP_NEG || e >= TO_EXP_POS ? toExponential(str, e) : toFixedPoint(str, e, '0'); + return n.s < 0 ? '-' + str : str; + } + P.absoluteValue = P.abs = function () { + var x = new BigNumber2(this); + if (x.s < 0) x.s = 1; + return x; + }; + P.comparedTo = function (y, b) { + return compare(this, new BigNumber2(y, b)); + }; + P.decimalPlaces = P.dp = function (dp, rm) { + var c, + n, + v, + x = this; + if (dp != null) { + intCheck(dp, 0, MAX); + if (rm == null) rm = ROUNDING_MODE; + else intCheck(rm, 0, 8); + return round(new BigNumber2(x), dp + x.e + 1, rm); + } + if (!(c = x.c)) return null; + n = ((v = c.length - 1) - bitFloor(this.e / LOG_BASE)) * LOG_BASE; + if ((v = c[v])) for (; v % 10 == 0; v /= 10, n--); + if (n < 0) n = 0; + return n; + }; + P.dividedBy = P.div = function (y, b) { + return div(this, new BigNumber2(y, b), DECIMAL_PLACES, ROUNDING_MODE); + }; + P.dividedToIntegerBy = P.idiv = function (y, b) { + return div(this, new BigNumber2(y, b), 0, 1); + }; + P.exponentiatedBy = P.pow = function (n, m) { + var half, + isModExp, + i, + k, + more, + nIsBig, + nIsNeg, + nIsOdd, + y, + x = this; + n = new BigNumber2(n); + if (n.c && !n.isInteger()) { + throw Error(bignumberError + 'Exponent not an integer: ' + valueOf(n)); + } + if (m != null) m = new BigNumber2(m); + nIsBig = n.e > 14; + if (!x.c || !x.c[0] || (x.c[0] == 1 && !x.e && x.c.length == 1) || !n.c || !n.c[0]) { + y = new BigNumber2(Math.pow(+valueOf(x), nIsBig ? n.s * (2 - isOdd(n)) : +valueOf(n))); + return m ? y.mod(m) : y; + } + nIsNeg = n.s < 0; + if (m) { + if (m.c ? !m.c[0] : !m.s) return new BigNumber2(NaN); + isModExp = !nIsNeg && x.isInteger() && m.isInteger(); + if (isModExp) x = x.mod(m); + } else if ( + n.e > 9 && + (x.e > 0 || + x.e < -1 || + (x.e == 0 ? x.c[0] > 1 || (nIsBig && x.c[1] >= 24e7) : x.c[0] < 8e13 || (nIsBig && x.c[0] <= 9999975e7))) + ) { + k = x.s < 0 && isOdd(n) ? -0 : 0; + if (x.e > -1) k = 1 / k; + return new BigNumber2(nIsNeg ? 1 / k : k); + } else if (POW_PRECISION) { + k = mathceil(POW_PRECISION / LOG_BASE + 2); + } + if (nIsBig) { + half = new BigNumber2(0.5); + if (nIsNeg) n.s = 1; + nIsOdd = isOdd(n); + } else { + i = Math.abs(+valueOf(n)); + nIsOdd = i % 2; + } + y = new BigNumber2(ONE); + for (;;) { + if (nIsOdd) { + y = y.times(x); + if (!y.c) break; + if (k) { + if (y.c.length > k) y.c.length = k; + } else if (isModExp) { + y = y.mod(m); + } + } + if (i) { + i = mathfloor(i / 2); + if (i === 0) break; + nIsOdd = i % 2; + } else { + n = n.times(half); + round(n, n.e + 1, 1); + if (n.e > 14) { + nIsOdd = isOdd(n); + } else { + i = +valueOf(n); + if (i === 0) break; + nIsOdd = i % 2; + } + } + x = x.times(x); + if (k) { + if (x.c && x.c.length > k) x.c.length = k; + } else if (isModExp) { + x = x.mod(m); + } + } + if (isModExp) return y; + if (nIsNeg) y = ONE.div(y); + return m ? y.mod(m) : k ? round(y, POW_PRECISION, ROUNDING_MODE, more) : y; + }; + P.integerValue = function (rm) { + var n = new BigNumber2(this); + if (rm == null) rm = ROUNDING_MODE; + else intCheck(rm, 0, 8); + return round(n, n.e + 1, rm); + }; + P.isEqualTo = P.eq = function (y, b) { + return compare(this, new BigNumber2(y, b)) === 0; + }; + P.isFinite = function () { + return !!this.c; + }; + P.isGreaterThan = P.gt = function (y, b) { + return compare(this, new BigNumber2(y, b)) > 0; + }; + P.isGreaterThanOrEqualTo = P.gte = function (y, b) { + return (b = compare(this, new BigNumber2(y, b))) === 1 || b === 0; + }; + P.isInteger = function () { + return !!this.c && bitFloor(this.e / LOG_BASE) > this.c.length - 2; + }; + P.isLessThan = P.lt = function (y, b) { + return compare(this, new BigNumber2(y, b)) < 0; + }; + P.isLessThanOrEqualTo = P.lte = function (y, b) { + return (b = compare(this, new BigNumber2(y, b))) === -1 || b === 0; + }; + P.isNaN = function () { + return !this.s; + }; + P.isNegative = function () { + return this.s < 0; + }; + P.isPositive = function () { + return this.s > 0; + }; + P.isZero = function () { + return !!this.c && this.c[0] == 0; + }; + P.minus = function (y, b) { + var i, + j, + t, + xLTy, + x = this, + a = x.s; + y = new BigNumber2(y, b); + b = y.s; + if (!a || !b) return new BigNumber2(NaN); + if (a != b) { + y.s = -b; + return x.plus(y); + } + var xe = x.e / LOG_BASE, + ye = y.e / LOG_BASE, + xc = x.c, + yc = y.c; + if (!xe || !ye) { + if (!xc || !yc) return xc ? ((y.s = -b), y) : new BigNumber2(yc ? x : NaN); + if (!xc[0] || !yc[0]) { + return yc[0] + ? ((y.s = -b), y) + : new BigNumber2( + xc[0] + ? x + : // IEEE 754 (2008) 6.3: n - n = -0 when rounding to -Infinity + ROUNDING_MODE == 3 + ? -0 + : 0 + ); + } + } + xe = bitFloor(xe); + ye = bitFloor(ye); + xc = xc.slice(); + if ((a = xe - ye)) { + if ((xLTy = a < 0)) { + a = -a; + t = xc; + } else { + ye = xe; + t = yc; + } + t.reverse(); + for (b = a; b--; t.push(0)); + t.reverse(); + } else { + j = (xLTy = (a = xc.length) < (b = yc.length)) ? a : b; + for (a = b = 0; b < j; b++) { + if (xc[b] != yc[b]) { + xLTy = xc[b] < yc[b]; + break; + } + } + } + if (xLTy) (t = xc), (xc = yc), (yc = t), (y.s = -y.s); + b = (j = yc.length) - (i = xc.length); + if (b > 0) for (; b--; xc[i++] = 0); + b = BASE - 1; + for (; j > a; ) { + if (xc[--j] < yc[j]) { + for (i = j; i && !xc[--i]; xc[i] = b); + --xc[i]; + xc[j] += BASE; + } + xc[j] -= yc[j]; + } + for (; xc[0] == 0; xc.splice(0, 1), --ye); + if (!xc[0]) { + y.s = ROUNDING_MODE == 3 ? -1 : 1; + y.c = [(y.e = 0)]; + return y; + } + return normalise(y, xc, ye); + }; + P.modulo = P.mod = function (y, b) { + var q, + s, + x = this; + y = new BigNumber2(y, b); + if (!x.c || !y.s || (y.c && !y.c[0])) { + return new BigNumber2(NaN); + } else if (!y.c || (x.c && !x.c[0])) { + return new BigNumber2(x); + } + if (MODULO_MODE == 9) { + s = y.s; + y.s = 1; + q = div(x, y, 0, 3); + y.s = s; + q.s *= s; + } else { + q = div(x, y, 0, MODULO_MODE); + } + y = x.minus(q.times(y)); + if (!y.c[0] && MODULO_MODE == 1) y.s = x.s; + return y; + }; + P.multipliedBy = P.times = function (y, b) { + var c, + e, + i, + j, + k, + m, + xcL, + xlo, + xhi, + ycL, + ylo, + yhi, + zc, + base, + sqrtBase, + x = this, + xc = x.c, + yc = (y = new BigNumber2(y, b)).c; + if (!xc || !yc || !xc[0] || !yc[0]) { + if (!x.s || !y.s || (xc && !xc[0] && !yc) || (yc && !yc[0] && !xc)) { + y.c = y.e = y.s = null; + } else { + y.s *= x.s; + if (!xc || !yc) { + y.c = y.e = null; + } else { + y.c = [0]; + y.e = 0; + } + } + return y; + } + e = bitFloor(x.e / LOG_BASE) + bitFloor(y.e / LOG_BASE); + y.s *= x.s; + xcL = xc.length; + ycL = yc.length; + if (xcL < ycL) (zc = xc), (xc = yc), (yc = zc), (i = xcL), (xcL = ycL), (ycL = i); + for (i = xcL + ycL, zc = []; i--; zc.push(0)); + base = BASE; + sqrtBase = SQRT_BASE; + for (i = ycL; --i >= 0; ) { + c = 0; + ylo = yc[i] % sqrtBase; + yhi = (yc[i] / sqrtBase) | 0; + for (k = xcL, j = i + k; j > i; ) { + xlo = xc[--k] % sqrtBase; + xhi = (xc[k] / sqrtBase) | 0; + m = yhi * xlo + xhi * ylo; + xlo = ylo * xlo + (m % sqrtBase) * sqrtBase + zc[j] + c; + c = ((xlo / base) | 0) + ((m / sqrtBase) | 0) + yhi * xhi; + zc[j--] = xlo % base; + } + zc[j] = c; + } + if (c) { + ++e; + } else { + zc.splice(0, 1); + } + return normalise(y, zc, e); + }; + P.negated = function () { + var x = new BigNumber2(this); + x.s = -x.s || null; + return x; + }; + P.plus = function (y, b) { + var t, + x = this, + a = x.s; + y = new BigNumber2(y, b); + b = y.s; + if (!a || !b) return new BigNumber2(NaN); + if (a != b) { + y.s = -b; + return x.minus(y); + } + var xe = x.e / LOG_BASE, + ye = y.e / LOG_BASE, + xc = x.c, + yc = y.c; + if (!xe || !ye) { + if (!xc || !yc) return new BigNumber2(a / 0); + if (!xc[0] || !yc[0]) return yc[0] ? y : new BigNumber2(xc[0] ? x : a * 0); + } + xe = bitFloor(xe); + ye = bitFloor(ye); + xc = xc.slice(); + if ((a = xe - ye)) { + if (a > 0) { + ye = xe; + t = yc; + } else { + a = -a; + t = xc; + } + t.reverse(); + for (; a--; t.push(0)); + t.reverse(); + } + a = xc.length; + b = yc.length; + if (a - b < 0) (t = yc), (yc = xc), (xc = t), (b = a); + for (a = 0; b; ) { + a = ((xc[--b] = xc[b] + yc[b] + a) / BASE) | 0; + xc[b] = BASE === xc[b] ? 0 : xc[b] % BASE; + } + if (a) { + xc = [a].concat(xc); + ++ye; + } + return normalise(y, xc, ye); + }; + P.precision = P.sd = function (sd, rm) { + var c, + n, + v, + x = this; + if (sd != null && sd !== !!sd) { + intCheck(sd, 1, MAX); + if (rm == null) rm = ROUNDING_MODE; + else intCheck(rm, 0, 8); + return round(new BigNumber2(x), sd, rm); + } + if (!(c = x.c)) return null; + v = c.length - 1; + n = v * LOG_BASE + 1; + if ((v = c[v])) { + for (; v % 10 == 0; v /= 10, n--); + for (v = c[0]; v >= 10; v /= 10, n++); + } + if (sd && x.e + 1 > n) n = x.e + 1; + return n; + }; + P.shiftedBy = function (k) { + intCheck(k, -MAX_SAFE_INTEGER, MAX_SAFE_INTEGER); + return this.times('1e' + k); + }; + P.squareRoot = P.sqrt = function () { + var m, + n, + r, + rep, + t, + x = this, + c = x.c, + s = x.s, + e = x.e, + dp = DECIMAL_PLACES + 4, + half = new BigNumber2('0.5'); + if (s !== 1 || !c || !c[0]) { + return new BigNumber2(!s || (s < 0 && (!c || c[0])) ? NaN : c ? x : 1 / 0); + } + s = Math.sqrt(+valueOf(x)); + if (s == 0 || s == 1 / 0) { + n = coeffToString(c); + if ((n.length + e) % 2 == 0) n += '0'; + s = Math.sqrt(+n); + e = bitFloor((e + 1) / 2) - (e < 0 || e % 2); + if (s == 1 / 0) { + n = '5e' + e; + } else { + n = s.toExponential(); + n = n.slice(0, n.indexOf('e') + 1) + e; + } + r = new BigNumber2(n); + } else { + r = new BigNumber2(s + ''); + } + if (r.c[0]) { + e = r.e; + s = e + dp; + if (s < 3) s = 0; + for (;;) { + t = r; + r = half.times(t.plus(div(x, t, dp, 1))); + if (coeffToString(t.c).slice(0, s) === (n = coeffToString(r.c)).slice(0, s)) { + if (r.e < e) --s; + n = n.slice(s - 3, s + 1); + if (n == '9999' || (!rep && n == '4999')) { + if (!rep) { + round(t, t.e + DECIMAL_PLACES + 2, 0); + if (t.times(t).eq(x)) { + r = t; + break; + } + } + dp += 4; + s += 4; + rep = 1; + } else { + if (!+n || (!+n.slice(1) && n.charAt(0) == '5')) { + round(r, r.e + DECIMAL_PLACES + 2, 1); + m = !r.times(r).eq(x); + } + break; + } + } + } + } + return round(r, r.e + DECIMAL_PLACES + 1, ROUNDING_MODE, m); + }; + P.toExponential = function (dp, rm) { + if (dp != null) { + intCheck(dp, 0, MAX); + dp++; + } + return format(this, dp, rm, 1); + }; + P.toFixed = function (dp, rm) { + if (dp != null) { + intCheck(dp, 0, MAX); + dp = dp + this.e + 1; + } + return format(this, dp, rm); + }; + P.toFormat = function (dp, rm, format2) { + var str, + x = this; + if (format2 == null) { + if (dp != null && rm && typeof rm == 'object') { + format2 = rm; + rm = null; + } else if (dp && typeof dp == 'object') { + format2 = dp; + dp = rm = null; + } else { + format2 = FORMAT; + } + } else if (typeof format2 != 'object') { + throw Error(bignumberError + 'Argument not an object: ' + format2); + } + str = x.toFixed(dp, rm); + if (x.c) { + var i, + arr = str.split('.'), + g1 = +format2.groupSize, + g2 = +format2.secondaryGroupSize, + groupSeparator = format2.groupSeparator || '', + intPart = arr[0], + fractionPart = arr[1], + isNeg = x.s < 0, + intDigits = isNeg ? intPart.slice(1) : intPart, + len = intDigits.length; + if (g2) (i = g1), (g1 = g2), (g2 = i), (len -= i); + if (g1 > 0 && len > 0) { + i = len % g1 || g1; + intPart = intDigits.substr(0, i); + for (; i < len; i += g1) intPart += groupSeparator + intDigits.substr(i, g1); + if (g2 > 0) intPart += groupSeparator + intDigits.slice(i); + if (isNeg) intPart = '-' + intPart; + } + str = fractionPart + ? intPart + + (format2.decimalSeparator || '') + + ((g2 = +format2.fractionGroupSize) + ? fractionPart.replace(new RegExp('\\d{' + g2 + '}\\B', 'g'), '$&' + (format2.fractionGroupSeparator || '')) + : fractionPart) + : intPart; + } + return (format2.prefix || '') + str + (format2.suffix || ''); + }; + P.toFraction = function (md) { + var d, + d0, + d1, + d2, + e, + exp, + n, + n0, + n1, + q, + r, + s, + x = this, + xc = x.c; + if (md != null) { + n = new BigNumber2(md); + if ((!n.isInteger() && (n.c || n.s !== 1)) || n.lt(ONE)) { + throw Error( + bignumberError + 'Argument ' + (n.isInteger() ? 'out of range: ' : 'not an integer: ') + valueOf(n) + ); + } + } + if (!xc) return new BigNumber2(x); + d = new BigNumber2(ONE); + n1 = d0 = new BigNumber2(ONE); + d1 = n0 = new BigNumber2(ONE); + s = coeffToString(xc); + e = d.e = s.length - x.e - 1; + d.c[0] = POWS_TEN[(exp = e % LOG_BASE) < 0 ? LOG_BASE + exp : exp]; + md = !md || n.comparedTo(d) > 0 ? (e > 0 ? d : n1) : n; + exp = MAX_EXP; + MAX_EXP = 1 / 0; + n = new BigNumber2(s); + n0.c[0] = 0; + for (;;) { + q = div(n, d, 0, 1); + d2 = d0.plus(q.times(d1)); + if (d2.comparedTo(md) == 1) break; + d0 = d1; + d1 = d2; + n1 = n0.plus(q.times((d2 = n1))); + n0 = d2; + d = n.minus(q.times((d2 = d))); + n = d2; + } + d2 = div(md.minus(d0), d1, 0, 1); + n0 = n0.plus(d2.times(n1)); + d0 = d0.plus(d2.times(d1)); + n0.s = n1.s = x.s; + e = e * 2; + r = + div(n1, d1, e, ROUNDING_MODE).minus(x).abs().comparedTo(div(n0, d0, e, ROUNDING_MODE).minus(x).abs()) < 1 + ? [n1, d1] + : [n0, d0]; + MAX_EXP = exp; + return r; + }; + P.toNumber = function () { + return +valueOf(this); + }; + P.toPrecision = function (sd, rm) { + if (sd != null) intCheck(sd, 1, MAX); + return format(this, sd, rm, 2); + }; + P.toString = function (b) { + var str, + n = this, + s = n.s, + e = n.e; + if (e === null) { + if (s) { + str = 'Infinity'; + if (s < 0) str = '-' + str; + } else { + str = 'NaN'; + } + } else { + if (b == null) { + str = + e <= TO_EXP_NEG || e >= TO_EXP_POS + ? toExponential(coeffToString(n.c), e) + : toFixedPoint(coeffToString(n.c), e, '0'); + } else if (b === 10 && alphabetHasNormalDecimalDigits) { + n = round(new BigNumber2(n), DECIMAL_PLACES + e + 1, ROUNDING_MODE); + str = toFixedPoint(coeffToString(n.c), n.e, '0'); + } else { + intCheck(b, 2, ALPHABET.length, 'Base'); + str = convertBase(toFixedPoint(coeffToString(n.c), e, '0'), 10, b, s, true); + } + if (s < 0 && n.c[0]) str = '-' + str; + } + return str; + }; + P.valueOf = P.toJSON = function () { + return valueOf(this); + }; + P._isBigNumber = true; + P[Symbol.toStringTag] = 'BigNumber'; + P[Symbol.for('nodejs.util.inspect.custom')] = P.valueOf; + if (configObject != null) BigNumber2.set(configObject); + return BigNumber2; +} +function bitFloor(n) { + var i = n | 0; + return n > 0 || n === i ? i : i - 1; +} +function coeffToString(a) { + var s, + z, + i = 1, + j = a.length, + r = a[0] + ''; + for (; i < j; ) { + s = a[i++] + ''; + z = LOG_BASE - s.length; + for (; z--; s = '0' + s); + r += s; + } + for (j = r.length; r.charCodeAt(--j) === 48; ); + return r.slice(0, j + 1 || 1); +} +function compare(x, y) { + var a, + b, + xc = x.c, + yc = y.c, + i = x.s, + j = y.s, + k = x.e, + l = y.e; + if (!i || !j) return null; + a = xc && !xc[0]; + b = yc && !yc[0]; + if (a || b) return a ? (b ? 0 : -j) : i; + if (i != j) return i; + a = i < 0; + b = k == l; + if (!xc || !yc) return b ? 0 : !xc ^ a ? 1 : -1; + if (!b) return (k > l) ^ a ? 1 : -1; + j = (k = xc.length) < (l = yc.length) ? k : l; + for (i = 0; i < j; i++) if (xc[i] != yc[i]) return (xc[i] > yc[i]) ^ a ? 1 : -1; + return k == l ? 0 : (k > l) ^ a ? 1 : -1; +} +function intCheck(n, min, max, name) { + if (n < min || n > max || n !== mathfloor(n)) { + throw Error( + bignumberError + + (name || 'Argument') + + (typeof n == 'number' + ? n < min || n > max + ? ' out of range: ' + : ' not an integer: ' + : ' not a primitive number: ') + + String(n) + ); + } +} +function isOdd(n) { + var k = n.c.length - 1; + return bitFloor(n.e / LOG_BASE) == k && n.c[k] % 2 != 0; +} +function toExponential(str, e) { + return (str.length > 1 ? str.charAt(0) + '.' + str.slice(1) : str) + (e < 0 ? 'e' : 'e+') + e; +} +function toFixedPoint(str, e, z) { + var len, zs; + if (e < 0) { + for (zs = z + '.'; ++e; zs += z); + str = zs + str; + } else { + len = str.length; + if (++e > len) { + for (zs = z, e -= len; --e; zs += z); + str += zs; + } else if (e < len) { + str = str.slice(0, e) + '.' + str.slice(e); + } + } + return str; +} +var BigNumberClone = clone(); +var bignumber_default = BigNumberClone; + +// src/util.js +var ce = (flag, message) => (p) => flag ? Left(message) : Right(p); +function isInteger(v) { + return new bignumber_default(v).isInteger(); +} +function roundDown(v) { + return new bignumber_default(v).integerValue(bignumber_default.ROUND_DOWN).toNumber(); +} +var addClaimBalanceTo = ({ state, action }) => { + const indexToRemove = state.claimable.findIndex((claim3) => claim3.txID === action.input.txID); + const claim2 = state.claimable[indexToRemove]; + const balance2 = state.balances[claim2.to] || 0; + state.balances[claim2.to] = balance2 + claim2.qty; + return indexToRemove; +}; +var addClaimBalanceFrom = ({ state, action }) => { + const indexToRemove = state.claimable.findIndex((claim3) => claim3.txID === action.input.tx); + const claim2 = state.claimable[indexToRemove]; + const balance2 = state.balances[claim2.from] || 0; + state.balances[claim2.from] = balance2 + claim2.qty; + return indexToRemove; +}; +function isArweaveAddress(address) { + if (!address) return void 0; + const addr = address.toString().trim(); + return /[a-z0-9_-]{43}/i.test(addr); +} + +// src/write/transfer.js +function transfer(state, action) { + return of({ state, action }) + .chain(fromNullable) + .chain(ce(!action.input?.target, 'Please specify a target.')) + .chain(ce(action.input?.target === action.caller, 'Target cannot be caller.')) + .chain(ce(!isArweaveAddress(action.input?.target), 'Invalid target.')) + .chain(ce(!isInteger(action.input?.qty), 'qty must be an integer.')) + .chain(ce(roundDown(action.input?.qty) < 1, 'Invalid token transfer. qty must be an integer greater than 0.')) + .chain(ce((state.balances[action.caller] || 0) < roundDown(action.input?.qty), 'Not enough tokens for transfer.')) + .map(updateBalances) + .fold( + (error) => { + throw new ContractError(error || 'An error occurred.'); + }, + () => ({ state }) + ); +} +var updateBalances = ({ state, action }) => { + const safeQty = roundDown(action.input.qty); + state.balances[action.caller] -= safeQty; + const targetBalance = state.balances[action.input.target] || 0; + state.balances[action.input.target] = targetBalance + safeQty; +}; + +// src/write/claim.js +function claim(state, action) { + return of({ state, action }) + .chain(fromNullable) + .chain(ce(!action.input?.txID, 'txID must be passed to the claim function.')) + .chain(ce(!action.input?.qty, 'A qty must be specified.')) + .chain( + ce( + state.claimable.filter((c) => c.txID === action.input.txID).length !== 1, + 'There must be 1 claimable with this tx id.' + ) + ) + .chain( + ce( + state.claimable.filter((c) => c.txID === action.input?.txID)[0]?.to !== action.caller, + 'Claim not addressed to caller.' + ) + ) + .chain( + ce(state.claimable.filter((c) => c.txID === action.input.txID)[0]?.qty !== action.input?.qty, 'Incorrect qty.') + ) + .map(addClaimBalanceTo) + .map((indexToRemove) => { + state.claimable.splice(indexToRemove, 1); + return state; + }) + .fold( + (msg) => { + throw new ContractError(msg || 'An error occurred.'); + }, + () => { + return { state }; + } + ); +} + +// src/write/allow.js +function allow(state, action) { + logger.info('TEST'); + return of(action.caller) + .chain(fromNullable) + .chain(ce(!action.input?.target, 'Please specify a target.')) + .chain(ce(action.input?.target === action.caller, 'Target cannot be caller.')) + .chain(ce(!isArweaveAddress(action.input?.target), 'Invalid target.')) + .chain(ce(!isInteger(action.input?.qty), 'qty must be an integer.')) + .chain(ce(roundDown(action.input?.qty) < 1, 'Invalid token transfer. qty must be an integer greater than 0.')) + .chain(ce((state.balances[action.caller] || 0) < roundDown(action.input?.qty), 'Not enough tokens for transfer.')) + .map((caller) => { + const safeQty = roundDown(action.input.qty); + state.balances[caller] -= safeQty; + state.claimable.push({ + from: caller, + to: action.input.target, + qty: safeQty, + txID: SmartWeave.transaction.id + }); + }) + .fold( + (msg) => { + throw new ContractError(msg || 'An error occurred.'); + }, + () => ({ state }) + ); +} + +// src/write/mint.js +function mint(state, action) { + if (!state.balances[action.caller]) { + state.balances[action.caller] = 0; + } + state.balances[action.caller] += roundDown(SmartWeave.transaction.reward / state.divisibility); + return { state }; +} + +// src/write/reject.js +function rejectClaimable(state, action) { + return of({ state, action }) + .chain(fromNullable) + .chain(ce(!action.input?.tx, 'txID must be passed to the reject function.')) + .chain( + ce( + state.claimable.filter((c) => c.txID === action.input.tx).length !== 1, + 'There must be 1 claimable with this tx id.' + ) + ) + .chain( + ce( + state.claimable.filter((c) => c.txID === action.input.tx)[0]?.to !== action.caller, + 'Claim not addressed to caller.' + ) + ) + .map(addClaimBalanceFrom) + .map((indexToRemove) => { + state.claimable.splice(indexToRemove, 1); + return state; + }) + .fold( + (msg) => { + throw new ContractError(msg || 'An error occurred.'); + }, + (state2) => ({ state: state2 }) + ); +} + +// src/contract.js +export async function handle(state, action) { + // if ( + // ['transfer', 'allow', 'claim', 'reject'].includes(action?.input?.function) && + // SmartWeave.transaction.origin === 'L1' + // ) { + // return { state }; + // } + // if (action?.input?.function === 'mint' && SmartWeave.transaction.origin === 'L2') return { state }; + switch (action?.input?.function) { + case 'balance': + return balance(state, action); + case 'reject': + return rejectClaimable(state, action); + case 'transfer': + return transfer(state, action); + case 'allow': + return allow(state, action); + case 'claim': + return claim(state, action); + case 'mint': + return mint(state, action); + default: + throw new ContractError(`No function supplied or function not recognized`); + } +} diff --git a/src/__tests__/integration/data/bazar-ucm.js b/src/__tests__/integration/data/bazar-ucm.js new file mode 100644 index 00000000..f5f7649e --- /dev/null +++ b/src/__tests__/integration/data/bazar-ucm.js @@ -0,0 +1,1843 @@ +// src/lib/either.js +var Right = (x) => ({ + isLeft: false, + chain: (f) => f(x), + ap: (other) => other.map(x), + alt: (other) => Right(x), + extend: (f) => f(Right(x)), + concat: (other) => other.fold( + (x2) => other, + (y) => Right(x.concat(y)) + ), + traverse: (of2, f) => f(x).map(Right), + map: (f) => Right(f(x)), + fold: (_, g) => g(x), + toString: () => `Right(${x})`, + extract: () => x +}); +var Left = (x) => ({ + isLeft: true, + chain: (_) => Left(x), + ap: (_) => Left(x), + extend: (_) => Left(x), + alt: (other) => other, + concat: (_) => Left(x), + traverse: (of2, _) => of2(Left(x)), + map: (_) => Left(x), + fold: (f, _) => f(x), + toString: () => `Left(${x})`, + extract: () => x +}); +var of = Right; + +// src/write/add-pair.js +function addPair(state, action) { + return of({ state, action }).chain(validate).map(updatePairs); +} +function updatePairs({ state, action }) { + state.pairs.push({ + pair: action.input.pair, + orders: [] + }); + return { state }; +} +function validate({ state, action }) { + if (!state.pairs) { + state.pairs = []; + } + if (!action.input.pair) { + return Left("pair is required"); + } + if (!action.input.pair[0].length === 43) { + return Left("Each pair must be a contract address"); + } + if (!action.input.pair[1].length === 43) { + return Left("Each pair must be a contract address"); + } + if (state.pairs.find( + ({ pair: existingPair }) => existingPair.includes(action.input.pair[0]) && existingPair.includes(action.input.pair[1]) + )) { + return Left("Pair already exists"); + } + return Right({ state, action }); +} + +// src/lib/streak-calc.js +function calculateStreak(lastHeight = 0, currentHeight = 0, streak = 0) { + if (streak === 0) { + return { days: 1, lastHeight: currentHeight }; + } + if (streak >= 30) { + return { days: 1, lastHeight: currentHeight }; + } + const diff = currentHeight - lastHeight; + if (diff <= 720) { + return { days: streak, lastHeight }; + } + if (diff > 720 && diff <= 1440) { + return { days: streak + 1, lastHeight: currentHeight }; + } + if (diff > 1440) { + return { days: 1, lastHeight: currentHeight }; + } + return { days: 0, lastHeight: 0 }; +} + +// src/write/create-order.js +var U = "KTzTXT_ANmF84fWEKHzWURD1LWd9QaFR9yfYUwH2Lxw"; +var CreateOrder = async (state, action) => { + U = state.U; + const caller = action.caller; + const input = action.input; + const pairs = state.pairs; + const usedPair = input.pair; + const qty = input.qty; + const price = input.price; + const max = input?.max || Number.MAX_SAFE_INTEGER; + let tokenTx = input.transaction; + let balances = state.balances; + ContractAssert( + isAddress(usedPair[0]) && isAddress(usedPair[1]), + "One of two supplied pair tokens is invalid" + ); + if (price) { + ContractAssert(typeof price === "number", "Price must be a number"); + ContractAssert( + price === void 0 || price === null || price > 0, + "Price must be greater than 0" + ); + } + if (!Number.isInteger(qty) || qty === void 0) { + throw new ContractError("Invalid value for quantity. Must be an integer."); + } + let contractID = usedPair[0]; + if (contractID === SmartWeave.contract.id) { + tokenTx = "INTERNAL_TRANSFER"; + if (qty <= 0 || caller === SmartWeave.contract.id) { + throw new ContractError("Invalid token transfer."); + } + if (balances[caller] < qty) { + throw new ContractError( + "Caller balance not high enough to send " + qty + " token(s)." + ); + } + balances[caller] -= qty; + if (SmartWeave.contract.id in balances) { + balances[SmartWeave.contract.id] += qty; + } else { + balances[SmartWeave.contract.id] = qty; + } + } else if (usedPair[1] === SmartWeave.contract.id && tokenTx === "INTERNAL_TRANSFER") { + } else { + if (tokenTx === void 0 || tokenTx === null) { + throw new ContractError( + "No token transaction provided given the token in the order is from a different contract" + ); + } + await claimBalance(contractID, tokenTx, qty); + } + const refundTransfer = async () => { + if (contractID === SmartWeave.contract.id) { + balances[SmartWeave.contract.id] -= qty; + if (caller in balances) { + balances[caller] += qty; + } else { + balances[caller] = qty; + } + } else { + await SmartWeave.contracts.write(contractID, { + function: "transfer", + target: caller, + qty + }); + } + }; + let pairIndex = -1; + for (let i = 0; i < pairs.length; i++) { + if (pairs[i].pair[0] === usedPair[0] && pairs[i].pair[1] === usedPair[1] || pairs[i].pair[0] === usedPair[1] && pairs[i].pair[1] === usedPair[0]) { + pairIndex = i; + } + } + if (pairIndex === -1) { + await refundTransfer(); + return { + state, + result: { + status: "failure", + message: "This pair does not exist yet" + } + }; + } + let sortedOrderbook; + if (state.pairs[pairIndex].orders.length > 0) { + sortedOrderbook = state.pairs[pairIndex].orders.sort( + (a, b) => a.price > b.price ? 1 : -1 + ); + } else { + sortedOrderbook = []; + } + const dominantToken = state.pairs[pairIndex].pair[0]; + try { + const { orderbook, foreignCalls, matches } = matchOrder( + { + pair: { + dominant: dominantToken, + from: contractID, + to: usedPair.find((val) => val !== contractID) + }, + quantity: qty, + creator: caller, + transaction: SmartWeave.transaction.id, + transfer: tokenTx, + price + }, + sortedOrderbook + ); + const maxPrice = matches.reduce((a, v) => v.price > a ? v.price : a, 0); + if (maxPrice > max) { + throw new Error("can not purchase item it is greater than max bid"); + } + state.pairs[pairIndex].orders = orderbook; + if (matches.length > 0) { + const vwap = matches.map(({ qty: volume, price: price2 }) => volume * price2).reduce((a, b) => a + b, 0) / matches.map(({ qty: volume }) => volume).reduce((a, b) => a + b, 0); + state.pairs[pairIndex].priceData = { + dominantToken, + block: SmartWeave.block.height, + vwap, + matchLogs: matches + }; + } else { + state.pairs[pairIndex].priceData = void 0; + } + for (let i = 0; i < foreignCalls.length; i++) { + if (foreignCalls[i].input.qty <= 0) { + continue; + } + if (foreignCalls[i].contract === SmartWeave.contract.id) { + balances[SmartWeave.contract.id] -= foreignCalls[i].input.qty; + if (foreignCalls[i].input.target in balances) { + balances[foreignCalls[i].input.target] += foreignCalls[i].input.qty; + } else { + balances[foreignCalls[i].input.target] = foreignCalls[i].input.qty; + } + } else { + if (foreignCalls[i].contract !== U) { + const buyer = foreignCalls[i].input.target; + if (!state.streaks[buyer]) { + state.streaks[buyer] = { days: 0, lastHeight: 0 }; + } + const streakUpdate = calculateStreak( + state.streaks[buyer].lastHeight, + SmartWeave.block.height, + state.streaks[buyer].days + ); + state.streaks[buyer] = streakUpdate; + } + const result = await SmartWeave.contracts.write( + foreignCalls[i].contract, + foreignCalls[i].input + ); + if (result.type !== "ok") { + throw new ContractError( + `Unable to fill order with txID: ${foreignCalls[i].txID}` + ); + } + } + } + if (state.balances) { + state.balances = balances; + } + return { + state, + result: { + status: "success", + message: "Order created successfully" + } + }; + } catch (e) { + await refundTransfer(); + return { + state, + result: { + status: "failure", + message: e.message + } + }; + } +}; +function matchOrder(input, orderbook) { + const orderType = input.price ? "limit" : "market"; + const foreignCalls = []; + const matches = []; + const reverseOrders = orderbook.filter( + (order) => input.pair.from !== order.token && order.id !== input.transaction + ); + if (!reverseOrders.length) { + if (orderType !== "limit") + throw new Error('The first order for a pair can only be a "limit" order'); + orderbook.push({ + id: input.transaction, + transfer: input.transfer, + creator: input.creator, + token: input.pair.from, + price: input.price, + quantity: Math.round(input.quantity), + originalQuantity: input.quantity + }); + return { + orderbook, + foreignCalls, + matches + }; + } + let fillAmount; + let receiveAmount = 0; + let remainingQuantity = input.quantity; + const newOrderbook = orderbook.reduce((acc, currentOrder) => { + if (input.pair.from === currentOrder.token || currentOrder.id === input.transaction) { + acc.push(currentOrder); + return acc; + } + const reversePrice = 1 / currentOrder.price; + if (orderType === "limit" && input.price !== reversePrice) { + acc.push(currentOrder); + return acc; + } + ; + fillAmount = Math.floor(remainingQuantity * (input.price ?? reversePrice)); + let receiveFromCurrent = 0; + if (fillAmount <= currentOrder.quantity) { + receiveFromCurrent = Math.floor(remainingQuantity * reversePrice); + currentOrder.quantity -= fillAmount; + receiveAmount += receiveFromCurrent; + if (remainingQuantity > 0) { + foreignCalls.push({ + txID: SmartWeave.transaction.id, + contract: input.pair.from, + input: { + function: "transfer", + target: currentOrder.creator, + qty: Math.round(remainingQuantity * 0.995) + } + }); + } + remainingQuantity = 0; + } else { + receiveFromCurrent = currentOrder.quantity; + receiveAmount += receiveFromCurrent; + const sendAmount = receiveFromCurrent * currentOrder.price; + remainingQuantity -= sendAmount; + foreignCalls.push({ + txID: SmartWeave.transaction.id, + contract: input.pair.from, + input: { + function: "transfer", + target: currentOrder.creator, + qty: input.pair.from === Math.round(sendAmount * 0.995) + } + }); + currentOrder.quantity = 0; + } + let dominantPrice = 0; + if (input.pair.dominant === input.pair.from) { + dominantPrice = input.price ?? reversePrice; + } else { + dominantPrice = currentOrder.price; + } + if (receiveFromCurrent > 0) { + matches.push({ + id: currentOrder.id, + qty: receiveFromCurrent, + price: dominantPrice + }); + } + if (currentOrder.quantity !== 0) { + acc.push(currentOrder); + } + return acc; + }, []); + if (remainingQuantity > 0) { + if (orderType === "limit") { + newOrderbook.push({ + id: input.transaction, + transfer: input.transfer, + creator: input.creator, + token: input.pair.from, + price: input.price, + quantity: Math.round(remainingQuantity), + originalQuantity: input.quantity + }); + } else { + foreignCalls.push({ + txID: SmartWeave.transaction.id, + contract: input.pair.from, + input: { + function: "transfer", + target: input.creator, + qty: remainingQuantity + } + }); + } + } + foreignCalls.push({ + txID: SmartWeave.transaction.id, + contract: input.pair.to, + input: { + function: "transfer", + target: input.creator, + qty: Math.round(receiveAmount * 0.995) + } + }); + return { + orderbook: newOrderbook, + foreignCalls, + matches + }; +} +var claimBalance = async (tokenID, transferTx, qty) => { + const result = await SmartWeave.contracts.write(tokenID, { + function: "claim", + txID: transferTx, + qty + }); + if (result.type !== "ok") { + throw new ContractError(`Unable to make claim with txID: ${transferTx}`); + } +}; +var isAddress = (addr) => /[a-z0-9_-]{43}/i.test(addr); + +// src/write/cancel-order.js +var CancelOrder = async (state, action) => { + const caller = action.caller; + const input = action.input; + const orderTxID = input.orderID; + ContractAssert(isAddress2(orderTxID), "Invalid order ID"); + const allOrders = state.pairs.map((pair) => pair.orders).flat(1); + const order = allOrders.find(({ id }) => id === orderTxID); + ContractAssert(order !== void 0, "Order does not exist"); + ContractAssert( + order.creator === caller, + "Caller is not the creator of the order" + ); + if (order.token === SmartWeave.contract.id) { + state.balances[SmartWeave.contract.id] -= order.quantity; + if (caller in state.balances) { + state.balances[caller] += order.quantity; + } else { + state.balances[caller] = order.quantity; + } + } else { + const result = await SmartWeave.contracts.write(order.token, { + function: "transfer", + target: caller, + qty: order.quantity + }); + if (result.type !== "ok") { + throw new ContractError( + `Unable to make claim with txID: ${SmartWeave.transaction.id}` + ); + } + } + const acitvePair = state.pairs.find( + (pair) => pair.orders.find(({ id }) => id === orderTxID) + ); + acitvePair.orders = acitvePair.orders.filter(({ id }) => id !== orderTxID); + return { + state, + result: { + status: "success", + message: "Order cancelled successfully" + } + }; +}; +var isAddress2 = (addr) => /[a-z0-9_-]{43}/i.test(addr); + +// src/read/balance.js +function balance(state, action) { + if (!action.input.target) { + action.input.target = action.caller; + } + ContractAssert( + /[a-z0-9_-]{43}/i.test(action.input.target), + "Invalid Target!" + ); + if (!state.balances[action.input.target]) { + return { + result: { + target: action.input.target, + balance: 0 + } + }; + } + return { + result: { + target: action.input.target, + balance: state.balances[action.input.target] + } + }; +} + +// src/write/transfer.js +var transfer = (state, action) => of({ state, action }).chain(validate2).map(update); +function update({ state, action }) { + state.balances[action.caller] -= action.input.qty; + state.balances[action.input.target] += action.input.qty; + return { state }; +} +function validate2({ state, action }) { + if (!action.caller || action.caller.length !== 43) { + return Left("Caller is not valid"); + } + if (!action.input.qty || typeof action.input.qty !== "number") { + return Left("qty is not defined or is not a number"); + } + if (!action.input.target || action.input.target.length !== 43) { + return Left("target is not valid"); + } + if (action.caller === action.input.target) { + return Left("target cannot be caller"); + } + if (!state.balances[action.input.target]) { + state.balances[action.input.target] = 0; + } + if (!state.balances[action.caller]) { + state.balances[action.caller] = 0; + } + if (state.balances[action.caller] < action.input.qty) { + return Left("not enough balance to transfer"); + } + return Right({ state, action }); +} + +// src/read/validate.js +function validate3(state) { + ContractAssert(state.name, "Name is required!"); + ContractAssert(state.ticker, "Ticker is required!"); + ContractAssert(state.balances, "Balances Object is required!"); + ContractAssert(state.pairs, "Pairs Array is required!"); + ContractAssert(state.claimable, "Claimable Array is required!"); + ContractAssert(state.streaks, "Streaks Object is required!"); + ContractAssert(state.lastReward > -1, "Last Reward prop is required"); + ContractAssert(state.recentRewards, "Recent Rewards prop is required"); + ContractAssert(state.U, "U is required!"); +} + +// src/write/allow.js +var allow = (state, action) => of({ state, action }).chain(validate4).map(update2); +function update2({ state, action }) { + state.balances[action.caller] -= action.input.qty; + if (!state.claimable) { + state.claimable = []; + } + state.claimable.push({ + from: action.caller, + to: action.input.target, + qty: action.input.qty, + txID: SmartWeave.transaction.id + }); + return { state }; +} +function validate4({ state, action }) { + if (!Number.isInteger(action.input.qty) || action.input.qty === void 0) { + return Left("Invalid value for quantity. Must be an integer."); + } + if (!action?.input?.target) { + return Left("No target specified."); + } + if (action.input.target.length !== 43) { + return Left("Target is not valid!"); + } + if (action.input.target === SmartWeave.transaction.id) { + return Left("Cant setup claim to transfer a balance to itself"); + } + if (action.caller === action.input.target) { + return Left("Invalid balance transfer"); + } + if (!state.balances[action.caller]) { + return Left("Caller does not have a balance"); + } + if (state.balances[action.caller] < action.input.qty) { + return Left("Caller balance is not high enough."); + } + return Right({ state, action }); +} + +// src/write/claim.js +var claim = (state, action) => of({ state, action }).chain(validate5).map(update3); +function update3({ state, action, idx }) { + if (!state.balances[action.caller]) { + state.balances[action.caller] = 0; + } + state.balances[action.caller] += action.input.qty; + state.claimable.splice(idx, 1); + return { state }; +} +function validate5({ state, action }) { + if (!action.input.txID) { + return Left("txID is not found."); + } + if (!action.input.qty) { + return Left("claim quantity is not specified."); + } + const idx = state.claimable.findIndex((c) => c.txID === action.input.txID); + if (idx < 0) { + return Left("claimable not found."); + } + if (state.claimable[idx].qty !== action.input.qty) { + return Left("claimable qty is not equal to claim qty."); + } + if (state.claimable[idx].to !== action.caller) { + return Left("claim is not addressed to caller."); + } + return Right({ state, action, idx }); +} + +// src/cron/buyback.js +var DUTCH = 1.01; +async function buyback(state) { + const U2 = state.U; + const uState = await SmartWeave.contracts.readContractState(U2); + const uBalance = uState.balances[SmartWeave.contract.id] || 0; + if (uBalance === 0) { + return state; + } + let zAR_U = state.pairs.find( + (p) => p.pair.includes(U2) && p.pair.includes(SmartWeave.contract.id) + ); + if (!zAR_U) { + state.pairs.push({ + pair: [SmartWeave.contract.id, U2], + orders: [], + priceData: {} + }); + zAR_U = state.pairs.find( + (p) => p.pair.includes(U2) && p.pair.includes(SmartWeave.contract.id) + ); + } + let response = null; + const orderToUpdate = await zAR_U.orders.find((o) => o.creator === SmartWeave.contract.id); + if (orderToUpdate) { + let price = Math.floor(orderToUpdate.price * DUTCH); + orderToUpdate.originalQuantity = uBalance; + orderToUpdate.quantity = uBalance; + orderToUpdate.price = price; + } else { + let price = zAR_U?.priceData?.vwap || 100; + response = await CreateOrder(state, { + caller: SmartWeave.contract.id, + input: { + pair: [U2, SmartWeave.contract.id], + qty: uBalance, + transaction: "INTERNAL_TRANSFER", + price + } + }); + } + if (response) { + response.state.balances[SmartWeave.contract.id] = 0; + if (response.result.status === "success") { + return response.state; + } else { + return state; + } + } else { + return state; + } +} + +// node_modules/ramda/es/internal/_isPlaceholder.js +function _isPlaceholder(a) { + return a != null && typeof a === "object" && a["@@functional/placeholder"] === true; +} + +// node_modules/ramda/es/internal/_curry1.js +function _curry1(fn) { + return function f1(a) { + if (arguments.length === 0 || _isPlaceholder(a)) { + return f1; + } else { + return fn.apply(this, arguments); + } + }; +} + +// node_modules/ramda/es/internal/_curry2.js +function _curry2(fn) { + return function f2(a, b) { + switch (arguments.length) { + case 0: + return f2; + case 1: + return _isPlaceholder(a) ? f2 : _curry1(function(_b) { + return fn(a, _b); + }); + default: + return _isPlaceholder(a) && _isPlaceholder(b) ? f2 : _isPlaceholder(a) ? _curry1(function(_a) { + return fn(_a, b); + }) : _isPlaceholder(b) ? _curry1(function(_b) { + return fn(a, _b); + }) : fn(a, b); + } + }; +} + +// node_modules/ramda/es/add.js +var add = /* @__PURE__ */ _curry2(function add2(a, b) { + return Number(a) + Number(b); +}); +var add_default = add; + +// node_modules/ramda/es/internal/_arity.js +function _arity(n, fn) { + switch (n) { + case 0: + return function() { + return fn.apply(this, arguments); + }; + case 1: + return function(a0) { + return fn.apply(this, arguments); + }; + case 2: + return function(a0, a1) { + return fn.apply(this, arguments); + }; + case 3: + return function(a0, a1, a2) { + return fn.apply(this, arguments); + }; + case 4: + return function(a0, a1, a2, a3) { + return fn.apply(this, arguments); + }; + case 5: + return function(a0, a1, a2, a3, a4) { + return fn.apply(this, arguments); + }; + case 6: + return function(a0, a1, a2, a3, a4, a5) { + return fn.apply(this, arguments); + }; + case 7: + return function(a0, a1, a2, a3, a4, a5, a6) { + return fn.apply(this, arguments); + }; + case 8: + return function(a0, a1, a2, a3, a4, a5, a6, a7) { + return fn.apply(this, arguments); + }; + case 9: + return function(a0, a1, a2, a3, a4, a5, a6, a7, a8) { + return fn.apply(this, arguments); + }; + case 10: + return function(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9) { + return fn.apply(this, arguments); + }; + default: + throw new Error("First argument to _arity must be a non-negative integer no greater than ten"); + } +} + +// node_modules/ramda/es/internal/_curryN.js +function _curryN(length, received, fn) { + return function() { + var combined = []; + var argsIdx = 0; + var left = length; + var combinedIdx = 0; + while (combinedIdx < received.length || argsIdx < arguments.length) { + var result; + if (combinedIdx < received.length && (!_isPlaceholder(received[combinedIdx]) || argsIdx >= arguments.length)) { + result = received[combinedIdx]; + } else { + result = arguments[argsIdx]; + argsIdx += 1; + } + combined[combinedIdx] = result; + if (!_isPlaceholder(result)) { + left -= 1; + } + combinedIdx += 1; + } + return left <= 0 ? fn.apply(this, combined) : _arity(left, _curryN(length, combined, fn)); + }; +} + +// node_modules/ramda/es/curryN.js +var curryN = /* @__PURE__ */ _curry2(function curryN2(length, fn) { + if (length === 1) { + return _curry1(fn); + } + return _arity(length, _curryN(length, [], fn)); +}); +var curryN_default = curryN; + +// node_modules/ramda/es/internal/_curry3.js +function _curry3(fn) { + return function f3(a, b, c) { + switch (arguments.length) { + case 0: + return f3; + case 1: + return _isPlaceholder(a) ? f3 : _curry2(function(_b, _c) { + return fn(a, _b, _c); + }); + case 2: + return _isPlaceholder(a) && _isPlaceholder(b) ? f3 : _isPlaceholder(a) ? _curry2(function(_a, _c) { + return fn(_a, b, _c); + }) : _isPlaceholder(b) ? _curry2(function(_b, _c) { + return fn(a, _b, _c); + }) : _curry1(function(_c) { + return fn(a, b, _c); + }); + default: + return _isPlaceholder(a) && _isPlaceholder(b) && _isPlaceholder(c) ? f3 : _isPlaceholder(a) && _isPlaceholder(b) ? _curry2(function(_a, _b) { + return fn(_a, _b, c); + }) : _isPlaceholder(a) && _isPlaceholder(c) ? _curry2(function(_a, _c) { + return fn(_a, b, _c); + }) : _isPlaceholder(b) && _isPlaceholder(c) ? _curry2(function(_b, _c) { + return fn(a, _b, _c); + }) : _isPlaceholder(a) ? _curry1(function(_a) { + return fn(_a, b, c); + }) : _isPlaceholder(b) ? _curry1(function(_b) { + return fn(a, _b, c); + }) : _isPlaceholder(c) ? _curry1(function(_c) { + return fn(a, b, _c); + }) : fn(a, b, c); + } + }; +} + +// node_modules/ramda/es/internal/_isArray.js +var isArray_default = Array.isArray || function _isArray(val) { + return val != null && val.length >= 0 && Object.prototype.toString.call(val) === "[object Array]"; +}; + +// node_modules/ramda/es/internal/_isTransformer.js +function _isTransformer(obj) { + return obj != null && typeof obj["@@transducer/step"] === "function"; +} + +// node_modules/ramda/es/internal/_dispatchable.js +function _dispatchable(methodNames, transducerCreator, fn) { + return function() { + if (arguments.length === 0) { + return fn(); + } + var obj = arguments[arguments.length - 1]; + if (!isArray_default(obj)) { + var idx = 0; + while (idx < methodNames.length) { + if (typeof obj[methodNames[idx]] === "function") { + return obj[methodNames[idx]].apply(obj, Array.prototype.slice.call(arguments, 0, -1)); + } + idx += 1; + } + if (_isTransformer(obj)) { + var transducer = transducerCreator.apply(null, Array.prototype.slice.call(arguments, 0, -1)); + return transducer(obj); + } + } + return fn.apply(this, arguments); + }; +} + +// node_modules/ramda/es/internal/_xfBase.js +var xfBase_default = { + init: function() { + return this.xf["@@transducer/init"](); + }, + result: function(result) { + return this.xf["@@transducer/result"](result); + } +}; + +// node_modules/ramda/es/internal/_has.js +function _has(prop, obj) { + return Object.prototype.hasOwnProperty.call(obj, prop); +} + +// node_modules/ramda/es/internal/_isArguments.js +var toString = Object.prototype.toString; +var _isArguments = /* @__PURE__ */ function() { + return toString.call(arguments) === "[object Arguments]" ? function _isArguments2(x) { + return toString.call(x) === "[object Arguments]"; + } : function _isArguments2(x) { + return _has("callee", x); + }; +}(); +var isArguments_default = _isArguments; + +// node_modules/ramda/es/keys.js +var hasEnumBug = !/* @__PURE__ */ { + toString: null +}.propertyIsEnumerable("toString"); +var nonEnumerableProps = ["constructor", "valueOf", "isPrototypeOf", "toString", "propertyIsEnumerable", "hasOwnProperty", "toLocaleString"]; +var hasArgsEnumBug = /* @__PURE__ */ function() { + "use strict"; + return arguments.propertyIsEnumerable("length"); +}(); +var contains = function contains2(list, item) { + var idx = 0; + while (idx < list.length) { + if (list[idx] === item) { + return true; + } + idx += 1; + } + return false; +}; +var keys = typeof Object.keys === "function" && !hasArgsEnumBug ? /* @__PURE__ */ _curry1(function keys2(obj) { + return Object(obj) !== obj ? [] : Object.keys(obj); +}) : /* @__PURE__ */ _curry1(function keys3(obj) { + if (Object(obj) !== obj) { + return []; + } + var prop, nIdx; + var ks = []; + var checkArgsLength = hasArgsEnumBug && isArguments_default(obj); + for (prop in obj) { + if (_has(prop, obj) && (!checkArgsLength || prop !== "length")) { + ks[ks.length] = prop; + } + } + if (hasEnumBug) { + nIdx = nonEnumerableProps.length - 1; + while (nIdx >= 0) { + prop = nonEnumerableProps[nIdx]; + if (_has(prop, obj) && !contains(ks, prop)) { + ks[ks.length] = prop; + } + nIdx -= 1; + } + } + return ks; +}); +var keys_default = keys; + +// node_modules/ramda/es/type.js +var type = /* @__PURE__ */ _curry1(function type2(val) { + return val === null ? "Null" : val === void 0 ? "Undefined" : Object.prototype.toString.call(val).slice(8, -1); +}); +var type_default = type; + +// node_modules/ramda/es/internal/_map.js +function _map(fn, functor) { + var idx = 0; + var len = functor.length; + var result = Array(len); + while (idx < len) { + result[idx] = fn(functor[idx]); + idx += 1; + } + return result; +} + +// node_modules/ramda/es/internal/_toISOString.js +var pad = function pad2(n) { + return (n < 10 ? "0" : "") + n; +}; +var _toISOString = typeof Date.prototype.toISOString === "function" ? function _toISOString2(d) { + return d.toISOString(); +} : function _toISOString3(d) { + return d.getUTCFullYear() + "-" + pad(d.getUTCMonth() + 1) + "-" + pad(d.getUTCDate()) + "T" + pad(d.getUTCHours()) + ":" + pad(d.getUTCMinutes()) + ":" + pad(d.getUTCSeconds()) + "." + (d.getUTCMilliseconds() / 1e3).toFixed(3).slice(2, 5) + "Z"; +}; + +// node_modules/ramda/es/internal/_arrayReduce.js +function _arrayReduce(reducer, acc, list) { + var index = 0; + var length = list.length; + while (index < length) { + acc = reducer(acc, list[index]); + index += 1; + } + return acc; +} + +// node_modules/ramda/es/internal/_xmap.js +var XMap = /* @__PURE__ */ function() { + function XMap2(f, xf) { + this.xf = xf; + this.f = f; + } + XMap2.prototype["@@transducer/init"] = xfBase_default.init; + XMap2.prototype["@@transducer/result"] = xfBase_default.result; + XMap2.prototype["@@transducer/step"] = function(result, input) { + return this.xf["@@transducer/step"](result, this.f(input)); + }; + return XMap2; +}(); +var _xmap = function _xmap2(f) { + return function(xf) { + return new XMap(f, xf); + }; +}; +var xmap_default = _xmap; + +// node_modules/ramda/es/map.js +var map = /* @__PURE__ */ _curry2( + /* @__PURE__ */ _dispatchable(["fantasy-land/map", "map"], xmap_default, function map2(fn, functor) { + switch (Object.prototype.toString.call(functor)) { + case "[object Function]": + return curryN_default(functor.length, function() { + return fn.call(this, functor.apply(this, arguments)); + }); + case "[object Object]": + return _arrayReduce(function(acc, key) { + acc[key] = fn(functor[key]); + return acc; + }, {}, keys_default(functor)); + default: + return _map(fn, functor); + } + }) +); +var map_default = map; + +// node_modules/ramda/es/internal/_isInteger.js +var isInteger_default = Number.isInteger || function _isInteger(n) { + return n << 0 === n; +}; + +// node_modules/ramda/es/internal/_isString.js +function _isString(x) { + return Object.prototype.toString.call(x) === "[object String]"; +} + +// node_modules/ramda/es/nth.js +var nth = /* @__PURE__ */ _curry2(function nth2(offset, list) { + var idx = offset < 0 ? list.length + offset : offset; + return _isString(list) ? list.charAt(idx) : list[idx]; +}); +var nth_default = nth; + +// node_modules/ramda/es/internal/_isArrayLike.js +var _isArrayLike = /* @__PURE__ */ _curry1(function isArrayLike(x) { + if (isArray_default(x)) { + return true; + } + if (!x) { + return false; + } + if (typeof x !== "object") { + return false; + } + if (_isString(x)) { + return false; + } + if (x.length === 0) { + return true; + } + if (x.length > 0) { + return x.hasOwnProperty(0) && x.hasOwnProperty(x.length - 1); + } + return false; +}); +var isArrayLike_default = _isArrayLike; + +// node_modules/ramda/es/internal/_createReduce.js +var symIterator = typeof Symbol !== "undefined" ? Symbol.iterator : "@@iterator"; +function _createReduce(arrayReduce, methodReduce, iterableReduce) { + return function _reduce(xf, acc, list) { + if (isArrayLike_default(list)) { + return arrayReduce(xf, acc, list); + } + if (list == null) { + return acc; + } + if (typeof list["fantasy-land/reduce"] === "function") { + return methodReduce(xf, acc, list, "fantasy-land/reduce"); + } + if (list[symIterator] != null) { + return iterableReduce(xf, acc, list[symIterator]()); + } + if (typeof list.next === "function") { + return iterableReduce(xf, acc, list); + } + if (typeof list.reduce === "function") { + return methodReduce(xf, acc, list, "reduce"); + } + throw new TypeError("reduce: list must be array or iterable"); + }; +} + +// node_modules/ramda/es/internal/_xArrayReduce.js +function _xArrayReduce(xf, acc, list) { + var idx = 0; + var len = list.length; + while (idx < len) { + acc = xf["@@transducer/step"](acc, list[idx]); + if (acc && acc["@@transducer/reduced"]) { + acc = acc["@@transducer/value"]; + break; + } + idx += 1; + } + return xf["@@transducer/result"](acc); +} + +// node_modules/ramda/es/bind.js +var bind = /* @__PURE__ */ _curry2(function bind2(fn, thisObj) { + return _arity(fn.length, function() { + return fn.apply(thisObj, arguments); + }); +}); +var bind_default = bind; + +// node_modules/ramda/es/internal/_xReduce.js +function _xIterableReduce(xf, acc, iter) { + var step = iter.next(); + while (!step.done) { + acc = xf["@@transducer/step"](acc, step.value); + if (acc && acc["@@transducer/reduced"]) { + acc = acc["@@transducer/value"]; + break; + } + step = iter.next(); + } + return xf["@@transducer/result"](acc); +} +function _xMethodReduce(xf, acc, obj, methodName) { + return xf["@@transducer/result"](obj[methodName](bind_default(xf["@@transducer/step"], xf), acc)); +} +var _xReduce = /* @__PURE__ */ _createReduce(_xArrayReduce, _xMethodReduce, _xIterableReduce); +var xReduce_default = _xReduce; + +// node_modules/ramda/es/internal/_xwrap.js +var XWrap = /* @__PURE__ */ function() { + function XWrap2(fn) { + this.f = fn; + } + XWrap2.prototype["@@transducer/init"] = function() { + throw new Error("init not implemented on XWrap"); + }; + XWrap2.prototype["@@transducer/result"] = function(acc) { + return acc; + }; + XWrap2.prototype["@@transducer/step"] = function(acc, x) { + return this.f(acc, x); + }; + return XWrap2; +}(); +function _xwrap(fn) { + return new XWrap(fn); +} + +// node_modules/ramda/es/reduce.js +var reduce = /* @__PURE__ */ _curry3(function(xf, acc, list) { + return xReduce_default(typeof xf === "function" ? _xwrap(xf) : xf, acc, list); +}); +var reduce_default = reduce; + +// node_modules/ramda/es/always.js +var always = /* @__PURE__ */ _curry1(function always2(val) { + return function() { + return val; + }; +}); +var always_default = always; + +// node_modules/ramda/es/values.js +var values = /* @__PURE__ */ _curry1(function values2(obj) { + var props = keys_default(obj); + var len = props.length; + var vals = []; + var idx = 0; + while (idx < len) { + vals[idx] = obj[props[idx]]; + idx += 1; + } + return vals; +}); +var values_default = values; + +// node_modules/ramda/es/internal/_assoc.js +function _assoc(prop, val, obj) { + if (isInteger_default(prop) && isArray_default(obj)) { + var arr = [].concat(obj); + arr[prop] = val; + return arr; + } + var result = {}; + for (var p in obj) { + result[p] = obj[p]; + } + result[prop] = val; + return result; +} + +// node_modules/ramda/es/isNil.js +var isNil = /* @__PURE__ */ _curry1(function isNil2(x) { + return x == null; +}); +var isNil_default = isNil; + +// node_modules/ramda/es/assocPath.js +var assocPath = /* @__PURE__ */ _curry3(function assocPath2(path3, val, obj) { + if (path3.length === 0) { + return val; + } + var idx = path3[0]; + if (path3.length > 1) { + var nextObj = !isNil_default(obj) && _has(idx, obj) && typeof obj[idx] === "object" ? obj[idx] : isInteger_default(path3[1]) ? [] : {}; + val = assocPath2(Array.prototype.slice.call(path3, 1), val, nextObj); + } + return _assoc(idx, val, obj); +}); +var assocPath_default = assocPath; + +// node_modules/ramda/es/assoc.js +var assoc = /* @__PURE__ */ _curry3(function assoc2(prop, val, obj) { + return assocPath_default([prop], val, obj); +}); +var assoc_default = assoc; + +// node_modules/ramda/es/internal/_cloneRegExp.js +function _cloneRegExp(pattern) { + return new RegExp(pattern.source, pattern.flags ? pattern.flags : (pattern.global ? "g" : "") + (pattern.ignoreCase ? "i" : "") + (pattern.multiline ? "m" : "") + (pattern.sticky ? "y" : "") + (pattern.unicode ? "u" : "") + (pattern.dotAll ? "s" : "")); +} + +// node_modules/ramda/es/internal/_clone.js +function _clone(value, deep, map3) { + map3 || (map3 = new _ObjectMap()); + if (_isPrimitive(value)) { + return value; + } + var copy = function copy2(copiedValue) { + var cachedCopy = map3.get(value); + if (cachedCopy) { + return cachedCopy; + } + map3.set(value, copiedValue); + for (var key in value) { + if (Object.prototype.hasOwnProperty.call(value, key)) { + copiedValue[key] = deep ? _clone(value[key], true, map3) : value[key]; + } + } + return copiedValue; + }; + switch (type_default(value)) { + case "Object": + return copy(Object.create(Object.getPrototypeOf(value))); + case "Array": + return copy([]); + case "Date": + return new Date(value.valueOf()); + case "RegExp": + return _cloneRegExp(value); + case "Int8Array": + case "Uint8Array": + case "Uint8ClampedArray": + case "Int16Array": + case "Uint16Array": + case "Int32Array": + case "Uint32Array": + case "Float32Array": + case "Float64Array": + case "BigInt64Array": + case "BigUint64Array": + return value.slice(); + default: + return value; + } +} +function _isPrimitive(param) { + var type3 = typeof param; + return param == null || type3 != "object" && type3 != "function"; +} +var _ObjectMap = /* @__PURE__ */ function() { + function _ObjectMap2() { + this.map = {}; + this.length = 0; + } + _ObjectMap2.prototype.set = function(key, value) { + const hashedKey = this.hash(key); + let bucket = this.map[hashedKey]; + if (!bucket) { + this.map[hashedKey] = bucket = []; + } + bucket.push([key, value]); + this.length += 1; + }; + _ObjectMap2.prototype.hash = function(key) { + let hashedKey = []; + for (var value in key) { + hashedKey.push(Object.prototype.toString.call(key[value])); + } + return hashedKey.join(); + }; + _ObjectMap2.prototype.get = function(key) { + if (this.length <= 180) { + for (const p in this.map) { + const bucket2 = this.map[p]; + for (let i = 0; i < bucket2.length; i += 1) { + const element = bucket2[i]; + if (element[0] === key) { + return element[1]; + } + } + } + return; + } + const hashedKey = this.hash(key); + const bucket = this.map[hashedKey]; + if (!bucket) { + return; + } + for (let i = 0; i < bucket.length; i += 1) { + const element = bucket[i]; + if (element[0] === key) { + return element[1]; + } + } + }; + return _ObjectMap2; +}(); + +// node_modules/ramda/es/clone.js +var clone = /* @__PURE__ */ _curry1(function clone2(value) { + return value != null && typeof value.clone === "function" ? value.clone() : _clone(value, true); +}); +var clone_default = clone; + +// node_modules/ramda/es/not.js +var not = /* @__PURE__ */ _curry1(function not2(a) { + return !a; +}); +var not_default = not; + +// node_modules/ramda/es/internal/_pipe.js +function _pipe(f, g) { + return function() { + return g.call(this, f.apply(this, arguments)); + }; +} + +// node_modules/ramda/es/internal/_checkForMethod.js +function _checkForMethod(methodname, fn) { + return function() { + var length = arguments.length; + if (length === 0) { + return fn(); + } + var obj = arguments[length - 1]; + return isArray_default(obj) || typeof obj[methodname] !== "function" ? fn.apply(this, arguments) : obj[methodname].apply(obj, Array.prototype.slice.call(arguments, 0, length - 1)); + }; +} + +// node_modules/ramda/es/slice.js +var slice = /* @__PURE__ */ _curry3( + /* @__PURE__ */ _checkForMethod("slice", function slice2(fromIndex, toIndex, list) { + return Array.prototype.slice.call(list, fromIndex, toIndex); + }) +); +var slice_default = slice; + +// node_modules/ramda/es/tail.js +var tail = /* @__PURE__ */ _curry1( + /* @__PURE__ */ _checkForMethod( + "tail", + /* @__PURE__ */ slice_default(1, Infinity) + ) +); +var tail_default = tail; + +// node_modules/ramda/es/pipe.js +function pipe() { + if (arguments.length === 0) { + throw new Error("pipe requires at least one argument"); + } + return _arity(arguments[0].length, reduce_default(_pipe, arguments[0], tail_default(arguments))); +} + +// node_modules/ramda/es/reverse.js +var reverse = /* @__PURE__ */ _curry1(function reverse2(list) { + return _isString(list) ? list.split("").reverse().join("") : Array.prototype.slice.call(list, 0).reverse(); +}); +var reverse_default = reverse; + +// node_modules/ramda/es/compose.js +function compose() { + if (arguments.length === 0) { + throw new Error("compose requires at least one argument"); + } + return pipe.apply(this, reverse_default(arguments)); +} + +// node_modules/ramda/es/head.js +var head = /* @__PURE__ */ nth_default(0); +var head_default = head; + +// node_modules/ramda/es/remove.js +var remove = /* @__PURE__ */ _curry3(function remove2(start, count, list) { + var result = Array.prototype.slice.call(list, 0); + result.splice(start, count); + return result; +}); +var remove_default = remove; + +// node_modules/ramda/es/internal/_dissoc.js +function _dissoc(prop, obj) { + if (obj == null) { + return obj; + } + if (isInteger_default(prop) && isArray_default(obj)) { + return remove_default(prop, 1, obj); + } + var result = {}; + for (var p in obj) { + result[p] = obj[p]; + } + delete result[prop]; + return result; +} + +// node_modules/ramda/es/dissocPath.js +function _shallowCloneObject(prop, obj) { + if (isInteger_default(prop) && isArray_default(obj)) { + return [].concat(obj); + } + var result = {}; + for (var p in obj) { + result[p] = obj[p]; + } + return result; +} +var dissocPath = /* @__PURE__ */ _curry2(function dissocPath2(path3, obj) { + if (obj == null) { + return obj; + } + switch (path3.length) { + case 0: + return obj; + case 1: + return _dissoc(path3[0], obj); + default: + var head2 = path3[0]; + var tail2 = Array.prototype.slice.call(path3, 1); + if (obj[head2] == null) { + return _shallowCloneObject(head2, obj); + } else { + return assoc_default(head2, dissocPath2(tail2, obj[head2]), obj); + } + } +}); +var dissocPath_default = dissocPath; + +// node_modules/ramda/es/dissoc.js +var dissoc = /* @__PURE__ */ _curry2(function dissoc2(prop, obj) { + return dissocPath_default([prop], obj); +}); +var dissoc_default = dissoc; + +// node_modules/ramda/es/internal/_objectAssign.js +function _objectAssign(target) { + if (target == null) { + throw new TypeError("Cannot convert undefined or null to object"); + } + var output = Object(target); + var idx = 1; + var length = arguments.length; + while (idx < length) { + var source = arguments[idx]; + if (source != null) { + for (var nextKey in source) { + if (_has(nextKey, source)) { + output[nextKey] = source[nextKey]; + } + } + } + idx += 1; + } + return output; +} +var objectAssign_default = typeof Object.assign === "function" ? Object.assign : _objectAssign; + +// node_modules/ramda/es/lens.js +var lens = /* @__PURE__ */ _curry2(function lens2(getter, setter) { + return function(toFunctorFn) { + return function(target) { + return map_default(function(focus) { + return setter(focus, target); + }, toFunctorFn(getter(target))); + }; + }; +}); +var lens_default = lens; + +// node_modules/ramda/es/paths.js +var paths = /* @__PURE__ */ _curry2(function paths2(pathsArray, obj) { + return pathsArray.map(function(paths3) { + var val = obj; + var idx = 0; + var p; + while (idx < paths3.length) { + if (val == null) { + return; + } + p = paths3[idx]; + val = isInteger_default(p) ? nth_default(p, val) : val[p]; + idx += 1; + } + return val; + }); +}); +var paths_default = paths; + +// node_modules/ramda/es/path.js +var path = /* @__PURE__ */ _curry2(function path2(pathAr, obj) { + return paths_default([pathAr], obj)[0]; +}); +var path_default = path; + +// node_modules/ramda/es/lensPath.js +var lensPath = /* @__PURE__ */ _curry1(function lensPath2(p) { + return lens_default(path_default(p), assocPath_default(p)); +}); +var lensPath_default = lensPath; + +// node_modules/ramda/es/mapObjIndexed.js +var mapObjIndexed = /* @__PURE__ */ _curry2(function mapObjIndexed2(fn, obj) { + return _arrayReduce(function(acc, key) { + acc[key] = fn(obj[key], key, obj); + return acc; + }, {}, keys_default(obj)); +}); +var mapObjIndexed_default = mapObjIndexed; + +// node_modules/ramda/es/sum.js +var sum = /* @__PURE__ */ reduce_default(add_default, 0); +var sum_default = sum; + +// node_modules/ramda/es/mergeAll.js +var mergeAll = /* @__PURE__ */ _curry1(function mergeAll2(list) { + return objectAssign_default.apply(null, [{}].concat(list)); +}); +var mergeAll_default = mergeAll; + +// node_modules/ramda/es/over.js +var Identity = function(x) { + return { + value: x, + map: function(f) { + return Identity(f(x)); + } + }; +}; +var over = /* @__PURE__ */ _curry3(function over2(lens3, f, x) { + return lens3(function(y) { + return Identity(f(y)); + })(x).value; +}); +var over_default = over; + +// node_modules/ramda/es/set.js +var set = /* @__PURE__ */ _curry3(function set2(lens3, v, x) { + return over_default(lens3, always_default(v), x); +}); +var set_default = set; + +// node_modules/ramda/es/toPairs.js +var toPairs = /* @__PURE__ */ _curry1(function toPairs2(obj) { + var pairs = []; + for (var prop in obj) { + if (_has(prop, obj)) { + pairs[pairs.length] = [prop, obj[prop]]; + } + } + return pairs; +}); +var toPairs_default = toPairs; + +// node_modules/ramda/es/trim.js +var hasProtoTrim = typeof String.prototype.trim === "function"; + +// src/lib/allocate.js +function allocate(balances, reward2) { + var total = reduce_default( + add_default, + 0, + values_default(balances).filter((v) => v > 0) + ); + const allocation = mergeAll_default( + reduce_default( + (a, s) => { + const asset = s[0]; + const balance2 = s[1]; + if (balance2 < 1) { + return a; + } + var pct = balance2 / total * 100; + const coins = Math.round(reward2 * (pct / 100)); + return [...a, { [asset]: Number(coins) }]; + }, + [], + Object.entries(balances) + ) + ); + var remainder = reward2 - sum_default(values_default(allocation)); + var iterator = keys_default(allocation).entries(); + while (remainder > 0) { + allocation[iterator.next().value[1]]++; + remainder--; + } + return allocation; +} + +// src/cron/reward.js +var DAY = 720; +var TOTAL_SUPPLY = 2628e4 * 1e6; +var HALVING_SUPPLY = TOTAL_SUPPLY * 0.9; +var ORIGIN_HEIGHT = 1232615; +var CYCLE_INTERVAL = DAY * 365; +function reward(state) { + if (state.lastReward + DAY >= SmartWeave.block.height) { + return state; + } + if (keys_default(state.streaks).length < 1) { + return state; + } + const { reward: reward2 } = setReward(SmartWeave.block.height)({ state }); + if (reward2 === 0) { + return state; + } + state.streaks = keys_default(state.streaks).reduce((a, k) => { + if (state.streaks[k].lastHeight > SmartWeave.block.height - DAY * 2) { + return { ...a, [k]: state.streaks[k] }; + } + return a; + }, {}); + if (keys_default(state.streaks).length === 0) { + return state; + } + const streaks = assignPoints(state.streaks); + state.recentRewards = allocate(streaks, reward2); + state = updateBalances({ state, rewards: state.recentRewards }); + state.lastReward = SmartWeave.block.height; + return state; +} +function assignPoints(streaks) { + return keys_default(streaks).reduce((a, k) => { + if (streaks[k].days > 0) { + const multiplier = streaks[k].days - 1; + return assoc_default(k, 1 + multiplier * 0.1, a); + } else { + return a; + } + }, {}); +} +function setReward(height) { + return ({ state }) => { + const S100 = 1 * 1e6; + const current = sum_default(values_default(state.balances)) || 0; + if (current >= HALVING_SUPPLY) { + if (!state.balances[contractId]) { + state.balances[contractId] = 0; + } + return 0; + } + const reward2 = getReward( + HALVING_SUPPLY, + CYCLE_INTERVAL, + height, + ORIGIN_HEIGHT + ); + return { state, reward: reward2 }; + }; +} +function updateBalances({ state, rewards }) { + keys_default(rewards).forEach((k) => { + if (!state.balances[k]) { + state.balances[k] = 0; + } + state.balances[k] += rewards[k]; + }); + return state; +} +function getReward(supply, interval, currentHeight, originHeight) { + const blockHeight = currentHeight - originHeight; + const currentCycle = Math.floor(blockHeight / interval) + 1; + const divisor = Math.pow(2, currentCycle); + const reward2 = Math.floor(Math.floor(supply / divisor) / 365); + return reward2; +} + +// src/write/cancel-claim.js +var cancelClaim = async (state, action) => { + ContractAssert(action.input.contract, "contract is required"); + ContractAssert(action.input.transaction, "transaction is required"); + ContractAssert(action.input.qty, "transaction is required"); + ContractAssert(action.input.contract.length === 43, "contract is not valid"); + ContractAssert(action.input.transaction.length === 43, "transaction is not valid"); + ContractAssert(Number.isInteger(action.input.qty), "qty must be integer"); + await SmartWeave.contracts.write(action.input.contract, { + function: "reject", + tx: action.input.transaction, + qty: action.input.qty + }); + return { state }; +}; + +// src/write/contributor-mint.js +var TOTAL_SUPPLY2 = 2628e4 * 1e6; +var REWARD_SUPPY = TOTAL_SUPPLY2 * 0.1; +var REWARD_VESTING_PERIOD = 720 * 365 * 4; +var REWARD_UNIT_PER_HEIGHT = Math.floor(REWARD_SUPPY / REWARD_VESTING_PERIOD); +function contributorMint(state, action) { + const currentHeight = SmartWeave.block.height; + const originHeight = state.originHeight; + return of({ + state, + contributor: action.caller, + height: { + origin: originHeight, + current: currentHeight + } + }).chain(getContributor).map(calcBlockDiff).map(calcRewardAmount).map(allocateForTier).map(allocateForMember).map(updateBalances2).map(setLastMint4Member); +} +function setLastMint4Member(ctx) { + const lastMintPath = ["contributors", "tiers", ctx.contributor.tier.name, "members", ctx.contributor.addr, "lastMint"]; + ctx.state = set_default(lensPath_default(lastMintPath), ctx.height.current, ctx.state); + return { state: ctx.state }; +} +function updateBalances2(ctx) { + const { state } = ctx; + if (!state.balances[ctx.contributor.addr]) { + state.balances[ctx.contributor.addr] = 0; + } + state.balances[ctx.contributor.addr] += ctx.rewardMember; + return assoc_default("state", state, ctx); +} +function allocateForMember(ctx) { + const members = ctx.state.contributors.tiers[ctx.contributor.tier.name].members; + const table = reduce_default((acc, [key, value]) => assoc_default(key, value.amount, acc), {}, toPairs_default(members)); + const reward2 = allocate(table, ctx.rewardTier); + return assoc_default("rewardMember", reward2[ctx.contributor.addr], ctx); +} +function allocateForTier(ctx) { + const { contributor, reward: reward2 } = ctx; + const rewardTier = Math.floor(reward2 * (contributor.tier.percent / 100)); + return assoc_default("rewardTier", rewardTier, ctx); +} +function calcRewardAmount(ctx) { + const { height } = ctx; + const reward2 = height.diff * REWARD_UNIT_PER_HEIGHT; + return assoc_default("reward", reward2, ctx); +} +function calcBlockDiff(ctx) { + const height = ctx.height; + const contributor = ctx.contributor; + const start = contributor.lastMint === 0 ? height.origin : contributor.lastMint; + const diff = height.current - start; + return assoc_default("height", { ...height, diff }, ctx); +} +function getContributor({ state, contributor, height }) { + return compose( + (c) => c ? Right({ state, contributor: c, height }) : Left("could not find"), + head_default, + map_default((m) => m[contributor]), + (tiers) => { + const members = reduce_default((a, [tierName, tierValue]) => { + const o = mapObjIndexed_default((d, k) => { + return { ...d, tier: { name: tierName, percent: tierValue.percent }, addr: k }; + }, tierValue.members); + return a.concat(o); + }, [], toPairs_default(tiers)); + return members; + }, + path_default(["contributors", "tiers"]) + )(state); +} + +// src/write/contributor-chg.js +function contributorChg(state, action) { + return of({ state, action }).chain(validate6).map(cloneMembers).map(setTarget).map(dissocCaller).map(attachMembers); +} +function attachMembers(ctx) { + ctx.state.contributors.tiers[ctx.tier].members = ctx.members; + return { state: ctx.state }; +} +function dissocCaller(ctx) { + ctx.members = dissoc_default(ctx.caller, ctx.members); + return ctx; +} +function setTarget(ctx) { + ctx.members = assoc_default(ctx.target, ctx.members[ctx.caller], ctx.members); + return ctx; +} +function cloneMembers(ctx) { + return { ...ctx, members: clone_default(path_default(["contributors", "tiers", ctx.tier, "members"], ctx.state)) }; +} +function validate6({ state, action }) { + if (not_default(action.input.tier)) { + return Left("Tier Input is required"); + } + if (not_default(action.input.target)) { + return Left("Target Input is required"); + } + return Right({ + state, + caller: action.caller, + tier: action.input.tier, + target: action.input.target + }); +} + +// src/write/evolve.js +var EVOLVE_WINDOW = 720 * 180; +function evolve(state, action) { + if (state.canEvolve && SmartWeave.block.height < state.originHeight + EVOLVE_WINDOW) { + if (SmartWeave.contract.owner === action.caller) { + state.evolve = action.input.value; + } + } + return { state }; +} + +// src/index.js +var identity = (x) => x; +export async function handle(state, action) { + async function CreateOrderPlusBuyback(state2, action2) { + const result = await CreateOrder(state2, action2); + return result; + } + validate3(state); + if (action.input.function === "createOrder") { + state = reward(state); + } + if (action.input.function === "createOrder" && !action.input.price) { + state = await buyback(state); + } + switch (action?.input?.function) { + case "noop": + return { state }; + case "addPair": + return addPair(state, action).extract(); + case "createOrder": + return CreateOrderPlusBuyback(state, action); + case "cancelOrder": + return CancelOrder(state, action); + case "cancelClaim": + return cancelClaim(state, action); + case "balance": + return balance(state, action); + case "transfer": + return transfer(state, action).fold(handleError, identity); + case "allow": + return allow(state, action).fold(handleError, identity); + case "claim": + return claim(state, action).fold(handleError, identity); + case "contributorMint": + return contributorMint(state, action).fold(handleError, identity); + case "contributorChg": + return contributorChg(state, action).fold(handleError, identity); + case "evolve": + return evolve(state, action); + default: + throw new ContractError("No Function Found"); + } +} +function handleError(msg) { + throw new ContractError(msg); +} diff --git a/yarn.lock b/yarn.lock index 4c7242ef..caff032c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7658,10 +7658,31 @@ warp-contracts-plugin-vrf@^1.0.3: "@idena/vrf-js" "^1.0.1" elliptic "^6.5.4" -warp-contracts-sqlite@^1.0.3-beta.1: - version "1.0.3-beta.1" - resolved "https://registry.yarnpkg.com/warp-contracts-sqlite/-/warp-contracts-sqlite-1.0.3-beta.1.tgz#dbacb6dd5ff1c1b5e0647d3ae79f20d49214e364" - integrity sha512-0YDO60LIau8D9UQzSKLkLSAlSpMyi9vEo7x72/Rt7vMMvVHp8J9af3eG7LZ+yT+29LJlWzCWkMTTYE3koYViCA== +"warp-contracts-rc@npm:warp-contracts@1.4.15-rc.4": + version "1.4.15-rc.4" + resolved "https://registry.yarnpkg.com/warp-contracts/-/warp-contracts-1.4.15-rc.4.tgz#cd41f3caa4110107bb4ff67b8ecccf2d5bff3a68" + integrity sha512-E5apjSRBLD9ifQ9D0znCpn8MfERz7wVv3fLoryYqr7EuDUYMnoqFiKBF0LP0ayvu1JcUCav41AaHi+dsf3O31w== + dependencies: + archiver "^5.3.0" + arweave "1.13.7" + async-mutex "^0.4.0" + better-sqlite3 "^8.5.0" + bignumber.js "9.1.1" + events "3.3.0" + fast-copy "^3.0.0" + level "^8.0.0" + memory-level "^1.0.0" + safe-stable-stringify "2.4.1" + stream-buffers "^3.0.2" + unzipit "^1.4.0" + warp-arbundles "1.0.1" + warp-isomorphic "1.0.4" + warp-wasm-metering "1.0.1" + +warp-contracts-sqlite@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/warp-contracts-sqlite/-/warp-contracts-sqlite-1.0.2.tgz#f690f3ad5832b8522baed2420437d1aa5214bab1" + integrity sha512-mBDTfexgBTEeUhddC3P438y03T4mEfDadzC32cyYOE8jQE1wfYF3GTFhTkz0eT+Z5o+DAT+4Ed+2Mxk5BSQMmw== dependencies: better-sqlite3 "^8.3.0" safe-stable-stringify "^2.4.3"