From 308eb7f9899200c4c86cd7cda0619052ef977eee Mon Sep 17 00:00:00 2001 From: Denis Carriere Date: Wed, 24 Apr 2024 23:20:19 +0200 Subject: [PATCH] init bpay repo --- .github/workflows/test.yml | 19 + .gitignore | 4 + README.md | 28 +- eosio.bpay.clauses.md | 3 + eosio.bpay.contracts.md | 10 + eosio.bpay.cpp | 75 +++ eosio.bpay.hpp | 55 +++ eosio.bpay.permission.yml | 23 + eosio.bpay.spec.ts | 140 ++++++ external/eosio.system/eosio.cpp | 103 +++++ external/eosio.token/eosio.token.cpp | 159 +++++++ external/eosio.token/eosio.token.hpp | 146 ++++++ include/eosio.system/eosio.system.hpp | 94 ++++ include/eosio.token/eosio.token.hpp | 146 ++++++ package-lock.json | 638 ++++++++++++++++++++++++++ package.json | 16 + 16 files changed, 1657 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/test.yml create mode 100644 eosio.bpay.clauses.md create mode 100644 eosio.bpay.contracts.md create mode 100644 eosio.bpay.cpp create mode 100644 eosio.bpay.hpp create mode 100644 eosio.bpay.permission.yml create mode 100644 eosio.bpay.spec.ts create mode 100644 external/eosio.system/eosio.cpp create mode 100644 external/eosio.token/eosio.token.cpp create mode 100644 external/eosio.token/eosio.token.hpp create mode 100644 include/eosio.system/eosio.system.hpp create mode 100644 include/eosio.token/eosio.token.hpp create mode 100644 package-lock.json create mode 100644 package.json diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..f9f5f0f --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,19 @@ +name: Bun Test + +on: push + +jobs: + build-and-test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: oven-sh/setup-bun@v1 + with: + bun-version: latest + - name: Install CDT + run: | + curl https://gateway.pinata.cloud/ipfs/QmfFhXmbaZMgwVs51MHcUemG1A2XCNSTByRcAEG7S6iXaD -o cdt_4.0.1-1_amd64.deb + sudo apt install ./cdt_4.0.1-1_amd64.deb + - run: bun install + - run: bun run build + - run: bun run test diff --git a/.gitignore b/.gitignore index 259148f..a826bcf 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,9 @@ # Prerequisites *.d +node_modules +.DS_Store +*.wasm +*.abi # Compiled Object files *.slo diff --git a/README.md b/README.md index 5d0a8ed..a0dc002 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,26 @@ -# eosio.bpay -eosio.bpay +# EOS Block Pay (`eosio.bpay`) [![Bun Test](https://github.com/eosnetworkfoundation/eosio.bpay/actions/workflows/test.yml/badge.svg)](https://github.com/eosnetworkfoundation/eosio.bpay/actions/workflows/test.yml) + +## Overview + +The `eosio.bpay` contract handles system block pay distribution. + +## Development and Testing + +### Build Instructions + +To compile the contract, developers can use the following command: + +```sh +$ cdt-cpp eosio.bpay.cpp -I ./include +``` + +### Testing Framework + +The contract includes a comprehensive testing suite designed to validate its functionality. The tests are executed using the following commands: + +```sh +$ npm test + +> test +> bun test +``` diff --git a/eosio.bpay.clauses.md b/eosio.bpay.clauses.md new file mode 100644 index 0000000..e8eb4e5 --- /dev/null +++ b/eosio.bpay.clauses.md @@ -0,0 +1,3 @@ +

UserAgreement

+ +The `eosio.bpay` contract handles block pay distribution. diff --git a/eosio.bpay.contracts.md b/eosio.bpay.contracts.md new file mode 100644 index 0000000..1b759a1 --- /dev/null +++ b/eosio.bpay.contracts.md @@ -0,0 +1,10 @@ +

claimrewards

+ +--- +spec_version: "0.2.0" +title: claimrewards +summary: 'Claim Rewards' +icon: https://gateway.pinata.cloud/ipfs/QmZ4HSZDuSrZ4BHawtZRhVfwyYJ4DepNJqVDzxY59KveiM#3830f1ce8cb07f7757dbcf383b1ec1b11914ac34a1f9d8b065f07600fa9dac19 +--- + +Claim rewards {{ owner }} has earned as a block producer. diff --git a/eosio.bpay.cpp b/eosio.bpay.cpp new file mode 100644 index 0000000..edf44d5 --- /dev/null +++ b/eosio.bpay.cpp @@ -0,0 +1,75 @@ +#include "eosio.bpay.hpp" + +namespace eosio { + +[[eosio::action]] +void bpay::claimrewards( const name owner ) { + require_auth( owner ); + + rewards_table _rewards( get_self(), get_self().value ); + + const auto& row = _rewards.get( owner.value, "not eligible to claim producer block pay" ); + check( row.quantity.amount > 0, "no rewards to claim"); + + // transfer rewards to owner + eosio::token::transfer_action transfer( "eosio.token"_n, { get_self(), "active"_n }); + transfer.send( get_self(), owner, row.quantity, "producer block pay" ); + + _rewards.modify(row, get_self(), [&](auto& row) { + row.quantity.amount = 0; + }); +} + +[[eosio::on_notify("*::transfer")]] +void bpay::on_transfer( const name from, const name to, const asset quantity, const string memo ) +{ + if (from == get_self() || to != get_self()) { + return; + } + + check( get_first_receiver() == "eosio.token"_n, "only eosio.token allowed") ; + check( quantity.symbol == eosio::symbol("EOS", 4), "only EOS token allowed" ); + + rewards_table _rewards( get_self(), get_self().value ); + eosiosystem::system_contract::producers_table _producers( "eosio"_n, "eosio"_n.value ); + + // get voter secondary index + auto idx = _producers.get_index<"prototalvote"_n>(); + + // get producer with the most votes + // reverse iterator to get the last element + auto prod = idx.rbegin(); + + // get top 21 producers by vote + std::vector top_producers; + for (int i = 0; i < 21; i++) { + if ( prod->is_active == false ) { + prod++; + i--; + continue; + } + top_producers.push_back(prod->owner); + print(i, " ", prod->owner, " ", prod->total_votes, "\n"); + prod++; + } + + // calculate rewards equal share for top 21 producers + asset reward = quantity / 21; + + // update rewards table + for (auto producer : top_producers) { + auto row = _rewards.find( producer.value ); + if (row == _rewards.end()) { + _rewards.emplace( get_self(), [&](auto& row) { + row.owner = producer; + row.quantity = reward; + }); + } else { + _rewards.modify(row, get_self(), [&](auto& row) { + row.quantity += reward; + }); + } + } +} + +} /// namespace eosio diff --git a/eosio.bpay.hpp b/eosio.bpay.hpp new file mode 100644 index 0000000..5cf6290 --- /dev/null +++ b/eosio.bpay.hpp @@ -0,0 +1,55 @@ +#pragma once + +#include +#include +#include + +using namespace std; + +namespace eosio { + /** + * The `eosio.bpay` contract handles system bpay distribution. + */ + class [[eosio::contract("eosio.bpay")]] bpay : public contract { + public: + using contract::contract; + + /** + * ## TABLE `rewards` + * + * @param owner - block producer owner account + * @param quantity - reward quantity in EOS + * + * ### example + * + * ```json + * [ + * { + * "owner": "alice", + * "quantity": "8.800 EOS" + * } + * ] + * ``` + */ + struct [[eosio::table("rewards")]] rewards_row { + name owner; + asset quantity; + + uint64_t primary_key() const { return owner.value; } + }; + typedef eosio::multi_index< "rewards"_n, rewards_row > rewards_table; + + /** + * Claim rewards for a block producer. + * + * @param owner - block producer owner account + */ + [[eosio::action]] + void claimrewards( const name owner); + + [[eosio::on_notify("*::transfer")]] + void on_transfer( const name from, const name to, const asset quantity, const string memo ); + + private: + }; +} /// namespace eosio diff --git a/eosio.bpay.permission.yml b/eosio.bpay.permission.yml new file mode 100644 index 0000000..da7d1a6 --- /dev/null +++ b/eosio.bpay.permission.yml @@ -0,0 +1,23 @@ +owner: + threshold: 1 + accounts: + - permission: + actor: eosio + permission: active + weight: 1 + +active: + threshold: 2 + accounts: + - permission: + actor: enf + permission: active + weight: 1 + - permission: + actor: eosio.prods + permission: prod.minor + weight: 1 + - permission: + actor: eosio.bpay + permission: eosio.code + weight: 2 \ No newline at end of file diff --git a/eosio.bpay.spec.ts b/eosio.bpay.spec.ts new file mode 100644 index 0000000..ba1f602 --- /dev/null +++ b/eosio.bpay.spec.ts @@ -0,0 +1,140 @@ +import { Asset, Name } from '@wharfkit/antelope' +import { describe, expect, test } from 'bun:test' +import { Blockchain, expectToThrow } from '@eosnetwork/vert' + +// Vert EOS VM +const blockchain = new Blockchain() + +// 21 producers +const alice = "bp.alice" +const bob = "bp.bob" +const charly = "bp.charly" +const producers = [ + alice, + bob, + charly, + "bp.d", + "bp.e", + "bp.f", + "bp.g", + "bp.h", + "bp.i", + "bp.j", + "bp.k", + "bp.l", + "bp.m", + "bp.n", + "bp.o", + "bp.p", + "bp.q", + "bp.r", + "bp.s", + "bp.t", + "bp.u", +] +const standby = "bp.standby" +const inactive = "bp.inactive" +blockchain.createAccounts(...producers, standby, inactive) + +const bpay_contract = 'eosio.bpay' +const contracts = { + bpay: blockchain.createContract(bpay_contract, bpay_contract, true), + token: blockchain.createContract('eosio.token', 'external/eosio.token/eosio.token', true), + system: blockchain.createContract('eosio', 'external/eosio.system/eosio', true), + fake: { + token: blockchain.createContract('fake.token', 'external/eosio.token/eosio.token', true), + }, +} + +function getProducers(owner: string) { + const scope = Name.from("eosio").value.value + const primary_key = Name.from(owner).value.value + return contracts.system.tables + .producers(scope) + .getTableRow(primary_key) +} + +function getRewards(owner: string) { + const scope = Name.from(bpay_contract).value.value + const primary_key = Name.from(owner).value.value + const row = contracts.bpay.tables + .rewards(scope) + .getTableRow(primary_key) + if (!row) return 0; + return Asset.from(row.quantity).units.toNumber() +} + +function getTokenBalance(account: string, symcode: string) { + const scope = Name.from(account).value.value + const primary_key = Asset.SymbolCode.from(symcode).value.value + const row = contracts.token.tables + .accounts(scope) + .getTableRow(primary_key) + if (!row) return 0; + return Asset.from(row.balance).units.toNumber() +} + +describe(bpay_contract, () => { + test('eosio::setproducers', async () => { + let votes = 100.0; + for ( const producer of producers ) { + await contracts.system.actions.setproducer([producer, votes, true]).send() + votes -= 1.0; + } + await contracts.system.actions.setproducer([standby, 1, true]).send() // lowest vote + await contracts.system.actions.setproducer([inactive, 200.0, false]).send() // highest vote, but inactive + }) + + test('eosio.token::issue::EOS', async () => { + const supply = `1000000000.0000 EOS` + await contracts.token.actions.create(['eosio.token', supply]).send() + await contracts.token.actions.issue(['eosio.token', supply, '']).send() + }) + + test("eosio.bpay::transfer", async () => { + await contracts.token.actions.transfer(['eosio.token', bpay_contract, '2100.0000 EOS', '']).send(); + const before = { + bpay: { + balance: getTokenBalance(bpay_contract, 'EOS'), + }, + alice: { + balance: getTokenBalance(alice, 'EOS'), + }, + bob: { + balance: getTokenBalance(bob, 'EOS'), + }, + + } + await contracts.bpay.actions.claimrewards([alice]).send(alice); + + const after = { + bpay: { + balance: getTokenBalance(bpay_contract, 'EOS'), + }, + alice: { + balance: getTokenBalance(alice, 'EOS'), + }, + bob: { + balance: getTokenBalance(bob, 'EOS'), + }, + } + + // EOS + expect(after.bpay.balance - before.bpay.balance).toBe(-1000000) + expect(after.alice.balance - before.alice.balance).toBe(1000000) + expect(after.bob.balance - before.bob.balance).toBe(0) + }); + + test('eosio.bpay::claimrewards::error - no rewards to claim', async () => { + const action = contracts.bpay.actions.claimrewards([alice]).send(alice); + await expectToThrow(action, 'eosio_assert: no rewards to claim'); + }) + + test.skip('eosio.bpay::claimrewards::error - not eligible to claim block rewards', async () => { + for ( const owner of [inactive, standby] ) { + const action = contracts.bpay.actions.claimrewards([owner]).send(owner); + await expectToThrow(action, 'eosio_assert: not eligible to claim producer block pay'); + } + }) + +}) \ No newline at end of file diff --git a/external/eosio.system/eosio.cpp b/external/eosio.system/eosio.cpp new file mode 100644 index 0000000..d25cca4 --- /dev/null +++ b/external/eosio.system/eosio.cpp @@ -0,0 +1,103 @@ +#include +#include +#include +#include + +#include + +using namespace eosio; + +class [[eosio::contract("eosio")]] system_contract : public contract +{ +public: + using contract::contract; + + [[eosio::action]] + void setproducer( const name owner, const double total_votes, const bool is_active ) + { + // set producer + producers_table _producers(get_self(), get_self().value); + _producers.emplace(get_self(), [&](auto& p) { + p.owner = owner; + p.total_votes = total_votes; + p.is_active = is_active; + }); + } + + static eosio::block_signing_authority convert_to_block_signing_authority( const eosio::public_key& producer_key ) { + return eosio::block_signing_authority_v0{ .threshold = 1, .keys = {{producer_key, 1}} }; + } + + // Defines `producer_info` structure to be stored in `producer_info` table, added after version 1.0 + struct [[eosio::table, eosio::contract("eosio.system")]] producer_info { + name owner; + double total_votes = 0; + eosio::public_key producer_key; /// a packed public key object + bool is_active = true; + std::string url; + uint32_t unpaid_blocks = 0; + time_point last_claim_time; + uint16_t location = 0; + eosio::binary_extension producer_authority; // added in version 1.9.0 + + uint64_t primary_key()const { return owner.value; } + double by_votes()const { return is_active ? -total_votes : total_votes; } + bool active()const { return is_active; } + void deactivate() { producer_key = public_key(); producer_authority.reset(); is_active = false; } + + eosio::block_signing_authority get_producer_authority()const { + if( producer_authority.has_value() ) { + bool zero_threshold = std::visit( [](auto&& auth ) -> bool { + return (auth.threshold == 0); + }, *producer_authority ); + // zero_threshold could be true despite the validation done in regproducer2 because the v1.9.0 eosio.system + // contract has a bug which may have modified the producer table such that the producer_authority field + // contains a default constructed eosio::block_signing_authority (which has a 0 threshold and so is invalid). + if( !zero_threshold ) return *producer_authority; + } + return convert_to_block_signing_authority( producer_key ); + } + + // The unregprod and claimrewards actions modify unrelated fields of the producers table and under the default + // serialization behavior they would increase the size of the serialized table if the producer_authority field + // was not already present. This is acceptable (though not necessarily desired) because those two actions require + // the authority of the producer who pays for the table rows. + // However, the rmvproducer action and the onblock transaction would also modify the producer table in a similar + // way and increasing its serialized size is not acceptable in that context. + // So, a custom serialization is defined to handle the binary_extension producer_authority + // field in the desired way. (Note: v1.9.0 did not have this custom serialization behavior.) + + template + friend DataStream& operator << ( DataStream& ds, const producer_info& t ) { + ds << t.owner + << t.total_votes + << t.producer_key + << t.is_active + << t.url + << t.unpaid_blocks + << t.last_claim_time + << t.location; + + if( !t.producer_authority.has_value() ) return ds; + + return ds << t.producer_authority; + } + + template + friend DataStream& operator >> ( DataStream& ds, producer_info& t ) { + return ds >> t.owner + >> t.total_votes + >> t.producer_key + >> t.is_active + >> t.url + >> t.unpaid_blocks + >> t.last_claim_time + >> t.location + >> t.producer_authority; + } + }; + + typedef eosio::multi_index< "producers"_n, producer_info, + indexed_by<"prototalvote"_n, const_mem_fun> + > producers_table; +}; \ No newline at end of file diff --git a/external/eosio.token/eosio.token.cpp b/external/eosio.token/eosio.token.cpp new file mode 100644 index 0000000..395b869 --- /dev/null +++ b/external/eosio.token/eosio.token.cpp @@ -0,0 +1,159 @@ +#include + +namespace eosio { + +void token::create( const name& issuer, + const asset& maximum_supply ) +{ + require_auth( get_self() ); + + auto sym = maximum_supply.symbol; + check( maximum_supply.is_valid(), "invalid supply"); + check( maximum_supply.amount > 0, "max-supply must be positive"); + + stats statstable( get_self(), sym.code().raw() ); + auto existing = statstable.find( sym.code().raw() ); + check( existing == statstable.end(), "token with symbol already exists" ); + + statstable.emplace( get_self(), [&]( auto& s ) { + s.supply.symbol = maximum_supply.symbol; + s.max_supply = maximum_supply; + s.issuer = issuer; + }); +} + + +void token::issue( const name& to, const asset& quantity, const string& memo ) +{ + auto sym = quantity.symbol; + check( sym.is_valid(), "invalid symbol name" ); + check( memo.size() <= 256, "memo has more than 256 bytes" ); + + stats statstable( get_self(), sym.code().raw() ); + auto existing = statstable.find( sym.code().raw() ); + check( existing != statstable.end(), "token with symbol does not exist, create token before issue" ); + const auto& st = *existing; + check( to == st.issuer, "tokens can only be issued to issuer account" ); + + require_auth( st.issuer ); + check( quantity.is_valid(), "invalid quantity" ); + check( quantity.amount > 0, "must issue positive quantity" ); + + check( quantity.symbol == st.supply.symbol, "symbol precision mismatch" ); + check( quantity.amount <= st.max_supply.amount - st.supply.amount, "quantity exceeds available supply"); + + statstable.modify( st, same_payer, [&]( auto& s ) { + s.supply += quantity; + }); + + add_balance( st.issuer, quantity, st.issuer ); +} + +void token::retire( const asset& quantity, const string& memo ) +{ + auto sym = quantity.symbol; + check( sym.is_valid(), "invalid symbol name" ); + check( memo.size() <= 256, "memo has more than 256 bytes" ); + + stats statstable( get_self(), sym.code().raw() ); + auto existing = statstable.find( sym.code().raw() ); + check( existing != statstable.end(), "token with symbol does not exist" ); + const auto& st = *existing; + + require_auth( st.issuer ); + check( quantity.is_valid(), "invalid quantity" ); + check( quantity.amount > 0, "must retire positive quantity" ); + + check( quantity.symbol == st.supply.symbol, "symbol precision mismatch" ); + + statstable.modify( st, same_payer, [&]( auto& s ) { + s.supply -= quantity; + }); + + sub_balance( st.issuer, quantity ); +} + +void token::transfer( const name& from, + const name& to, + const asset& quantity, + const string& memo ) +{ + check( from != to, "cannot transfer to self" ); + // ignore auth for testing to allow privileged eosio contract to transfer using donatetorex action + // require_auth( from ); + check( is_account( to ), "to account does not exist"); + auto sym = quantity.symbol.code(); + stats statstable( get_self(), sym.raw() ); + const auto& st = statstable.get( sym.raw() ); + + require_recipient( from ); + require_recipient( to ); + + check( quantity.is_valid(), "invalid quantity" ); + check( quantity.amount > 0, "must transfer positive quantity" ); + check( quantity.symbol == st.supply.symbol, "symbol precision mismatch" ); + check( memo.size() <= 256, "memo has more than 256 bytes" ); + + auto payer = has_auth( to ) ? to : from; + + sub_balance( from, quantity ); + add_balance( to, quantity, payer ); +} + +void token::sub_balance( const name& owner, const asset& value ) { + accounts from_acnts( get_self(), owner.value ); + + const auto& from = from_acnts.get( value.symbol.code().raw(), "no balance object found" ); + check( from.balance.amount >= value.amount, "overdrawn balance" ); + + from_acnts.modify( from, owner, [&]( auto& a ) { + a.balance -= value; + }); +} + +void token::add_balance( const name& owner, const asset& value, const name& ram_payer ) +{ + accounts to_acnts( get_self(), owner.value ); + auto to = to_acnts.find( value.symbol.code().raw() ); + if( to == to_acnts.end() ) { + to_acnts.emplace( ram_payer, [&]( auto& a ){ + a.balance = value; + }); + } else { + to_acnts.modify( to, same_payer, [&]( auto& a ) { + a.balance += value; + }); + } +} + +void token::open( const name& owner, const symbol& symbol, const name& ram_payer ) +{ + require_auth( ram_payer ); + + check( is_account( owner ), "owner account does not exist" ); + + auto sym_code_raw = symbol.code().raw(); + stats statstable( get_self(), sym_code_raw ); + const auto& st = statstable.get( sym_code_raw, "symbol does not exist" ); + check( st.supply.symbol == symbol, "symbol precision mismatch" ); + + accounts acnts( get_self(), owner.value ); + auto it = acnts.find( sym_code_raw ); + if( it == acnts.end() ) { + acnts.emplace( ram_payer, [&]( auto& a ){ + a.balance = asset{0, symbol}; + }); + } +} + +void token::close( const name& owner, const symbol& symbol ) +{ + require_auth( owner ); + accounts acnts( get_self(), owner.value ); + auto it = acnts.find( symbol.code().raw() ); + check( it != acnts.end(), "Balance row already deleted or never existed. Action won't have any effect." ); + check( it->balance.amount == 0, "Cannot close because the balance is not zero." ); + acnts.erase( it ); +} + +} /// namespace eosio diff --git a/external/eosio.token/eosio.token.hpp b/external/eosio.token/eosio.token.hpp new file mode 100644 index 0000000..ce8756c --- /dev/null +++ b/external/eosio.token/eosio.token.hpp @@ -0,0 +1,146 @@ +#pragma once + +#include +#include + +#include + +namespace eosiosystem { + class system_contract; +} + +namespace eosio { + + using std::string; + + /** + * The `eosio.token` sample system contract defines the structures and actions that allow users to create, issue, and manage tokens for EOSIO based blockchains. It demonstrates one way to implement a smart contract which allows for creation and management of tokens. It is possible for one to create a similar contract which suits different needs. However, it is recommended that if one only needs a token with the below listed actions, that one uses the `eosio.token` contract instead of developing their own. + * + * The `eosio.token` contract class also implements two useful public static methods: `get_supply` and `get_balance`. The first allows one to check the total supply of a specified token, created by an account and the second allows one to check the balance of a token for a specified account (the token creator account has to be specified as well). + * + * The `eosio.token` contract manages the set of tokens, accounts and their corresponding balances, by using two internal multi-index structures: the `accounts` and `stats`. The `accounts` multi-index table holds, for each row, instances of `account` object and the `account` object holds information about the balance of one token. The `accounts` table is scoped to an EOSIO account, and it keeps the rows indexed based on the token's symbol. This means that when one queries the `accounts` multi-index table for an account name the result is all the tokens that account holds at the moment. + * + * Similarly, the `stats` multi-index table, holds instances of `currency_stats` objects for each row, which contains information about current supply, maximum supply, and the creator account for a symbol token. The `stats` table is scoped to the token symbol. Therefore, when one queries the `stats` table for a token symbol the result is one single entry/row corresponding to the queried symbol token if it was previously created, or nothing, otherwise. + */ + class [[eosio::contract("eosio.token")]] token : public contract { + public: + using contract::contract; + + /** + * Allows `issuer` account to create a token in supply of `maximum_supply`. If validation is successful a new entry in statstable for token symbol scope gets created. + * + * @param issuer - the account that creates the token, + * @param maximum_supply - the maximum supply set for the token created. + * + * @pre Token symbol has to be valid, + * @pre Token symbol must not be already created, + * @pre maximum_supply has to be smaller than the maximum supply allowed by the system: 1^62 - 1. + * @pre Maximum supply must be positive; + */ + [[eosio::action]] + void create( const name& issuer, + const asset& maximum_supply); + /** + * This action issues to `to` account a `quantity` of tokens. + * + * @param to - the account to issue tokens to, it must be the same as the issuer, + * @param quantity - the amount of tokens to be issued, + * @memo - the memo string that accompanies the token issue transaction. + */ + [[eosio::action]] + void issue( const name& to, const asset& quantity, const string& memo ); + + /** + * The opposite for create action, if all validations succeed, + * it debits the statstable.supply amount. + * + * @param quantity - the quantity of tokens to retire, + * @param memo - the memo string to accompany the transaction. + */ + [[eosio::action]] + void retire( const asset& quantity, const string& memo ); + + /** + * Allows `from` account to transfer to `to` account the `quantity` tokens. + * One account is debited and the other is credited with quantity tokens. + * + * @param from - the account to transfer from, + * @param to - the account to be transferred to, + * @param quantity - the quantity of tokens to be transferred, + * @param memo - the memo string to accompany the transaction. + */ + [[eosio::action]] + void transfer( const name& from, + const name& to, + const asset& quantity, + const string& memo ); + /** + * Allows `ram_payer` to create an account `owner` with zero balance for + * token `symbol` at the expense of `ram_payer`. + * + * @param owner - the account to be created, + * @param symbol - the token to be payed with by `ram_payer`, + * @param ram_payer - the account that supports the cost of this action. + * + * More information can be read [here](https://github.com/EOSIO/eosio.contracts/issues/62) + * and [here](https://github.com/EOSIO/eosio.contracts/issues/61). + */ + [[eosio::action]] + void open( const name& owner, const symbol& symbol, const name& ram_payer ); + + /** + * This action is the opposite for open, it closes the account `owner` + * for token `symbol`. + * + * @param owner - the owner account to execute the close action for, + * @param symbol - the symbol of the token to execute the close action for. + * + * @pre The pair of owner plus symbol has to exist otherwise no action is executed, + * @pre If the pair of owner plus symbol exists, the balance has to be zero. + */ + [[eosio::action]] + void close( const name& owner, const symbol& symbol ); + + static asset get_supply( const name& token_contract_account, const symbol_code& sym_code ) + { + stats statstable( token_contract_account, sym_code.raw() ); + const auto& st = statstable.get( sym_code.raw(), "invalid supply symbol code" ); + return st.supply; + } + + static asset get_balance( const name& token_contract_account, const name& owner, const symbol_code& sym_code ) + { + accounts accountstable( token_contract_account, owner.value ); + const auto& ac = accountstable.get( sym_code.raw(), "no balance with specified symbol" ); + return ac.balance; + } + + using create_action = eosio::action_wrapper<"create"_n, &token::create>; + using issue_action = eosio::action_wrapper<"issue"_n, &token::issue>; + using retire_action = eosio::action_wrapper<"retire"_n, &token::retire>; + using transfer_action = eosio::action_wrapper<"transfer"_n, &token::transfer>; + using open_action = eosio::action_wrapper<"open"_n, &token::open>; + using close_action = eosio::action_wrapper<"close"_n, &token::close>; + private: + struct [[eosio::table]] account { + asset balance; + + uint64_t primary_key()const { return balance.symbol.code().raw(); } + }; + + struct [[eosio::table]] currency_stats { + asset supply; + asset max_supply; + name issuer; + + uint64_t primary_key()const { return supply.symbol.code().raw(); } + }; + + typedef eosio::multi_index< "accounts"_n, account > accounts; + typedef eosio::multi_index< "stat"_n, currency_stats > stats; + + void sub_balance( const name& owner, const asset& value ); + void add_balance( const name& owner, const asset& value, const name& ram_payer ); + }; + +} diff --git a/include/eosio.system/eosio.system.hpp b/include/eosio.system/eosio.system.hpp new file mode 100644 index 0000000..ba9d2c4 --- /dev/null +++ b/include/eosio.system/eosio.system.hpp @@ -0,0 +1,94 @@ +#include +#include +#include +#include + +#include + +using namespace eosio; + +namespace eosiosystem { + +class [[eosio::contract("eosio")]] system_contract : public contract +{ +public: + using contract::contract; + + static eosio::block_signing_authority convert_to_block_signing_authority( const eosio::public_key& producer_key ) { + return eosio::block_signing_authority_v0{ .threshold = 1, .keys = {{producer_key, 1}} }; + } + + // Defines `producer_info` structure to be stored in `producer_info` table, added after version 1.0 + struct [[eosio::table, eosio::contract("eosio.system")]] producer_info { + name owner; + double total_votes = 0; + eosio::public_key producer_key; /// a packed public key object + bool is_active = true; + std::string url; + uint32_t unpaid_blocks = 0; + time_point last_claim_time; + uint16_t location = 0; + eosio::binary_extension producer_authority; // added in version 1.9.0 + + uint64_t primary_key()const { return owner.value; } + double by_votes()const { return is_active ? -total_votes : total_votes; } + bool active()const { return is_active; } + void deactivate() { producer_key = public_key(); producer_authority.reset(); is_active = false; } + + eosio::block_signing_authority get_producer_authority()const { + if( producer_authority.has_value() ) { + bool zero_threshold = std::visit( [](auto&& auth ) -> bool { + return (auth.threshold == 0); + }, *producer_authority ); + // zero_threshold could be true despite the validation done in regproducer2 because the v1.9.0 eosio.system + // contract has a bug which may have modified the producer table such that the producer_authority field + // contains a default constructed eosio::block_signing_authority (which has a 0 threshold and so is invalid). + if( !zero_threshold ) return *producer_authority; + } + return convert_to_block_signing_authority( producer_key ); + } + + // The unregprod and claimrewards actions modify unrelated fields of the producers table and under the default + // serialization behavior they would increase the size of the serialized table if the producer_authority field + // was not already present. This is acceptable (though not necessarily desired) because those two actions require + // the authority of the producer who pays for the table rows. + // However, the rmvproducer action and the onblock transaction would also modify the producer table in a similar + // way and increasing its serialized size is not acceptable in that context. + // So, a custom serialization is defined to handle the binary_extension producer_authority + // field in the desired way. (Note: v1.9.0 did not have this custom serialization behavior.) + + template + friend DataStream& operator << ( DataStream& ds, const producer_info& t ) { + ds << t.owner + << t.total_votes + << t.producer_key + << t.is_active + << t.url + << t.unpaid_blocks + << t.last_claim_time + << t.location; + + if( !t.producer_authority.has_value() ) return ds; + + return ds << t.producer_authority; + } + + template + friend DataStream& operator >> ( DataStream& ds, producer_info& t ) { + return ds >> t.owner + >> t.total_votes + >> t.producer_key + >> t.is_active + >> t.url + >> t.unpaid_blocks + >> t.last_claim_time + >> t.location + >> t.producer_authority; + } + }; + + typedef eosio::multi_index< "producers"_n, producer_info, + indexed_by<"prototalvote"_n, const_mem_fun> + > producers_table; +}; +} \ No newline at end of file diff --git a/include/eosio.token/eosio.token.hpp b/include/eosio.token/eosio.token.hpp new file mode 100644 index 0000000..e4942df --- /dev/null +++ b/include/eosio.token/eosio.token.hpp @@ -0,0 +1,146 @@ +#pragma once + +#include +#include + +#include + +namespace eosiosystem { + class system_contract; +} + +namespace eosio { + + using std::string; + + /** + * The `eosio.token` sample system contract defines the structures and actions that allow users to create, issue, and manage tokens for EOSIO based blockchains. It demonstrates one way to implement a smart contract which allows for creation and management of tokens. It is possible for one to create a similar contract which suits different needs. However, it is recommended that if one only needs a token with the below listed actions, that one uses the `eosio.token` contract instead of developing their own. + * + * The `eosio.token` contract class also implements two useful public static methods: `get_supply` and `get_balance`. The first allows one to check the total supply of a specified token, created by an account and the second allows one to check the balance of a token for a specified account (the token creator account has to be specified as well). + * + * The `eosio.token` contract manages the set of tokens, accounts and their corresponding balances, by using two internal multi-index structures: the `accounts` and `stats`. The `accounts` multi-index table holds, for each row, instances of `account` object and the `account` object holds information about the balance of one token. The `accounts` table is scoped to an EOSIO account, and it keeps the rows indexed based on the token's symbol. This means that when one queries the `accounts` multi-index table for an account name the result is all the tokens that account holds at the moment. + * + * Similarly, the `stats` multi-index table, holds instances of `currency_stats` objects for each row, which contains information about current supply, maximum supply, and the creator account for a symbol token. The `stats` table is scoped to the token symbol. Therefore, when one queries the `stats` table for a token symbol the result is one single entry/row corresponding to the queried symbol token if it was previously created, or nothing, otherwise. + */ + class [[eosio::contract("eosio.token")]] token : public contract { + public: + using contract::contract; + + /** + * Allows `issuer` account to create a token in supply of `maximum_supply`. If validation is successful a new entry in statstable for token symbol scope gets created. + * + * @param issuer - the account that creates the token, + * @param maximum_supply - the maximum supply set for the token created. + * + * @pre Token symbol has to be valid, + * @pre Token symbol must not be already created, + * @pre maximum_supply has to be smaller than the maximum supply allowed by the system: 1^62 - 1. + * @pre Maximum supply must be positive; + */ + [[eosio::action]] + void create( const name& issuer, + const asset& maximum_supply); + /** + * This action issues to `to` account a `quantity` of tokens. + * + * @param to - the account to issue tokens to, it must be the same as the issuer, + * @param quantity - the amount of tokens to be issued, + * @memo - the memo string that accompanies the token issue transaction. + */ + [[eosio::action]] + void issue( const name& to, const asset& quantity, const string& memo ); + + /** + * The opposite for create action, if all validations succeed, + * it debits the statstable.supply amount. + * + * @param quantity - the quantity of tokens to retire, + * @param memo - the memo string to accompany the transaction. + */ + [[eosio::action]] + void retire( const asset& quantity, const string& memo ); + + /** + * Allows `from` account to transfer to `to` account the `quantity` tokens. + * One account is debited and the other is credited with quantity tokens. + * + * @param from - the account to transfer from, + * @param to - the account to be transferred to, + * @param quantity - the quantity of tokens to be transferred, + * @param memo - the memo string to accompany the transaction. + */ + [[eosio::action]] + void transfer( const name& from, + const name& to, + const asset& quantity, + const string& memo ); + /** + * Allows `ram_payer` to create an account `owner` with zero balance for + * token `symbol` at the expense of `ram_payer`. + * + * @param owner - the account to be created, + * @param symbol - the token to be payed with by `ram_payer`, + * @param ram_payer - the account that supports the cost of this action. + * + * More information can be read [here](https://github.com/EOSIO/eosio.contracts/issues/62) + * and [here](https://github.com/EOSIO/eosio.contracts/issues/61). + */ + [[eosio::action]] + void open( const name& owner, const symbol& symbol, const name& ram_payer ); + + /** + * This action is the opposite for open, it closes the account `owner` + * for token `symbol`. + * + * @param owner - the owner account to execute the close action for, + * @param symbol - the symbol of the token to execute the close action for. + * + * @pre The pair of owner plus symbol has to exist otherwise no action is executed, + * @pre If the pair of owner plus symbol exists, the balance has to be zero. + */ + [[eosio::action]] + void close( const name& owner, const symbol& symbol ); + + static asset get_supply( const name& token_contract_account, const symbol_code& sym_code ) + { + stats statstable( token_contract_account, sym_code.raw() ); + const auto& st = statstable.get( sym_code.raw(), "invalid supply symbol code" ); + return st.supply; + } + + static asset get_balance( const name& token_contract_account, const name& owner, const symbol_code& sym_code ) + { + accounts accountstable( token_contract_account, owner.value ); + const auto& ac = accountstable.get( sym_code.raw(), "no balance with specified symbol" ); + return ac.balance; + } + + using create_action = eosio::action_wrapper<"create"_n, &token::create>; + using issue_action = eosio::action_wrapper<"issue"_n, &token::issue>; + using retire_action = eosio::action_wrapper<"retire"_n, &token::retire>; + using transfer_action = eosio::action_wrapper<"transfer"_n, &token::transfer>; + using open_action = eosio::action_wrapper<"open"_n, &token::open>; + using close_action = eosio::action_wrapper<"close"_n, &token::close>; + private: + struct [[eosio::table]] account { + asset balance; + + uint64_t primary_key()const { return balance.symbol.code().raw(); } + }; + + struct [[eosio::table]] currency_stats { + asset supply; + asset max_supply; + name issuer; + + uint64_t primary_key()const { return supply.symbol.code().raw(); } + }; + + typedef eosio::multi_index< "accounts"_n, account > accounts; + typedef eosio::multi_index< "stat"_n, currency_stats > stats; + + void sub_balance( const name& owner, const asset& value ); + void add_balance( const name& owner, const asset& value, const name& ram_payer ); + }; + +} diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..cd8f2e7 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,638 @@ +{ + "name": "eosio.bpay", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "dependencies": { + "@eosnetwork/vert": "^1", + "@wharfkit/antelope": "^1", + "@wharfkit/contract": "^1" + }, + "devDependencies": { + "@types/bun": "latest", + "typescript": "latest" + } + }, + "node_modules/@eosnetwork/vert": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@eosnetwork/vert/-/vert-1.0.0.tgz", + "integrity": "sha512-k0LsIQobA0R5BFVemerrMnfdvsnqUEx9dUUyv6P0cgUKMb/CCnvkTFZOD29IXkOIifLJVYgeD6hYPu78IyRqeg==", + "dependencies": { + "@ethereumjs/util": "^8.0.0-beta.1", + "@greymass/eosio": "^0.5.5", + "bn.js": "^5.2.0", + "brorand": "^1.1.0", + "chai": "^4.3.6", + "colors": "^1.4.0", + "cross-fetch": "^3.1.5", + "elliptic": "^6.5.4", + "hash.js": "^1.1.7", + "js-sha3": "^0.8.0", + "json-diff": "^0.9.0", + "json-diff-ts": "^1.2.4", + "lodash": "^4.17.21", + "loglevel": "^1.8.0", + "loglevel-plugin-prefix": "^0.8.4", + "rustbn.js": "^0.2.0", + "sorted-btree": "^1.6.0" + } + }, + "node_modules/@ethereumjs/rlp": { + "version": "4.0.1", + "license": "MPL-2.0", + "bin": { + "rlp": "bin/rlp" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@ethereumjs/util": { + "version": "8.1.0", + "license": "MPL-2.0", + "dependencies": { + "@ethereumjs/rlp": "^4.0.1", + "ethereum-cryptography": "^2.0.0", + "micro-ftch": "^0.3.1" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@greymass/eosio": { + "version": "0.5.5", + "license": "BSD-3-Clause-No-Military-License", + "dependencies": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "elliptic": "^6.5.4", + "hash.js": "^1.0.0", + "tslib": "^2.0.3" + } + }, + "node_modules/@greymass/eosio/node_modules/bn.js": { + "version": "4.12.0", + "license": "MIT" + }, + "node_modules/@noble/curves": { + "version": "1.3.0", + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.3.3" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@noble/hashes": { + "version": "1.3.3", + "license": "MIT", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@scure/base": { + "version": "1.1.5", + "license": "MIT", + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@scure/bip32": { + "version": "1.3.3", + "license": "MIT", + "dependencies": { + "@noble/curves": "~1.3.0", + "@noble/hashes": "~1.3.2", + "@scure/base": "~1.1.4" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@scure/bip39": { + "version": "1.2.2", + "license": "MIT", + "dependencies": { + "@noble/hashes": "~1.3.2", + "@scure/base": "~1.1.4" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@types/bun": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/@types/bun/-/bun-1.0.12.tgz", + "integrity": "sha512-qPb5FcygbpSS1NDBjWyQCWeI9kKXwSYSR1Enu7yb+gMXgFwGMhlyOvgV/7FGrdvAjlSXWRY6IDepos7k8WzAtQ==", + "dev": true, + "dependencies": { + "bun-types": "1.0.36" + } + }, + "node_modules/@types/node": { + "version": "20.11.30", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.30.tgz", + "integrity": "sha512-dHM6ZxwlmuZaRmUPfv1p+KrdD1Dci04FbdEm/9wEMouFqxYoFl5aMkt0VMAUtYRQDyYvD41WJLukhq/ha3YuTw==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/ws": { + "version": "8.5.10", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz", + "integrity": "sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@wharfkit/abicache": { + "version": "1.2.2", + "license": "BSD-3-Clause", + "dependencies": { + "@wharfkit/antelope": "^1.0.2", + "@wharfkit/signing-request": "^3.1.0", + "pako": "^2.0.4", + "tslib": "^2.1.0" + } + }, + "node_modules/@wharfkit/antelope": { + "version": "1.0.7", + "license": "BSD-3-Clause-No-Military-License", + "dependencies": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "elliptic": "^6.5.4", + "hash.js": "^1.0.0", + "pako": "^2.1.0", + "tslib": "^2.0.3" + } + }, + "node_modules/@wharfkit/antelope/node_modules/bn.js": { + "version": "4.12.0", + "license": "MIT" + }, + "node_modules/@wharfkit/contract": { + "version": "1.1.5", + "license": "BSD-3-Clause", + "dependencies": { + "@wharfkit/abicache": "^1.2.0", + "@wharfkit/antelope": "^1.0.4", + "@wharfkit/signing-request": "^3.1.0", + "tslib": "^2.1.0" + } + }, + "node_modules/@wharfkit/signing-request": { + "version": "3.1.0", + "license": "MIT", + "dependencies": { + "@wharfkit/antelope": "^1.0.0", + "tslib": "^2.0.3" + } + }, + "node_modules/assertion-error": { + "version": "1.1.0", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/bn.js": { + "version": "5.2.1", + "license": "MIT" + }, + "node_modules/brorand": { + "version": "1.1.0", + "license": "MIT" + }, + "node_modules/bun-types": { + "version": "1.0.36", + "resolved": "https://registry.npmjs.org/bun-types/-/bun-types-1.0.36.tgz", + "integrity": "sha512-gaIb1SyhB0JZfIEg73/kSFhqolUqJXC68peguhXGwqr27HuvI8nkD0LTIHp/1DY4cNadfXHYgYrZIWX7oEoXlg==", + "dev": true, + "dependencies": { + "@types/node": "~20.11.3", + "@types/ws": "~8.5.10" + } + }, + "node_modules/chai": { + "version": "4.4.1", + "license": "MIT", + "dependencies": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.3", + "deep-eql": "^4.1.3", + "get-func-name": "^2.0.2", + "loupe": "^2.3.6", + "pathval": "^1.1.1", + "type-detect": "^4.0.8" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/check-error": { + "version": "1.0.3", + "license": "MIT", + "dependencies": { + "get-func-name": "^2.0.2" + }, + "engines": { + "node": "*" + } + }, + "node_modules/cli-color": { + "version": "2.0.4", + "license": "ISC", + "dependencies": { + "d": "^1.0.1", + "es5-ext": "^0.10.64", + "es6-iterator": "^2.0.3", + "memoizee": "^0.4.15", + "timers-ext": "^0.1.7" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/colors": { + "version": "1.4.0", + "license": "MIT", + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/cross-fetch": { + "version": "3.1.8", + "license": "MIT", + "dependencies": { + "node-fetch": "^2.6.12" + } + }, + "node_modules/d": { + "version": "1.0.2", + "license": "ISC", + "dependencies": { + "es5-ext": "^0.10.64", + "type": "^2.7.2" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/deep-eql": { + "version": "4.1.3", + "license": "MIT", + "dependencies": { + "type-detect": "^4.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/difflib": { + "version": "0.2.4", + "dependencies": { + "heap": ">= 0.2.0" + } + }, + "node_modules/dreamopt": { + "version": "0.8.0", + "dependencies": { + "wordwrap": ">=0.0.2" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/elliptic": { + "version": "6.5.5", + "license": "MIT", + "dependencies": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/elliptic/node_modules/bn.js": { + "version": "4.12.0", + "license": "MIT" + }, + "node_modules/es5-ext": { + "version": "0.10.64", + "hasInstallScript": true, + "license": "ISC", + "dependencies": { + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.3", + "esniff": "^2.0.1", + "next-tick": "^1.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/es6-iterator": { + "version": "2.0.3", + "license": "MIT", + "dependencies": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, + "node_modules/es6-symbol": { + "version": "3.1.4", + "license": "ISC", + "dependencies": { + "d": "^1.0.2", + "ext": "^1.7.0" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/es6-weak-map": { + "version": "2.0.3", + "license": "ISC", + "dependencies": { + "d": "1", + "es5-ext": "^0.10.46", + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.1" + } + }, + "node_modules/esniff": { + "version": "2.0.1", + "license": "ISC", + "dependencies": { + "d": "^1.0.1", + "es5-ext": "^0.10.62", + "event-emitter": "^0.3.5", + "type": "^2.7.2" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/ethereum-cryptography": { + "version": "2.1.3", + "license": "MIT", + "dependencies": { + "@noble/curves": "1.3.0", + "@noble/hashes": "1.3.3", + "@scure/bip32": "1.3.3", + "@scure/bip39": "1.2.2" + } + }, + "node_modules/event-emitter": { + "version": "0.3.5", + "license": "MIT", + "dependencies": { + "d": "1", + "es5-ext": "~0.10.14" + } + }, + "node_modules/ext": { + "version": "1.7.0", + "license": "ISC", + "dependencies": { + "type": "^2.7.2" + } + }, + "node_modules/get-func-name": { + "version": "2.0.2", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/hash.js": { + "version": "1.1.7", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "node_modules/heap": { + "version": "0.2.7", + "license": "MIT" + }, + "node_modules/hmac-drbg": { + "version": "1.0.1", + "license": "MIT", + "dependencies": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "license": "ISC" + }, + "node_modules/is-promise": { + "version": "2.2.2", + "license": "MIT" + }, + "node_modules/js-sha3": { + "version": "0.8.0", + "license": "MIT" + }, + "node_modules/json-diff": { + "version": "0.9.1", + "license": "MIT", + "dependencies": { + "cli-color": "^2.0.0", + "difflib": "~0.2.1", + "dreamopt": "~0.8.0" + }, + "bin": { + "json-diff": "bin/json-diff.js" + }, + "engines": { + "node": "*" + } + }, + "node_modules/json-diff-ts": { + "version": "1.2.8", + "license": "MIT", + "dependencies": { + "lodash": "^4.17.21" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "license": "MIT" + }, + "node_modules/loglevel": { + "version": "1.9.1", + "license": "MIT", + "engines": { + "node": ">= 0.6.0" + }, + "funding": { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/loglevel" + } + }, + "node_modules/loglevel-plugin-prefix": { + "version": "0.8.4", + "license": "MIT" + }, + "node_modules/loupe": { + "version": "2.3.7", + "license": "MIT", + "dependencies": { + "get-func-name": "^2.0.1" + } + }, + "node_modules/lru-queue": { + "version": "0.1.0", + "license": "MIT", + "dependencies": { + "es5-ext": "~0.10.2" + } + }, + "node_modules/memoizee": { + "version": "0.4.15", + "license": "ISC", + "dependencies": { + "d": "^1.0.1", + "es5-ext": "^0.10.53", + "es6-weak-map": "^2.0.3", + "event-emitter": "^0.3.5", + "is-promise": "^2.2.2", + "lru-queue": "^0.1.0", + "next-tick": "^1.1.0", + "timers-ext": "^0.1.7" + } + }, + "node_modules/micro-ftch": { + "version": "0.3.1", + "license": "MIT" + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "license": "ISC" + }, + "node_modules/minimalistic-crypto-utils": { + "version": "1.0.1", + "license": "MIT" + }, + "node_modules/next-tick": { + "version": "1.1.0", + "license": "ISC" + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/pako": { + "version": "2.1.0", + "license": "(MIT AND Zlib)" + }, + "node_modules/pathval": { + "version": "1.1.1", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/rustbn.js": { + "version": "0.2.0", + "license": "(MIT OR Apache-2.0)" + }, + "node_modules/sorted-btree": { + "version": "1.8.1", + "license": "MIT" + }, + "node_modules/timers-ext": { + "version": "0.1.7", + "license": "ISC", + "dependencies": { + "es5-ext": "~0.10.46", + "next-tick": "1" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "license": "MIT" + }, + "node_modules/tslib": { + "version": "2.6.2", + "license": "0BSD" + }, + "node_modules/type": { + "version": "2.7.2", + "license": "ISC" + }, + "node_modules/type-detect": { + "version": "4.0.8", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/typescript": { + "version": "5.4.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", + "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "license": "BSD-2-Clause" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/wordwrap": { + "version": "1.0.0", + "license": "MIT" + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..7349524 --- /dev/null +++ b/package.json @@ -0,0 +1,16 @@ +{ + "type": "module", + "scripts": { + "build": "cdt-cpp eosio.bpay.cpp -I ./include", + "test": "bun test" + }, + "dependencies": { + "@eosnetwork/vert": "^1", + "@wharfkit/antelope": "^1", + "@wharfkit/contract": "^1" + }, + "devDependencies": { + "@types/bun": "latest", + "typescript": "latest" + } +} \ No newline at end of file