Skip to content

Commit

Permalink
Merge pull request #1 from greymass/tokens
Browse files Browse the repository at this point in the history
Tokens
  • Loading branch information
aaroncox authored Jan 28, 2025
2 parents 5af8184 + ee4ed6d commit e685aa1
Show file tree
Hide file tree
Showing 10 changed files with 446 additions and 72 deletions.
7 changes: 6 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ build/api/production:
testnet:
make -C contracts/api testnet

# MAINNET

mainnet:
make -C contracts/api mainnet

# UNIT TESTS

test/api: build/api/debug node_modules codegen
Expand All @@ -44,4 +49,4 @@ test: build/debug codegen node_modules
codegen: codegen/api

codegen/api:
npx @wharfkit/cli generate --json ./contracts/api/build/api.abi --file ./codegen/api.ts api
npx @wharfkit/cli generate --json ./contracts/api/build/api.abi --file ./codegen/api.ts unicove.gm
28 changes: 21 additions & 7 deletions contracts/api/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ BIN := ./node_modules/.bin

SRC_CONTRACT_NAME = api
MAINNET_NODE_URL = https://eos.greymass.com
MAINNET_CONTRACT_ACCOUNT = api
MAINNET_CONTRACT_ACCOUNT = unicove.gm
TESTNET_NODE_URL = https://jungle4.greymass.com
TESTNET_CONTRACT_ACCOUNT = api.gm
TESTNET_CONTRACT_ACCOUNT = unicove.gm

build: | build/dir
cdt-cpp -abigen -abigen_output=build/${SRC_CONTRACT_NAME}.abi -o build/${SRC_CONTRACT_NAME}.wasm src/${SRC_CONTRACT_NAME}.cpp -R src -I include -D DEBUG
Expand All @@ -29,11 +29,15 @@ testnet: build/debug
build/ ${SRC_CONTRACT_NAME}.wasm ${SRC_CONTRACT_NAME}.abi

mainnet: build/production
cleos -u $(MAINNET_NODE_URL) set contract \
--dont-broadcast --skip-sign --expiration 259200 --json-file msig.json \
${MAINNET_CONTRACT_ACCOUNT} build/ ${SRC_CONTRACT_NAME}.wasm ${SRC_CONTRACT_NAME}.abi
cleos -u $(MAINNET_NODE_URL) multisig propose_trx ${MAINNET_MSIG_PROPOSAL} ${MAINNET_MSIG_SIGNERS} \
msig.json ${MAINNET_MSIG_PROPOSER} -p ${MAINNET_MSIG_PERMISSION}
cleos -u $(MAINNET_NODE_URL) set contract $(MAINNET_CONTRACT_ACCOUNT) \
build/ ${SRC_CONTRACT_NAME}.wasm ${SRC_CONTRACT_NAME}.abi

# mainnet: build/production
# cleos -u $(MAINNET_NODE_URL) set contract \
# --dont-broadcast --skip-sign --expiration 259200 --json-file msig.json \
# ${MAINNET_CONTRACT_ACCOUNT} build/ ${SRC_CONTRACT_NAME}.wasm ${SRC_CONTRACT_NAME}.abi
# cleos -u $(MAINNET_NODE_URL) multisig propose_trx ${MAINNET_MSIG_PROPOSAL} ${MAINNET_MSIG_SIGNERS} \
# msig.json ${MAINNET_MSIG_PROPOSER} -p ${MAINNET_MSIG_PERMISSION}

test: build/debug node_modules build/contract.ts
bun test
Expand Down Expand Up @@ -78,3 +82,13 @@ distclean: clean

node_modules:
bun install

.PHONY: testnet/mockdata
testnet/mockdata:
cleos -u $(TESTNET_NODE_URL) push action $(TESTNET_CONTRACT_ACCOUNT) addtokens '{"tokens": [{"contract": "eosio.token", "symbol": "4,EOS"},{"contract": "eosio.token", "symbol": "4,EOS"}]}' -p $(TESTNET_CONTRACT_ACCOUNT)@active
# cleos -u $(TESTNET_NODE_URL) push action $(TESTNET_CONTRACT_ACCOUNT) addtoken '{"contract": "eosio.token", "symbol": "4,EOS"}' -p $(TESTNET_CONTRACT_ACCOUNT)@active
# cleos -u $(TESTNET_NODE_URL) push action $(TESTNET_CONTRACT_ACCOUNT) addtoken '{"contract": "eosio.token", "symbol": "4,JUNGLE"}' -p $(TESTNET_CONTRACT_ACCOUNT)@active

.PHONY: testnet/wipe
testnet/wipe:
cleos -u $(TESTNET_NODE_URL) push action $(TESTNET_CONTRACT_ACCOUNT) wipe '{}' -p $(TESTNET_CONTRACT_ACCOUNT)@active
52 changes: 46 additions & 6 deletions contracts/api/include/api/api.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,30 +22,70 @@ struct get_account_response
eosiosystem::rex_fund rexfund;
};

struct token_definition
{
name contract;
symbol symbol;
};

class [[eosio::contract("api")]] api : public contract
{
public:
using contract::contract;

struct [[eosio::table("config")]] config_row
{
name system_contract = name("eosio");
name system_contract_msig = name("eosio.msig");
name system_token_contract = name("eosio.token");
symbol system_token_symbol = symbol("EOS", 4);
};
typedef eosio::singleton<"config"_n, config_row> config_table;

struct [[eosio::table("tokens")]] token_row
{
uint64_t id;
name contract;
symbol symbol;
uint64_t primary_key() const { return id; }
};
typedef eosio::multi_index<"tokens"_n, token_row> token_table;

[[eosio::action]] void addtoken(const token_definition token);
[[eosio::action]] void addtokens(const std::vector<token_definition> tokens);
[[eosio::action]] void removetoken(const uint64_t id);
[[eosio::action]] void setconfig(const name system_contract,
const name system_contract_msig,
const name system_token_contract,
const symbol system_token_symbol);
/**
* getaccount readonly action
*/
[[eosio::action]] get_account_response getaccount(const name account);
[[eosio::action, eosio::read_only]] get_account_response getaccount(const name account);
using getaccount_action = action_wrapper<"getaccount"_n, &api::getaccount>;

// DEBUG (used to help testing)
[[eosio::action, eosio::read_only]] std::vector<asset> getbalances(const name account,
const std::vector<token_definition> tokens);
using getbalances_action = action_wrapper<"getbalances"_n, &api::getbalances>;

[[eosio::action, eosio::read_only]] std::vector<token_definition> gettokens();
using gettokens_action = action_wrapper<"gettokens"_n, &api::gettokens>;

#ifdef DEBUG
[[eosio::action]] void
cleartable(const name table_name, const optional<name> scope, const optional<uint64_t> max_rows);
[[eosio::action]] void wipe();
[[eosio::action]] void reset();
#endif

private:
// DEBUG (used to help testing)
void add_token(const token_definition token);
std::vector<token_definition> get_token_definitions();

#ifdef DEBUG
// @debug
template <typename T>
void clear_table(T& table, uint64_t rows_to_clear);
void reset_singletons();
void wipe_singletons();
void wipe_tables();
#endif
};

Expand Down
113 changes: 96 additions & 17 deletions contracts/api/src/api.cpp
Original file line number Diff line number Diff line change
@@ -1,32 +1,31 @@
#include "api/api.hpp"

const name SYSTEM_CONTRACT_ACCOUNT = name("eosio");
const name MSIG_CONTRACT_ACCOUNT = name("eosio.msig");
const name SYSTEM_TOKEN_ACCOUNT = name("eosio.token");
const symbol SYSTEM_TOKEN_SYMBOL = eosiosystem::system_contract::get_core_symbol();

namespace api {

[[eosio::action, eosio::read_only]] get_account_response api::getaccount(const name account)
{
config_table _config(get_self(), get_self().value);
auto config = _config.get_or_default();

// get core token balance for the account
asset balance;
eosio::token::accounts balance_table(SYSTEM_TOKEN_ACCOUNT, account.value);
auto balance_itr = balance_table.get(SYSTEM_TOKEN_SYMBOL.code().raw(), "no balance object found");
balance = balance_itr.balance;
asset balance = asset(0, config.system_token_symbol);
eosio::token::accounts balance_table(config.system_token_contract, account.value);
auto balance_itr = balance_table.find(config.system_token_symbol.code().raw());
if (balance_itr != balance_table.end()) {
balance = balance_itr->balance;
}

// get pending refund for the account
eosiosystem::refund_request refund;

eosiosystem::refunds_table refunds_table(SYSTEM_CONTRACT_ACCOUNT, account.value);
auto refund_itr = refunds_table.find(account.value);
eosiosystem::refunds_table refunds_table(config.system_contract, account.value);
auto refund_itr = refunds_table.find(account.value);
if (refund_itr != refunds_table.end()) {
refund = *refund_itr;
}

// get all delegated balances for the account
std::vector<eosiosystem::delegated_bandwidth> dbw_rows;
eosiosystem::del_bandwidth_table dbw_table(SYSTEM_CONTRACT_ACCOUNT, account.value);
eosiosystem::del_bandwidth_table dbw_table(config.system_contract, account.value);
auto dbw_itr = dbw_table.begin();
while (dbw_itr != dbw_table.end()) {
dbw_rows.push_back(*dbw_itr);
Expand All @@ -35,7 +34,7 @@ namespace api {

// get all msig proposals from the account
std::vector<eosio::multisig::proposal> msig_rows;
eosio::multisig::proposals msig_table(MSIG_CONTRACT_ACCOUNT, account.value);
eosio::multisig::proposals msig_table(config.system_contract_msig, account.value);
auto msig_itr = msig_table.begin();
while (msig_itr != msig_table.end()) {
msig_rows.push_back(*msig_itr);
Expand All @@ -44,17 +43,16 @@ namespace api {

eosiosystem::rex_balance rexbal;
eosiosystem::rex_fund rexfund;

if (eosiosystem::system_contract::rex_system_initialized()) {
// get rexbal entry for the account
eosiosystem::rex_balance_table rexbal_table(SYSTEM_CONTRACT_ACCOUNT, SYSTEM_CONTRACT_ACCOUNT.value);
eosiosystem::rex_balance_table rexbal_table(config.system_contract, config.system_contract.value);
auto rex_itr = rexbal_table.find(account.value);
if (rex_itr != rexbal_table.end()) {
rexbal = *rex_itr;
}

// get rexfund entry for the account
eosiosystem::rex_fund_table rexfund_table(SYSTEM_CONTRACT_ACCOUNT, SYSTEM_CONTRACT_ACCOUNT.value);
eosiosystem::rex_fund_table rexfund_table(config.system_contract, config.system_contract.value);
auto rexfund_itr = rexfund_table.find(account.value);
if (rexfund_itr != rexfund_table.end()) {
rexfund = *rexfund_itr;
Expand All @@ -70,6 +68,87 @@ namespace api {
.rexfund = rexfund};
}

std::vector<token_definition> api::get_token_definitions()
{
std::vector<token_definition> result;
token_table _tokens(get_self(), get_self().value);
auto token_itr = _tokens.begin();
while (token_itr != _tokens.end()) {
result.push_back({.contract = token_itr->contract, .symbol = token_itr->symbol});
token_itr++;
}
return result;
}

[[eosio::action, eosio::read_only]] std::vector<token_definition> api::gettokens() { return get_token_definitions(); }

[[eosio::action, eosio::read_only]] std::vector<asset> api::getbalances(const name account,
const std::vector<token_definition> tokens)
{
std::vector<asset> balances;

std::vector<token_definition> token_definitions = tokens;
if (token_definitions.size() == 0) {
token_definitions = get_token_definitions();
}

for (const auto& token : token_definitions) {
eosio::token::accounts _accounts(token.contract, account.value);
auto balance_itr = _accounts.find(token.symbol.code().raw());
if (balance_itr != _accounts.end()) {
balances.push_back(balance_itr->balance);
} else {
balances.push_back(asset(0, token.symbol));
}
}

return balances;
}

void api::add_token(const token_definition token)
{
require_auth(get_self());
token_table tokens(get_self(), get_self().value);
tokens.emplace(get_self(), [&](auto& row) {
row.id = tokens.available_primary_key();
row.contract = token.contract;
row.symbol = token.symbol;
});
}

[[eosio::action]] void api::addtoken(const token_definition token) { add_token(token); }

[[eosio::action]] void api::addtokens(const std::vector<token_definition> tokens)
{
for (const auto& token : tokens) {
add_token(token);
}
}

[[eosio::action]] void api::removetoken(const uint64_t id)
{
require_auth(get_self());
token_table tokens(get_self(), get_self().value);
auto token_itr = tokens.find(id);
check(token_itr != tokens.end(), "token not found");
tokens.erase(token_itr);
}

[[eosio::action]] void api::setconfig(const name system_contract,
const name system_contract_msig,
const name system_token_contract,
const symbol system_token_symbol)
{
require_auth(get_self());
config_table _config(get_self(), get_self().value);
auto config = _config.get_or_default();
config.system_contract = system_contract;
config.system_contract_msig = system_contract_msig;
config.system_token_contract = system_token_contract;
config.system_token_symbol = system_token_symbol;
_config.set(config, get_self());
}

} // namespace api

// DEBUG (used on testnet)
Expand Down
55 changes: 25 additions & 30 deletions contracts/api/src/debug.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
namespace api {

// @debug
template <typename T>
void api::clear_table(T& table, uint64_t rows_to_clear)
{
Expand All @@ -10,43 +9,39 @@ void api::clear_table(T& table, uint64_t rows_to_clear)
}
}

// @debug
[[eosio::action]] void
api::cleartable(const name table_name, const optional<name> scope, const optional<uint64_t> max_rows)
void api::reset_singletons()
{
require_auth(get_self());
const uint64_t rows_to_clear = (!max_rows || *max_rows == 0) ? -1 : *max_rows;
const uint64_t value = scope ? scope->value : get_self().value;

// list out all the tables that could be cleared
//
// api::table1 _table1(get_self(), value);
// api::table2 _table2(get_self(), value);

// Use an if/else if/else chain to determine which table to clear
//
// if (table_name == "table1"_n)
// clear_table(_table1, rows_to_clear);
// else if (table_name == "table2"_n)
// clear_table(_table2, rows_to_clear);
// else
// check(false, "cleartable: [table_name] unknown table to clear");
config_table _config(get_self(), get_self().value);
config_row default_row;
_config.set(default_row, get_self());
}

void api::wipe_singletons()
{
config_table _config(get_self(), get_self().value);
_config.remove();
}

void api::wipe_tables()
{
token_table tokens(get_self(), get_self().value);
clear_table(tokens, -1);
}

// @debug
[[eosio::action]] void api::wipe()
{
require_auth(get_self());

// Define the tables to wipe
//
// api::table1 _table1(get_self(), get_self().value);
// api::table2 _table2(get_self(), get_self().value);
wipe_singletons();
wipe_tables();
}

[[eosio::action]] void api::reset()
{
require_auth(get_self());

// Call clear on the tables to wipe
//
// clear_table(_table1, -1);
// clear_table(_table2, -1);
reset_singletons();
wipe_tables();
}

} // namespace api
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
"@types/bun": "^1.0.4",
"@typescript-eslint/eslint-plugin": "^7.8.0",
"@typescript-eslint/parser": "^6.20.0",
"@wharfkit/abicache": "^1.2.2",
"@wharfkit/signing-request": "^3.2.0",
"eslint": "^8.56.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-prettier": "^5.1.3",
Expand Down
Loading

0 comments on commit e685aa1

Please sign in to comment.