mirror of
https://github.com/wharfkit/resources.git
synced 2026-07-21 18:03:39 +00:00
initial commit
This commit is contained in:
@@ -0,0 +1,12 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"root": true,
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"plugins": ["@typescript-eslint"],
|
||||
"ignorePatterns": ["lib/*", "node_modules/**"],
|
||||
"extends": [
|
||||
"eslint:recommended",
|
||||
"plugin:prettier/recommended",
|
||||
"plugin:@typescript-eslint/eslint-recommended",
|
||||
"plugin:@typescript-eslint/recommended"
|
||||
],
|
||||
"rules": {
|
||||
"prettier/prettier": "warn",
|
||||
"no-console": "warn",
|
||||
"sort-imports": [
|
||||
"warn",
|
||||
{
|
||||
"ignoreCase": true,
|
||||
"ignoreDeclarationSort": true
|
||||
}
|
||||
],
|
||||
"@typescript-eslint/explicit-module-boundary-types": "off",
|
||||
"@typescript-eslint/no-explicit-any": "off",
|
||||
"@typescript-eslint/no-namespace": "off",
|
||||
"@typescript-eslint/no-non-null-assertion": "off",
|
||||
"@typescript-eslint/no-empty-function": "warn",
|
||||
"no-inner-declarations": "off",
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
custom: "https://greymass.com/support-us"
|
||||
@@ -0,0 +1,19 @@
|
||||
name: Tests
|
||||
on: push
|
||||
jobs:
|
||||
test:
|
||||
name: Node 14
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: '14'
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
- name: Install dependencies
|
||||
run: make node_modules
|
||||
- name: Run tests
|
||||
run: make ci-test
|
||||
- name: Run linter
|
||||
run: make ci-lint
|
||||
@@ -0,0 +1,5 @@
|
||||
node_modules/
|
||||
lib/
|
||||
coverage/
|
||||
.nyc_output/
|
||||
docs/
|
||||
@@ -0,0 +1,8 @@
|
||||
arrowParens: "always"
|
||||
bracketSpacing: false
|
||||
endOfLine: "lf"
|
||||
printWidth: 100
|
||||
semi: false
|
||||
singleQuote: true
|
||||
tabWidth: 4
|
||||
trailingComma: "es5"
|
||||
Vendored
+4
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
"editor.formatOnSave": true
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
Copyright (c) 2021 Greymass Inc. All Rights Reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistribution of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistribution in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
YOU ACKNOWLEDGE THAT THIS SOFTWARE IS NOT DESIGNED, LICENSED OR INTENDED FOR USE
|
||||
IN THE DESIGN, CONSTRUCTION, OPERATION OR MAINTENANCE OF ANY MILITARY FACILITY.
|
||||
@@ -0,0 +1,50 @@
|
||||
SRC_FILES := $(shell find src -name '*.ts')
|
||||
BIN := ./node_modules/.bin
|
||||
|
||||
lib: ${SRC_FILES} package.json tsconfig.json node_modules rollup.config.js
|
||||
@${BIN}/rollup -c && touch lib
|
||||
|
||||
.PHONY: test
|
||||
test: node_modules
|
||||
@TS_NODE_PROJECT='./test/tsconfig.json' ${BIN}/mocha \
|
||||
-u tdd -r ts-node/register --extension ts test/*.ts --grep '$(grep)'
|
||||
|
||||
.PHONY: coverage
|
||||
coverage: node_modules
|
||||
@TS_NODE_PROJECT='./test/tsconfig.json' ${BIN}/nyc --reporter=html \
|
||||
${BIN}/mocha -u tdd -r ts-node/register --extension ts test/*.ts \
|
||||
-R nyan && open coverage/index.html
|
||||
|
||||
.PHONY: lint
|
||||
lint: node_modules
|
||||
@${BIN}/eslint src --ext .ts --fix
|
||||
|
||||
.PHONY: ci-test
|
||||
ci-test: node_modules
|
||||
@TS_NODE_PROJECT='./test/tsconfig.json' ${BIN}/nyc --reporter=text \
|
||||
${BIN}/mocha -u tdd -r ts-node/register --extension ts test/*.ts -R list
|
||||
|
||||
.PHONY: ci-lint
|
||||
ci-lint: node_modules
|
||||
@${BIN}/eslint src --ext .ts --max-warnings 0 --format unix && echo "Ok"
|
||||
|
||||
docs: $(SRC_FILES) node_modules
|
||||
@${BIN}/typedoc --out docs \
|
||||
--excludeInternal --excludePrivate --excludeProtected \
|
||||
--includeVersion --readme none \
|
||||
src/index.ts
|
||||
|
||||
.PHONY: deploy-pages
|
||||
deploy-pages: docs
|
||||
@${BIN}/gh-pages -d docs
|
||||
|
||||
node_modules:
|
||||
yarn install --non-interactive --frozen-lockfile --ignore-scripts
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -rf lib/ coverage/ docs/
|
||||
|
||||
.PHONY: distclean
|
||||
distclean: clean
|
||||
rm -rf node_modules/
|
||||
@@ -0,0 +1,25 @@
|
||||
# eosio-resources
|
||||
|
||||
## Installation
|
||||
|
||||
The `eosio-resources` package is distributed as a module on [npm](https://www.npmjs.com/package/eosio-resources).
|
||||
|
||||
```
|
||||
yarn add eosio-resources
|
||||
# or
|
||||
npm install --save eosio-resources
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
TODO
|
||||
|
||||
## Developing
|
||||
|
||||
You need [Make](https://www.gnu.org/software/make/), [node.js](https://nodejs.org/en/) and [yarn](https://classic.yarnpkg.com/en/docs/install) installed.
|
||||
|
||||
Clone the repository and run `make` to checkout all dependencies and build the project. See the [Makefile](./Makefile) for other useful targets. Before submitting a pull request make sure to run `make lint`.
|
||||
|
||||
---
|
||||
|
||||
Made with ☕️ & ❤️ by [Greymass](https://greymass.com), if you find this useful please consider [supporting us](https://greymass.com/support-us).
|
||||
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"name": "@greymass/eosio-resources",
|
||||
"description": "Library to assist in EOSIO Resource calculations.",
|
||||
"version": "0.0.1",
|
||||
"homepage": "https://github.com/greymass/eosio-resources",
|
||||
"license": "BSD-3-Clause",
|
||||
"main": "lib/eosio-resources.js",
|
||||
"module": "lib/eosio-resources.m.js",
|
||||
"types": "lib/eosio-resources.d.ts",
|
||||
"browser": {
|
||||
"buffer": false,
|
||||
"crypto": false
|
||||
},
|
||||
"sideEffects": false,
|
||||
"files": [
|
||||
"lib/*",
|
||||
"src/*"
|
||||
],
|
||||
"scripts": {
|
||||
"prepare": "make"
|
||||
},
|
||||
"dependencies": {
|
||||
"@greymass/eosio": "^0.3.0",
|
||||
"tslib": "^2.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rollup/plugin-typescript": "^8.1.1",
|
||||
"@types/mocha": "^8.0.3",
|
||||
"@types/node": "^14.14.28",
|
||||
"@typescript-eslint/eslint-plugin": "^4.15.1",
|
||||
"@typescript-eslint/parser": "^4.15.1",
|
||||
"assert": "^2.0.0",
|
||||
"eslint": "^7.19.0",
|
||||
"eslint-config-prettier": "^7.0.0",
|
||||
"eslint-plugin-prettier": "^3.2.0",
|
||||
"gh-pages": "^3.1.0",
|
||||
"node-fetch": "^2.6.1",
|
||||
"mocha": "^8.2.1",
|
||||
"nyc": "^15.1.0",
|
||||
"prettier": "^2.2.1",
|
||||
"rollup": "^2.38.2",
|
||||
"rollup-plugin-dts": "^2.0.0",
|
||||
"ts-node": "^9.1.0",
|
||||
"typedoc": "^0.20.25",
|
||||
"typescript": "^4.1.2"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
import fs from 'fs'
|
||||
import dts from 'rollup-plugin-dts'
|
||||
import typescript from '@rollup/plugin-typescript'
|
||||
|
||||
import pkg from './package.json'
|
||||
|
||||
const name = pkg.name
|
||||
const license = fs.readFileSync('LICENSE').toString('utf-8').trim()
|
||||
const banner = `
|
||||
/**
|
||||
* ${name} v${pkg.version}
|
||||
* ${pkg.homepage}
|
||||
*
|
||||
* @license
|
||||
* ${license.replace(/\n/g, '\n * ')}
|
||||
*/
|
||||
`.trim()
|
||||
|
||||
const external = Object.keys(pkg.dependencies)
|
||||
|
||||
export default [
|
||||
{
|
||||
input: 'src/index.ts',
|
||||
output: {
|
||||
banner,
|
||||
file: pkg.main,
|
||||
format: 'cjs',
|
||||
sourcemap: true,
|
||||
},
|
||||
plugins: [typescript({target: 'es6'})],
|
||||
external,
|
||||
onwarn,
|
||||
},
|
||||
{
|
||||
input: 'src/index.ts',
|
||||
output: {
|
||||
banner,
|
||||
file: pkg.module,
|
||||
format: 'esm',
|
||||
sourcemap: true,
|
||||
},
|
||||
plugins: [typescript({target: 'esnext'})],
|
||||
external,
|
||||
onwarn,
|
||||
},
|
||||
{
|
||||
input: 'src/index.ts',
|
||||
output: {banner, file: pkg.types, format: 'esm'},
|
||||
onwarn,
|
||||
plugins: [dts()],
|
||||
},
|
||||
]
|
||||
|
||||
function onwarn(warning, rollupWarn) {
|
||||
if (warning.code === 'CIRCULAR_DEPENDENCY') {
|
||||
// unnecessary warning
|
||||
return
|
||||
}
|
||||
if (
|
||||
warning.code === 'UNUSED_EXTERNAL_IMPORT' &&
|
||||
warning.source === 'tslib' &&
|
||||
warning.names[0] === '__read'
|
||||
) {
|
||||
// when using ts with importHelpers: true rollup complains about this
|
||||
// seems safe to ignore since __read is not actually imported or used anywhere in the resulting bundles
|
||||
return
|
||||
}
|
||||
rollupWarn(warning)
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
import {Asset, Float64, Int64, Struct, TimePointSec, UInt32, UInt64, UInt8} from '@greymass/eosio'
|
||||
|
||||
@Struct.type('powerupstateresource')
|
||||
export class PowerUpStateResource extends Struct {
|
||||
@Struct.field('uint8') version!: UInt8
|
||||
@Struct.field('int64') weight!: Int64
|
||||
@Struct.field('int64') weight_ratio!: Int64
|
||||
@Struct.field('int64') assumed_stake_weight!: Int64
|
||||
@Struct.field('int64') initial_weight_ratio!: Int64
|
||||
@Struct.field('int64') target_weight_ratio!: Int64
|
||||
@Struct.field('time_point_sec') initial_timestamp!: TimePointSec
|
||||
@Struct.field('time_point_sec') target_timestamp!: TimePointSec
|
||||
@Struct.field('float64') exponent!: Float64
|
||||
@Struct.field('uint32') decay_secs!: UInt32
|
||||
@Struct.field('asset') min_price!: Asset
|
||||
@Struct.field('asset') max_price!: Asset
|
||||
@Struct.field('int64') utilization!: Int64
|
||||
@Struct.field('int64') adjusted_utilization!: Int64
|
||||
@Struct.field('time_point_sec') utilization_timestamp!: TimePointSec
|
||||
}
|
||||
|
||||
@Struct.type('powerupstate')
|
||||
export class PowerUpState extends Struct {
|
||||
@Struct.field('uint8') version!: UInt8
|
||||
@Struct.field(PowerUpStateResource) net!: PowerUpStateResource
|
||||
@Struct.field(PowerUpStateResource) cpu!: PowerUpStateResource
|
||||
@Struct.field('uint32') powerup_days!: UInt32
|
||||
@Struct.field('asset') min_powerup_fee!: Asset
|
||||
}
|
||||
|
||||
@Struct.type('rexstate')
|
||||
export class REXState extends Struct {
|
||||
@Struct.field('uint8') version!: UInt8
|
||||
@Struct.field('asset') total_lent!: Asset
|
||||
@Struct.field('asset') total_unlent!: Asset
|
||||
@Struct.field('asset') total_rent!: Asset
|
||||
@Struct.field('asset') total_lendable!: Asset
|
||||
@Struct.field('asset') total_rex!: Asset
|
||||
@Struct.field('asset') namebid_proceeds!: Asset
|
||||
@Struct.field('uint64') loan_num!: UInt64
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
import {APIClient} from '@greymass/eosio'
|
||||
|
||||
import {PowerUpAPI} from './powerup'
|
||||
import {REXAPI} from './rex'
|
||||
|
||||
interface ResourcesOptions {
|
||||
api?: APIClient
|
||||
symbol?: string
|
||||
url?: string
|
||||
}
|
||||
|
||||
interface SampleUsage {
|
||||
cpu: number
|
||||
net: number
|
||||
}
|
||||
|
||||
export class Resources {
|
||||
static __className = 'Resources'
|
||||
|
||||
readonly api: APIClient
|
||||
|
||||
// target rex weight at end of any existing transition
|
||||
rex_target_weight = Math.pow(10, 13)
|
||||
|
||||
// ms per day
|
||||
mspd = 200 * 2 * 60 * 60 * 24
|
||||
|
||||
// token precision/symbol
|
||||
symbol = '4,EOS'
|
||||
|
||||
constructor(options: ResourcesOptions) {
|
||||
if (options.api) {
|
||||
this.api = options.api
|
||||
} else if (options.url) {
|
||||
this.api = new APIClient({url: options.url})
|
||||
} else {
|
||||
throw new Error('Missing url or api client')
|
||||
}
|
||||
}
|
||||
|
||||
v1 = {
|
||||
powerup: new PowerUpAPI(this),
|
||||
rex: new REXAPI(this),
|
||||
}
|
||||
|
||||
async getSampledUsage(): Promise<SampleUsage> {
|
||||
const account = await this.api.v1.chain.get_account('teamgreymass')
|
||||
return {
|
||||
cpu: account.cpu_limit.max.value / account.total_resources.cpu_weight.value / 1000,
|
||||
net: account.net_limit.max.value / account.total_resources.net_weight.value / 1000,
|
||||
}
|
||||
}
|
||||
}
|
||||
+108
@@ -0,0 +1,108 @@
|
||||
import {Asset} from '@greymass/eosio'
|
||||
|
||||
import {Resources} from '.'
|
||||
import {PowerUpState} from './abi-types'
|
||||
|
||||
export class PowerUpAPI {
|
||||
constructor(private parent: Resources) {}
|
||||
|
||||
async get_state() {
|
||||
const response = await this.parent.api.v1.chain.get_table_rows({
|
||||
code: 'eosio',
|
||||
scope: '',
|
||||
table: 'powup.state',
|
||||
type: PowerUpState,
|
||||
})
|
||||
return response.rows[0]
|
||||
}
|
||||
|
||||
async get_reserved(resource: string) {
|
||||
const state = await this.get_state()
|
||||
const {utilization, weight} = state[resource]
|
||||
return Number(utilization) / Number(weight)
|
||||
}
|
||||
|
||||
async get_allocated() {
|
||||
const state = await this.get_state()
|
||||
const {weight_ratio} = state.cpu
|
||||
return 1 - Number(weight_ratio) / this.parent.rex_target_weight / 100
|
||||
}
|
||||
|
||||
async get_price_per_ms(ms = 1): Promise<Asset> {
|
||||
// Retrieve state
|
||||
const state = await this.get_state()
|
||||
const allocated = await this.get_allocated()
|
||||
|
||||
// Casting EOSIO types to usable formats for JS calculations
|
||||
let adjusted_utilization = Number(state.cpu.adjusted_utilization)
|
||||
const decay_secs = Number(state.cpu.decay_secs.value)
|
||||
const exponent = Number(state.cpu.exponent)
|
||||
const max_price: number = state.cpu.max_price.value
|
||||
const min_price: number = state.cpu.min_price.value
|
||||
const utilization = Number(state.cpu.utilization)
|
||||
const utilization_timestamp = Number(state.cpu.utilization_timestamp.value)
|
||||
const weight = Number(state.cpu.weight)
|
||||
|
||||
// Milliseconds available per day available in PowerUp (factoring in shift)
|
||||
const mspdAvailable = this.parent.mspd * allocated
|
||||
|
||||
// Percentage to rent
|
||||
const percentToRent = ms / mspdAvailable
|
||||
const utilization_increase = weight * percentToRent
|
||||
|
||||
// If utilization is less than adjusted, calculate real time value
|
||||
if (utilization < adjusted_utilization) {
|
||||
// Create now & adjust JS timestamp to match EOSIO timestamp values
|
||||
const now: number = Math.floor(Date.now() / 1000)
|
||||
const diff: number = adjusted_utilization - utilization
|
||||
let delta: number = Math.floor(
|
||||
diff * Math.exp(-(now - utilization_timestamp) / decay_secs)
|
||||
)
|
||||
delta = Math.min(Math.max(delta, 0), diff) // Clamp the delta
|
||||
adjusted_utilization = utilization + delta
|
||||
}
|
||||
|
||||
const price_integral_delta = (
|
||||
start_utilization: number,
|
||||
end_utilization: number
|
||||
): number => {
|
||||
const coefficient = (max_price - min_price) / exponent
|
||||
const start_u = start_utilization / weight
|
||||
const end_u = end_utilization / weight
|
||||
return (
|
||||
min_price * end_u -
|
||||
min_price * start_u +
|
||||
coefficient * Math.pow(end_u, exponent) -
|
||||
coefficient * Math.pow(start_u, exponent)
|
||||
)
|
||||
}
|
||||
|
||||
const price_function = (utilization: number): number => {
|
||||
let price = min_price
|
||||
const new_exponent = exponent - 1.0
|
||||
if (new_exponent <= 0.0) {
|
||||
return max_price
|
||||
} else {
|
||||
price += (max_price - min_price) * Math.pow(utilization / weight, new_exponent)
|
||||
}
|
||||
return price
|
||||
}
|
||||
|
||||
let fee = 0
|
||||
let start_utilization: number = utilization
|
||||
const end_utilization: number = start_utilization + utilization_increase
|
||||
|
||||
if (start_utilization < adjusted_utilization) {
|
||||
fee +=
|
||||
(price_function(adjusted_utilization) *
|
||||
Math.min(utilization_increase, adjusted_utilization - start_utilization)) /
|
||||
weight
|
||||
start_utilization = adjusted_utilization
|
||||
}
|
||||
|
||||
if (start_utilization < end_utilization) {
|
||||
fee += price_integral_delta(start_utilization, end_utilization)
|
||||
}
|
||||
return Asset.fromUnits(Math.ceil(fee * 10000), this.parent.symbol)
|
||||
}
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
import {Asset} from '@greymass/eosio'
|
||||
|
||||
import {Resources} from './'
|
||||
import {REXState} from './abi-types'
|
||||
|
||||
export class REXAPI {
|
||||
constructor(private parent: Resources) {}
|
||||
|
||||
async get_state() {
|
||||
const response = await this.parent.api.v1.chain.get_table_rows({
|
||||
code: 'eosio',
|
||||
scope: 'eosio',
|
||||
table: 'rexpool',
|
||||
type: REXState,
|
||||
})
|
||||
return response.rows[0]
|
||||
}
|
||||
|
||||
async get_reserved() {
|
||||
const state = await this.get_state()
|
||||
const {total_lent, total_lendable} = state
|
||||
return Number(total_lent.units) / Number(total_lendable.units)
|
||||
}
|
||||
|
||||
async get_allocated() {
|
||||
const state = await this.parent.v1.powerup.get_state()
|
||||
const {weight_ratio} = state.cpu
|
||||
return Number(weight_ratio) / this.parent.rex_target_weight / 100
|
||||
}
|
||||
|
||||
async get_price_per_ms(ms = 1): Promise<Asset> {
|
||||
const allocated = await this.get_allocated()
|
||||
const state = await this.get_state()
|
||||
const {cpu} = await this.parent.getSampledUsage()
|
||||
|
||||
const totalRent = state.total_rent
|
||||
const totalUnlent = state.total_unlent
|
||||
const tokens = 1
|
||||
const msPerToken = (tokens / (totalRent.value / totalUnlent.value)) * cpu * allocated
|
||||
return Asset.from((tokens / msPerToken) * ms, this.parent.symbol)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"rows": [
|
||||
"00008c06f04621000000fac780e9141803004e79bb7de00000000080c6a47e8d030000a0724e1809000093c83560e8b96e6000000000000000408051010040787d010000000004454f53000000008017b42c0000000004454f5300000000614a250000000000bb0fb1000000000079353d6000311ac01b85000000fac780e91418030038e5edf6810300000080c6a47e8d030000a0724e1809000093c83560e8b96e6000000000000000408051010040787d010000000004454f53000000008017b42c0000000004454f53000000009985cf10000000000a07f0100000000079353d6001000000010000000000000004454f5300000000"
|
||||
],
|
||||
"more": false,
|
||||
"next_key": ""
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"rows": [
|
||||
"00ad8f4a884f00000004454f53000000001eafab5b3f00000004454f5300000000053341050000000004454f5300000000cb3ef6e38e00000004454f53000000004855ced3ea9d15000452455800000000000000000000000004454f53000000000419070000000000"
|
||||
],
|
||||
"more": false,
|
||||
"next_key": ""
|
||||
}
|
||||
@@ -0,0 +1,185 @@
|
||||
{
|
||||
"account_name": "teamgreymass",
|
||||
"head_block_num": 170942680,
|
||||
"head_block_time": "2021-03-01T18:47:26.000",
|
||||
"privileged": false,
|
||||
"last_code_update": "1970-01-01T00:00:00.000",
|
||||
"created": "2018-06-10T13:04:15.000",
|
||||
"core_liquid_balance": "2956.3573 EOS",
|
||||
"ram_quota": 67988,
|
||||
"net_weight": 29224,
|
||||
"cpu_weight": 129514594,
|
||||
"net_limit": {
|
||||
"used": 266415,
|
||||
"available": 3070460,
|
||||
"max": 3336875
|
||||
},
|
||||
"cpu_limit": {
|
||||
"used": 1047582,
|
||||
"available": 92233,
|
||||
"max": 1139815
|
||||
},
|
||||
"ram_usage": 16346,
|
||||
"permissions": [
|
||||
{
|
||||
"perm_name": "active",
|
||||
"parent": "owner",
|
||||
"required_auth": {
|
||||
"threshold": 1,
|
||||
"keys": [
|
||||
{
|
||||
"key": "EOS6gqJ7sdPgjHLFLtks9cRPs5qYHa9U3CwK4P2JasTLWKQ9kXZK1",
|
||||
"weight": 1
|
||||
}
|
||||
],
|
||||
"accounts": [],
|
||||
"waits": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"perm_name": "claim",
|
||||
"parent": "active",
|
||||
"required_auth": {
|
||||
"threshold": 1,
|
||||
"keys": [
|
||||
{
|
||||
"key": "EOS6DLD9HxMcwn73U41jjdGsNe9vDFRKB26um6qTAqrtYcJFtED4C",
|
||||
"weight": 1
|
||||
}
|
||||
],
|
||||
"accounts": [],
|
||||
"waits": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"perm_name": "decentium",
|
||||
"parent": "active",
|
||||
"required_auth": {
|
||||
"threshold": 1,
|
||||
"keys": [
|
||||
{
|
||||
"key": "EOS7knG7M5TUEdRv1bkVjTPddVoDQnwS7oEZXAgFk3A4hhocA3eJf",
|
||||
"weight": 1
|
||||
}
|
||||
],
|
||||
"accounts": [],
|
||||
"waits": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"perm_name": "oracle",
|
||||
"parent": "active",
|
||||
"required_auth": {
|
||||
"threshold": 1,
|
||||
"keys": [
|
||||
{
|
||||
"key": "EOS88VqmDmJJ9S23eNqdeWYf2zySxv3ckQrWBKy7EvVRCUuhSU4f3",
|
||||
"weight": 1
|
||||
}
|
||||
],
|
||||
"accounts": [],
|
||||
"waits": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"perm_name": "owner",
|
||||
"parent": "",
|
||||
"required_auth": {
|
||||
"threshold": 1,
|
||||
"keys": [
|
||||
{
|
||||
"key": "EOS8QzGtCea2thiqcTVeXGdyRZpdKYptQznbcWSMj73FD5RgwKN82",
|
||||
"weight": 1
|
||||
}
|
||||
],
|
||||
"accounts": [],
|
||||
"waits": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"perm_name": "producerjson",
|
||||
"parent": "active",
|
||||
"required_auth": {
|
||||
"threshold": 1,
|
||||
"keys": [
|
||||
{
|
||||
"key": "EOS5JCEciUdfXnQmTyj85T98bXTAZZ1g7Nmajseu7ZWB8DrDa6Etp",
|
||||
"weight": 1
|
||||
}
|
||||
],
|
||||
"accounts": [],
|
||||
"waits": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"perm_name": "transfer",
|
||||
"parent": "active",
|
||||
"required_auth": {
|
||||
"threshold": 1,
|
||||
"keys": [
|
||||
{
|
||||
"key": "EOS6AkZZ5YZ6G5eCQGJBAPbkmouEaiSKFkdM289wEMKcf2rnx7mrb",
|
||||
"weight": 1
|
||||
},
|
||||
{
|
||||
"key": "EOS6RWZ1CmDL4B6LdixuertnzxcRuUDac3NQspJEvMnebGcUwhvfX",
|
||||
"weight": 1
|
||||
}
|
||||
],
|
||||
"accounts": [],
|
||||
"waits": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"perm_name": "vote",
|
||||
"parent": "active",
|
||||
"required_auth": {
|
||||
"threshold": 1,
|
||||
"keys": [
|
||||
{
|
||||
"key": "EOS65NrHPVXaV4voxepQREmYCmnMJm4tAWdxPaK46CbUN1rrVmRzg",
|
||||
"weight": 1
|
||||
}
|
||||
],
|
||||
"accounts": [],
|
||||
"waits": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"perm_name": "voting",
|
||||
"parent": "active",
|
||||
"required_auth": {
|
||||
"threshold": 1,
|
||||
"keys": [
|
||||
{
|
||||
"key": "EOS7pn6P5FftyNAKRfx9VcUzBFMvC4UitNbnoKbfxNe8SShELo2it",
|
||||
"weight": 1
|
||||
}
|
||||
],
|
||||
"accounts": [],
|
||||
"waits": []
|
||||
}
|
||||
}
|
||||
],
|
||||
"total_resources": {
|
||||
"owner": "teamgreymass",
|
||||
"net_weight": "2.9224 EOS",
|
||||
"cpu_weight": "12951.4594 EOS",
|
||||
"ram_bytes": 66588
|
||||
},
|
||||
"self_delegated_bandwidth": null,
|
||||
"refund_request": null,
|
||||
"voter_info": {
|
||||
"owner": "teamgreymass",
|
||||
"proxy": "greymassvote",
|
||||
"producers": [],
|
||||
"staked": 100200,
|
||||
"last_vote_weight": "243319576912.68286132812500000",
|
||||
"proxied_vote_weight": "0.00000000000000000",
|
||||
"is_proxy": 0,
|
||||
"flags1": 0,
|
||||
"reserved2": 0,
|
||||
"reserved3": "0.0000 EOS"
|
||||
},
|
||||
"rex_info": null
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
import 'mocha'
|
||||
import {strict as assert} from 'assert'
|
||||
import {join as joinPath} from 'path'
|
||||
|
||||
import {APIClient, Name} from '@greymass/eosio'
|
||||
import {MockProvider} from './utils/mock-provider'
|
||||
|
||||
import {Resources} from '../src'
|
||||
import * as ABIs from '../src/abi-types'
|
||||
|
||||
const eos = new APIClient({
|
||||
provider: new MockProvider(joinPath(__dirname, 'data'), 'https://eos.greymass.com'),
|
||||
})
|
||||
|
||||
const resources = new Resources({api: eos})
|
||||
|
||||
suite('powerup', function () {
|
||||
this.slow(200)
|
||||
test('v1.powerup.get_state', async function () {
|
||||
const state = await resources.v1.powerup.get_state()
|
||||
assert.equal(state instanceof ABIs.PowerUpState, true)
|
||||
})
|
||||
test('v1.powerup.get_allocated', async function () {
|
||||
const cpu = await resources.v1.powerup.get_allocated()
|
||||
// 12.7957297784418% represented as float
|
||||
assert.equal(cpu, 0.12909697392435804)
|
||||
})
|
||||
test('v1.powerup.get_reserved(cpu)', async function () {
|
||||
const cpu = await resources.v1.powerup.get_reserved('cpu')
|
||||
// 0.04985526440273404% represented as float
|
||||
assert.equal(cpu, 0.0004933312426372583)
|
||||
})
|
||||
test('v1.powerup.get_reserved(net)', async function () {
|
||||
const net = await resources.v1.powerup.get_reserved('net')
|
||||
// 0.0017273973739949453% represented as float
|
||||
assert.equal(net, 0.000017099101893048595)
|
||||
})
|
||||
test('v1.powerup.get_price_per_ms(1)', async function () {
|
||||
const price = await resources.v1.powerup.get_price_per_ms()
|
||||
assert.equal(String(price), '0.0006 EOS')
|
||||
assert.equal(price.value, 0.0006)
|
||||
assert.equal(Number(price.units), 6)
|
||||
})
|
||||
test('v1.powerup.get_price_per_ms(1000)', async function () {
|
||||
const price = await resources.v1.powerup.get_price_per_ms(1000)
|
||||
assert.equal(String(price), '0.5702 EOS')
|
||||
assert.equal(price.value, 0.5702)
|
||||
assert.equal(Number(price.units), 5702)
|
||||
})
|
||||
})
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
import 'mocha'
|
||||
import {strict as assert} from 'assert'
|
||||
import {join as joinPath} from 'path'
|
||||
|
||||
import {APIClient, Name} from '@greymass/eosio'
|
||||
import {MockProvider} from './utils/mock-provider'
|
||||
|
||||
import {Resources} from '../src'
|
||||
import * as ABIs from '../src/abi-types'
|
||||
|
||||
const eos = new APIClient({
|
||||
provider: new MockProvider(joinPath(__dirname, 'data'), 'https://eos.greymass.com'),
|
||||
})
|
||||
|
||||
const resources = new Resources({api: eos})
|
||||
|
||||
suite('rex', function () {
|
||||
this.slow(200)
|
||||
test('v1.rex.get_state', async function () {
|
||||
const state = await resources.v1.rex.get_state()
|
||||
assert.equal(state instanceof ABIs.REXState, true)
|
||||
})
|
||||
test('v1.rex.get_allocated', async function () {
|
||||
const cpu = await resources.v1.rex.get_allocated()
|
||||
// 0.872042702215582% represented as float
|
||||
assert.equal(cpu, 0.870903026075642)
|
||||
})
|
||||
test('v1.rex.get_reserved', async function () {
|
||||
const reserved = await resources.v1.rex.get_reserved()
|
||||
// 55.66151698897704% represented as float
|
||||
assert.equal(reserved, 0.5565968415413414)
|
||||
})
|
||||
test('v1.rex.get_price_per_ms(1)', async function () {
|
||||
const price = await resources.v1.rex.get_price_per_ms()
|
||||
assert.equal(String(price), '0.0042 EOS')
|
||||
assert.equal(price.value, 0.0042)
|
||||
assert.equal(Number(price.units), 42)
|
||||
})
|
||||
test('v1.rex.get_price_per_ms(1000)', async function () {
|
||||
const price = await resources.v1.rex.get_price_per_ms(1000)
|
||||
assert.equal(String(price), '4.2269 EOS')
|
||||
assert.equal(price.value, 4.2269)
|
||||
assert.equal(Number(price.units), 42269)
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"extends": "../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"isolatedModules": false,
|
||||
"module": "commonjs",
|
||||
"target": "es6",
|
||||
},
|
||||
"include": ["./**/*.ts"]
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
import fetch from 'node-fetch'
|
||||
import {join as joinPath} from 'path'
|
||||
import {promisify} from 'util'
|
||||
import {readFile as _readFile, writeFile as _writeFile} from 'fs'
|
||||
|
||||
const readFile = promisify(_readFile)
|
||||
const writeFile = promisify(_writeFile)
|
||||
|
||||
import {APIProvider, Bytes, Checksum160, FetchProvider} from '@greymass/eosio'
|
||||
|
||||
export class MockProvider implements APIProvider {
|
||||
recordProvider = new FetchProvider(this.api, {fetch})
|
||||
|
||||
constructor(private dir: string, private api: string = 'https://jungle3.greymass.com') {}
|
||||
|
||||
getFilename(path: string, params?: unknown) {
|
||||
const digest = Checksum160.hash(
|
||||
Bytes.from(this.api + path + (params ? JSON.stringify(params) : ''), 'utf8')
|
||||
).hexString
|
||||
return joinPath(this.dir, digest + '.json')
|
||||
}
|
||||
|
||||
async getExisting(filename: string) {
|
||||
try {
|
||||
const data = await readFile(filename)
|
||||
return JSON.parse(data.toString('utf8'))
|
||||
} catch (error) {
|
||||
if (error.code !== 'ENOENT') {
|
||||
throw error
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async call(path: string, params?: unknown) {
|
||||
const filename = this.getFilename(path, params)
|
||||
if (process.env['MOCK_RECORD'] !== 'overwrite') {
|
||||
const existing = await this.getExisting(filename)
|
||||
if (existing) {
|
||||
return existing
|
||||
}
|
||||
}
|
||||
if (process.env['MOCK_RECORD']) {
|
||||
const response = await this.recordProvider.call(path, params)
|
||||
const json = JSON.stringify(response, undefined, 4)
|
||||
await writeFile(filename, json)
|
||||
return response
|
||||
} else {
|
||||
throw new Error(`No data for ${path}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"downlevelIteration": true,
|
||||
"esModuleInterop": true,
|
||||
"experimentalDecorators": true,
|
||||
"importHelpers": true,
|
||||
"isolatedModules": true,
|
||||
"lib": ["esnext"],
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"noImplicitAny": false,
|
||||
"sourceMap": true,
|
||||
"strict": true,
|
||||
"target": "esnext"
|
||||
},
|
||||
"include": ["src/**/*"]
|
||||
}
|
||||
Reference in New Issue
Block a user