From 5bf8b92b3fea5ef7e1cb74dabf6968e54bc2318e Mon Sep 17 00:00:00 2001 From: MZoxx <148331637+MZoxx@users.noreply.github.com> Date: Mon, 18 May 2026 09:39:17 +0700 Subject: [PATCH] Add GGWP (WolfPack) contract commands to qubic-cli Adds CLI support for the GGWP (WolfPack) revenue-distribution and staking smart contract: - Read: status, holder/clan/shareholder/staking info, exclude info, distribution preview - Admin: deposit revenue, add/remove clan member, set clan rank, set admin, set exclude address - Staking: stake, request/finalize unstake, deposit staking rewards, claim staking rewards New files ggwp.cpp / ggwp.h; command parsing in argparser.h, dispatch in main.cpp, command enum in structs.h, globals in global.h, build entry in CMakeLists.txt, and a [WOLFPACK COMMANDS] section in both the -help output and README.md. Builds cleanly against current main. --- CMakeLists.txt | 1 + README.md | 38 +++++++ argparser.h | 200 +++++++++++++++++++++++++++++++++ ggwp.cpp | 291 +++++++++++++++++++++++++++++++++++++++++++++++++ ggwp.h | 202 ++++++++++++++++++++++++++++++++++ global.h | 6 + main.cpp | 85 +++++++++++++++ structs.h | 18 +++ 8 files changed, 841 insertions(+) create mode 100644 ggwp.cpp create mode 100644 ggwp.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 3525837..1764147 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,6 +18,7 @@ SET(FILES ${CMAKE_SOURCE_DIR}/asset_utils.cpp ${CMAKE_SOURCE_DIR}/qearn.cpp ${CMAKE_SOURCE_DIR}/qpi_adapter.cpp ${CMAKE_SOURCE_DIR}/qrwa.cpp + ${CMAKE_SOURCE_DIR}/ggwp.cpp ${CMAKE_SOURCE_DIR}/qswap.cpp ${CMAKE_SOURCE_DIR}/quottery.cpp ${CMAKE_SOURCE_DIR}/qutil.cpp diff --git a/README.md b/README.md index c992410..2400f37 100644 --- a/README.md +++ b/README.md @@ -520,6 +520,44 @@ Commands: -qbondgetcfa Get list of commission free addresses. +[WOLFPACK COMMANDS] + -ggwpstatus + Show WolfPack (GGWP) contract status. + -ggwpholderinfo
+ Show token balance and holder status for an address. + -ggwpclaninfo
+ Show clan rank and membership for an address. + -ggwpshareholderinfo
+ Show SC shareholder status and shares for an address. + -ggwpstakinginfo
+ Show staking info (staked amount, pending rewards, unstake status) for an address. + -ggwpexcludeinfo + Show WolfPack exclude addresses (slot 1 and slot 2). + -ggwpdistpreview + Preview the distribution split for AMOUNT QU. + -ggwpdeposit + Deposit revenue into WolfPack (amount in QU). + -ggwpaddclan
+ Add a clan member with rank 0-5 (admin-only). + -ggwpremoveclan
+ Remove a clan member (admin-only). + -ggwpsetclanrank
+ Set clan member rank 0-5 (admin-only). + -ggwpsetadmin
+ Set a new admin address (admin-only). + -ggwpsetexclude
+ Set exclude address slot 1 or 2 (admin-only). + -ggwpstake + Stake AMOUNT GGWP shares into the WolfPack contract. + -ggwprequestunstake + Request unstaking of AMOUNT shares (2-epoch delay before finalize). + -ggwpfinalizeunstake + Finalize a pending unstake request after the delay has passed. + -ggwpdepositstaking + Deposit AMOUNT GGWP shares into the staking reward pool. + -ggwpclaimrewards + Claim accumulated staking rewards. + [TESTING COMMANDS] -testqpifunctionsoutput Test that output of qpi functions matches TickData and quorum tick votes for 15 ticks in the future (as specified by scheduletick offset). Requires the TESTEXA SC to be enabled. diff --git a/argparser.h b/argparser.h index 1a0fc26..bbd2ff4 100644 --- a/argparser.h +++ b/argparser.h @@ -212,6 +212,44 @@ void print_help() printf("\t-qrwarevokeasset \n"); printf("\t\tRevoke asset management rights back to QX (100 QU fee).\n"); + printf("\n[WOLFPACK COMMANDS]\n"); + printf("\t-ggwpstatus\n"); + printf("\t\tShow WolfPack contract status.\n"); + printf("\t-ggwpholderinfo
\n"); + printf("\t\tShow token balance and holder status for an address.\n"); + printf("\t-ggwpclaninfo
\n"); + printf("\t\tShow clan rank and membership for an address.\n"); + printf("\t-ggwpshareholderinfo
\n"); + printf("\t\tShow SC shareholder status and shares for an address.\n"); + printf("\t-ggwpexcludeinfo\n"); + printf("\t\tShow WolfPack exclude addresses (slot 1 and slot 2).\n"); + printf("\t-ggwpdistpreview \n"); + printf("\t\tPreview distribution split for AMOUNT QU (calls WP fn 7).\n"); + printf("\t-ggwpdeposit \n"); + printf("\t\tDeposit revenue into WolfPack (amount in QU).\n"); + printf("\t-ggwpaddclan
\n"); + printf("\t\tAdd a clan member with rank 0-5 (admin-only).\n"); + printf("\t-ggwpremoveclan
\n"); + printf("\t\tRemove a clan member (admin-only).\n"); + printf("\t-ggwpsetclanrank
\n"); + printf("\t\tSet clan member rank 0-5 (admin-only).\n"); + printf("\t-ggwpsetadmin
\n"); + printf("\t\tSet new admin address (admin-only).\n"); + printf("\t-ggwpsetexclude
\n"); + printf("\t\tSet exclude address slot 1 or 2 (admin-only).\n"); + printf("\t-ggwpstakinginfo
\n"); + printf("\t\tShow staking info (staked amount, pending rewards, unstake status) for an address.\n"); + printf("\t-ggwpstake \n"); + printf("\t\tStake AMOUNT GGWP shares into the WolfPack contract.\n"); + printf("\t-ggwprequestunstake \n"); + printf("\t\tRequest unstaking of AMOUNT shares (2-epoch delay before finalize).\n"); + printf("\t-ggwpfinalizeunstake\n"); + printf("\t\tFinalize a pending unstake request after the delay has passed.\n"); + printf("\t-ggwpdepositstaking \n"); + printf("\t\tDeposit AMOUNT GGWP shares into the staking reward pool.\n"); + printf("\t-ggwpclaimrewards\n"); + printf("\t\tClaim accumulated staking rewards.\n"); + printf("\n[SMART CONTRACT COMMANDS]\n"); printf("\t-callcontractfunction \n"); printf("\t\tCall a contract function of contract index and print the output. Valid node ip/port are required.\t\n"); @@ -1393,6 +1431,168 @@ void parseArgument(int argc, char** argv) break; } + /***************************** + ***** WOLFPACK COMMANDS ***** + *****************************/ + + if (strcmp(argv[i], "-ggwpstatus") == 0) + { + g_cmd = WP_STATUS; + i += 1; + CHECK_OVER_PARAMETERS + break; + } + if (strcmp(argv[i], "-ggwpholderinfo") == 0) + { + CHECK_NUMBER_OF_PARAMETERS(1) + g_cmd = WP_HOLDER_INFO; + g_wp_identity = argv[i + 1]; + i += 2; + CHECK_OVER_PARAMETERS + break; + } + if (strcmp(argv[i], "-ggwpclaninfo") == 0) + { + CHECK_NUMBER_OF_PARAMETERS(1) + g_cmd = WP_CLAN_MEMBER_INFO; + g_wp_identity = argv[i + 1]; + i += 2; + CHECK_OVER_PARAMETERS + break; + } + if (strcmp(argv[i], "-ggwpshareholderinfo") == 0) + { + CHECK_NUMBER_OF_PARAMETERS(1) + g_cmd = WP_SHAREHOLDER_INFO; + g_wp_identity = argv[i + 1]; + i += 2; + CHECK_OVER_PARAMETERS + break; + } + if (strcmp(argv[i], "-ggwpexcludeinfo") == 0) + { + g_cmd = WP_EXCLUDE_INFO; + i += 1; + CHECK_OVER_PARAMETERS + break; + } + if (strcmp(argv[i], "-ggwpdistpreview") == 0) + { + CHECK_NUMBER_OF_PARAMETERS(1) + g_cmd = WP_DIST_PREVIEW; + g_wp_amount = strtoull(argv[i + 1], nullptr, 10); + i += 2; + CHECK_OVER_PARAMETERS + break; + } + if (strcmp(argv[i], "-ggwpdeposit") == 0) + { + CHECK_NUMBER_OF_PARAMETERS(1) + g_cmd = WP_DEPOSIT_REVENUE; + g_wp_amount = strtoull(argv[i + 1], nullptr, 10); + i += 2; + CHECK_OVER_PARAMETERS + break; + } + if (strcmp(argv[i], "-ggwpaddclan") == 0) + { + CHECK_NUMBER_OF_PARAMETERS(2) + g_cmd = WP_ADD_CLAN_MEMBER; + g_wp_address = argv[i + 1]; + g_wp_rank = strtoull(argv[i + 2], nullptr, 10); + i += 3; + CHECK_OVER_PARAMETERS + break; + } + if (strcmp(argv[i], "-ggwpremoveclan") == 0) + { + CHECK_NUMBER_OF_PARAMETERS(1) + g_cmd = WP_REMOVE_CLAN_MEMBER; + g_wp_address = argv[i + 1]; + i += 2; + CHECK_OVER_PARAMETERS + break; + } + if (strcmp(argv[i], "-ggwpsetclanrank") == 0) + { + CHECK_NUMBER_OF_PARAMETERS(2) + g_cmd = WP_SET_CLAN_RANK; + g_wp_address = argv[i + 1]; + g_wp_rank = strtoull(argv[i + 2], nullptr, 10); + i += 3; + CHECK_OVER_PARAMETERS + break; + } + if (strcmp(argv[i], "-ggwpsetadmin") == 0) + { + CHECK_NUMBER_OF_PARAMETERS(1) + g_cmd = WP_SET_ADMIN; + g_wp_address = argv[i + 1]; + i += 2; + CHECK_OVER_PARAMETERS + break; + } + if (strcmp(argv[i], "-ggwpsetexclude") == 0) + { + CHECK_NUMBER_OF_PARAMETERS(2) + g_cmd = WP_SET_EXCLUDE_ADDRESS; + g_wp_slot = strtoull(argv[i + 1], nullptr, 10); + g_wp_address = argv[i + 2]; + i += 3; + CHECK_OVER_PARAMETERS + break; + } + if (strcmp(argv[i], "-ggwpstakinginfo") == 0) + { + CHECK_NUMBER_OF_PARAMETERS(1) + g_cmd = WP_STAKING_INFO; + g_wp_identity = argv[i + 1]; + i += 2; + CHECK_OVER_PARAMETERS + break; + } + if (strcmp(argv[i], "-ggwpstake") == 0) + { + CHECK_NUMBER_OF_PARAMETERS(1) + g_cmd = WP_STAKE; + g_wp_amount = strtoull(argv[i + 1], nullptr, 10); + i += 2; + CHECK_OVER_PARAMETERS + break; + } + if (strcmp(argv[i], "-ggwprequestunstake") == 0) + { + CHECK_NUMBER_OF_PARAMETERS(1) + g_cmd = WP_REQUEST_UNSTAKE; + g_wp_amount = strtoull(argv[i + 1], nullptr, 10); + i += 2; + CHECK_OVER_PARAMETERS + break; + } + if (strcmp(argv[i], "-ggwpfinalizeunstake") == 0) + { + g_cmd = WP_FINALIZE_UNSTAKE; + i += 1; + CHECK_OVER_PARAMETERS + break; + } + if (strcmp(argv[i], "-ggwpdepositstaking") == 0) + { + CHECK_NUMBER_OF_PARAMETERS(1) + g_cmd = WP_DEPOSIT_STAKING_REWARDS; + g_wp_amount = strtoull(argv[i + 1], nullptr, 10); + i += 2; + CHECK_OVER_PARAMETERS + break; + } + if (strcmp(argv[i], "-ggwpclaimrewards") == 0) + { + g_cmd = WP_CLAIM_STAKING_REWARDS; + i += 1; + CHECK_OVER_PARAMETERS + break; + } + /*********************** ***** QX COMMANDS ***** ***********************/ diff --git a/ggwp.cpp b/ggwp.cpp new file mode 100644 index 0000000..6f29350 --- /dev/null +++ b/ggwp.cpp @@ -0,0 +1,291 @@ +#include "ggwp.h" +#include "wallet_utils.h" +#include "key_utils.h" +#include "logger.h" + +static void printIdentity(const char* label, const uint8_t* pubkey) +{ + char id[128] = {}; + getIdentityFromPublicKey(pubkey, id, false); + LOG("%s%s\n", label, id); +} + +// ─── Query functions ─────────────────────────────────────────── + +void wpStatus(const char* nodeIp, int nodePort) +{ + LOG("═══ WolfPack Contract Status ═══════════════════════════\n\n"); + + WPGetStatus_output out = {}; + if (runContractFunction(nodeIp, nodePort, WP_CONTRACT_INDEX, + WP_GET_STATUS, nullptr, 0, &out, sizeof(out))) + { + LOG("Holder Count: %llu\n", (unsigned long long)out.holderCount); + LOG("Total Tokens Snapshot: %llu\n", (unsigned long long)out.totalTokensSnapshot); + LOG("Shareholder Count: %llu\n", (unsigned long long)out.shareholderCount); + LOG("Total Shares Snapshot: %llu\n", (unsigned long long)out.totalSharesSnapshot); + LOG("Clan Member Count: %llu\n", (unsigned long long)out.clanMemberCount); + LOG("Clan Weighted Total: %llu\n", (unsigned long long)out.clanWeightedTotal); + LOG("Pending Revenue: %llu QU\n", (unsigned long long)out.pendingRevenue); + LOG("Reinvestment Fund: %llu QU\n", (unsigned long long)out.reinvestmentFund); + LOG("Total Distributed: %llu QU\n", (unsigned long long)out.totalDistributed); + LOG("Total Deposited: %llu QU\n", (unsigned long long)out.totalDeposited); + LOG("Last Payout Tick: %llu\n", (unsigned long long)out.lastPayoutTick); + LOG("Last Distribution Epoch: %llu\n", (unsigned long long)out.lastDistributionEpoch); + printIdentity("Admin: ", out.adminAddress); + } + else + { + LOG("ERROR: Could not query WP GetStatus (fn 1)\n"); + } +} + +void wpHolderInfo(const char* nodeIp, int nodePort, const char* address) +{ + WPGetHolderInfo_input input = {}; + getPublicKeyFromIdentity(address, input.holderAddress); + + WPGetHolderInfo_output out = {}; + if (runContractFunction(nodeIp, nodePort, WP_CONTRACT_INDEX, + WP_GET_HOLDER_INFO, &input, sizeof(input), &out, sizeof(out))) + { + LOG("═══ WolfPack Holder Info ════════════════════════════════\n\n"); + LOG("Address: %s\n", address); + LOG("Token Balance: %llu\n", (unsigned long long)out.tokenBalance); + LOG("Is Holder: %s\n", out.isHolder ? "YES" : "NO"); + } + else + { + LOG("ERROR: Could not query WP GetHolderInfo (fn 2)\n"); + } +} + +void wpClanMemberInfo(const char* nodeIp, int nodePort, const char* address) +{ + WPGetClanMemberInfo_input input = {}; + getPublicKeyFromIdentity(address, input.memberAddress); + + WPGetClanMemberInfo_output out = {}; + if (runContractFunction(nodeIp, nodePort, WP_CONTRACT_INDEX, + WP_GET_CLAN_MEMBER_INFO, &input, sizeof(input), &out, sizeof(out))) + { + LOG("═══ WolfPack Clan Member Info ══════════════════════════\n\n"); + LOG("Address: %s\n", address); + LOG("Rank: %llu\n", (unsigned long long)out.rank); + LOG("Is Member: %s\n", out.isMember ? "YES" : "NO"); + } + else + { + LOG("ERROR: Could not query WP GetClanMemberInfo (fn 3)\n"); + } +} + +void wpShareholderInfo(const char* nodeIp, int nodePort, const char* address) +{ + WPGetShareholderInfo_input input = {}; + getPublicKeyFromIdentity(address, input.shareholderAddress); + + WPGetShareholderInfo_output out = {}; + if (runContractFunction(nodeIp, nodePort, WP_CONTRACT_INDEX, + WP_GET_SHAREHOLDER_INFO, &input, sizeof(input), &out, sizeof(out))) + { + LOG("═══ WolfPack Shareholder Info ══════════════════════════\n\n"); + LOG("Address: %s\n", address); + LOG("SC Shares: %llu\n", (unsigned long long)out.shares); + LOG("Is Shareholder: %s\n", out.isShareholder ? "YES" : "NO"); + } + else + { + LOG("ERROR: Could not query WP GetShareholderInfo (fn 4)\n"); + } +} + +// ─── Procedures ──────────────────────────────────────────────── + +void wpDepositRevenue(const char* nodeIp, int nodePort, const char* seed, + uint64_t amount, uint32_t scheduledTickOffset) +{ + LOG("Depositing %llu QU revenue to WolfPack...\n", (unsigned long long)amount); + makeContractTransaction(nodeIp, nodePort, seed, WP_CONTRACT_INDEX, + WP_PROC_DEPOSIT_REVENUE, amount, 0, nullptr, scheduledTickOffset); +} + +void wpAddClanMember(const char* nodeIp, int nodePort, const char* seed, + const char* memberAddress, uint64_t rank, uint32_t scheduledTickOffset) +{ + WPAddClanMember_input input = {}; + getPublicKeyFromIdentity(memberAddress, input.memberAddress); + input.rank = rank; + + LOG("Adding clan member (rank %llu): %s\n", (unsigned long long)rank, memberAddress); + makeContractTransaction(nodeIp, nodePort, seed, WP_CONTRACT_INDEX, + WP_PROC_ADD_CLAN_MEMBER, 0, sizeof(input), &input, scheduledTickOffset); +} + +void wpRemoveClanMember(const char* nodeIp, int nodePort, const char* seed, + const char* memberAddress, uint32_t scheduledTickOffset) +{ + WPRemoveClanMember_input input = {}; + getPublicKeyFromIdentity(memberAddress, input.memberAddress); + + LOG("Removing clan member: %s\n", memberAddress); + makeContractTransaction(nodeIp, nodePort, seed, WP_CONTRACT_INDEX, + WP_PROC_REMOVE_CLAN_MEMBER, 0, sizeof(input), &input, scheduledTickOffset); +} + +void wpSetClanRank(const char* nodeIp, int nodePort, const char* seed, + const char* memberAddress, uint64_t rank, uint32_t scheduledTickOffset) +{ + WPSetClanRank_input input = {}; + getPublicKeyFromIdentity(memberAddress, input.memberAddress); + input.rank = rank; + + LOG("Setting clan rank to %llu for: %s\n", (unsigned long long)rank, memberAddress); + makeContractTransaction(nodeIp, nodePort, seed, WP_CONTRACT_INDEX, + WP_PROC_SET_CLAN_RANK, 0, sizeof(input), &input, scheduledTickOffset); +} + +void wpSetAdmin(const char* nodeIp, int nodePort, const char* seed, + const char* newAdmin, uint32_t scheduledTickOffset) +{ + WPSetAdmin_input input = {}; + getPublicKeyFromIdentity(newAdmin, input.newAdmin); + + char verifiedId[128] = {}; + getIdentityFromPublicKey(input.newAdmin, verifiedId, false); + LOG("Setting WP admin to: %s\n", verifiedId); + makeContractTransaction(nodeIp, nodePort, seed, WP_CONTRACT_INDEX, + WP_PROC_SET_ADMIN, 0, sizeof(input), &input, scheduledTickOffset); +} + +void wpSetExcludeAddress(const char* nodeIp, int nodePort, const char* seed, + uint64_t slot, const char* address, uint32_t scheduledTickOffset) +{ + WPSetExcludeAddress_input input = {}; + input.slot = slot; + getPublicKeyFromIdentity(address, input.address); + + LOG("Setting exclude slot %llu to: %s\n", (unsigned long long)slot, address); + makeContractTransaction(nodeIp, nodePort, seed, WP_CONTRACT_INDEX, + WP_PROC_SET_EXCLUDE_ADDRESS, 0, sizeof(input), &input, scheduledTickOffset); +} + +// ─── Staking ─────────────────────────────────────────────────── + +void wpStakingInfo(const char* nodeIp, int nodePort, const char* address) +{ + WPGetStakingInfo_input input = {}; + getPublicKeyFromIdentity(address, input.stakerAddress); + + WPGetStakingInfo_output out = {}; + if (runContractFunction(nodeIp, nodePort, WP_CONTRACT_INDEX, + WP_GET_STAKING_INFO, &input, sizeof(input), &out, sizeof(out))) + { + LOG("═══ WolfPack Staking Info ══════════════════════════════\n\n"); + LOG("Address: %s\n", address); + LOG("Is Staker: %s\n", out.isStaker ? "YES" : "NO"); + LOG("Staked Amount: %llu WP\n", (unsigned long long)out.stakedAmount); + LOG("Pending Rewards: %llu WP\n", (unsigned long long)out.pendingRewards); + LOG("Unstake Amount: %llu WP\n", (unsigned long long)out.unstakeAmount); + LOG("Unstake Epoch: %llu\n", (unsigned long long)out.unstakeEpoch); + LOG("Total Staked (all): %llu WP\n", (unsigned long long)out.totalStaked); + LOG("Reward Pool: %llu WP\n", (unsigned long long)out.stakingRewardPool); + } + else + { + LOG("ERROR: Could not query WP GetStakingInfo (fn 5)\n"); + } +} + +void wpStake(const char* nodeIp, int nodePort, const char* seed, + uint64_t numberOfShares, uint32_t scheduledTickOffset) +{ + WPStake_input input = {}; + input.numberOfShares = numberOfShares; + + LOG("Staking %llu WP tokens...\n", (unsigned long long)numberOfShares); + LOG("NOTE: Transfer management rights on QX first (newMgmtIdx: 27)\n"); + makeContractTransaction(nodeIp, nodePort, seed, WP_CONTRACT_INDEX, + WP_PROC_STAKE, 0, sizeof(input), &input, scheduledTickOffset); +} + +void wpRequestUnstake(const char* nodeIp, int nodePort, const char* seed, + uint64_t numberOfShares, uint32_t scheduledTickOffset) +{ + WPRequestUnstake_input input = {}; + input.numberOfShares = numberOfShares; + + LOG("Requesting unstake of %llu WP tokens...\n", (unsigned long long)numberOfShares); + LOG("WARNING: 2-epoch cooldown before FinalizeUnstake is possible\n"); + makeContractTransaction(nodeIp, nodePort, seed, WP_CONTRACT_INDEX, + WP_PROC_REQUEST_UNSTAKE, 0, sizeof(input), &input, scheduledTickOffset); +} + +void wpFinalizeUnstake(const char* nodeIp, int nodePort, const char* seed, + uint32_t scheduledTickOffset) +{ + LOG("Finalizing unstake...\n"); + LOG("NOTE: 100 QU QX fee will be charged\n"); + makeContractTransaction(nodeIp, nodePort, seed, WP_CONTRACT_INDEX, + WP_PROC_FINALIZE_UNSTAKE, 0, 0, nullptr, scheduledTickOffset); +} + +void wpDepositStakingRewards(const char* nodeIp, int nodePort, const char* seed, + uint64_t numberOfShares, uint32_t scheduledTickOffset) +{ + WPDepositStakingRewards_input input = {}; + input.numberOfShares = numberOfShares; + + LOG("Depositing %llu WP tokens into staking reward pool...\n", (unsigned long long)numberOfShares); + makeContractTransaction(nodeIp, nodePort, seed, WP_CONTRACT_INDEX, + WP_PROC_DEPOSIT_STAKING_REWARDS, 0, sizeof(input), &input, scheduledTickOffset); +} + +void wpClaimStakingRewards(const char* nodeIp, int nodePort, const char* seed, + uint32_t scheduledTickOffset) +{ + LOG("Claiming staking rewards...\n"); + LOG("NOTE: 100 QU QX fee will be charged\n"); + makeContractTransaction(nodeIp, nodePort, seed, WP_CONTRACT_INDEX, + WP_PROC_CLAIM_STAKING_REWARDS, 0, 0, nullptr, scheduledTickOffset); +} + + +void wpExcludeAddresses(const char* nodeIp, int nodePort) +{ + LOG("=== WolfPack Exclude Addresses ===\n\n"); + + WPGetExcludeAddresses_output out = {}; + if (runContractFunction(nodeIp, nodePort, WP_CONTRACT_INDEX, + WP_GET_EXCLUDE_ADDRESSES, nullptr, 0, &out, sizeof(out))) + { + printIdentity("Exclude Slot 1: ", out.address1); + printIdentity("Exclude Slot 2: ", out.address2); + } + else + { + LOG("ERROR: Could not query WP GetExcludeAddresses (fn 6)\n"); + } +} + + +void wpDistPreview(const char* nodeIp, int nodePort, uint64_t amount) +{ + LOG("=== WolfPack Distribution Preview for %llu QU ===\n", (unsigned long long)amount); + + WPGetDistributionPreview_input in = {}; + in.amount = amount; + WPGetDistributionPreview_output out = {}; + if (runContractFunction(nodeIp, nodePort, WP_CONTRACT_INDEX, + WP_GET_DISTRIBUTION_PREVIEW, &in, sizeof(in), &out, sizeof(out))) + { + LOG("Holder Share: %llu\n", (unsigned long long)out.holderShare); + LOG("Shareholder Share: %llu\n", (unsigned long long)out.shareholderShare); + LOG("Clan Share: %llu\n", (unsigned long long)out.clanShare); + LOG("Reinvest Share: %llu\n", (unsigned long long)out.reinvestShare); + } + else + { + LOG("ERROR: Could not query WP GetDistributionPreview (fn 7)\n"); + } +} diff --git a/ggwp.h b/ggwp.h new file mode 100644 index 0000000..9bbedd0 --- /dev/null +++ b/ggwp.h @@ -0,0 +1,202 @@ +#pragma once + +#include "structs.h" + +// ─── Contract constants ──────────────────────────────────────── +#define WP_CONTRACT_INDEX 27 + +// Query function numbers +#define WP_GET_STATUS 1 +#define WP_GET_HOLDER_INFO 2 +#define WP_GET_CLAN_MEMBER_INFO 3 +#define WP_GET_SHAREHOLDER_INFO 4 +#define WP_GET_STAKING_INFO 5 +#define WP_GET_EXCLUDE_ADDRESSES 6 +#define WP_GET_DISTRIBUTION_PREVIEW 7 + +// Procedure IDs +#define WP_PROC_DEPOSIT_REVENUE 1 +#define WP_PROC_ADD_CLAN_MEMBER 2 +#define WP_PROC_REMOVE_CLAN_MEMBER 3 +#define WP_PROC_SET_CLAN_RANK 4 +#define WP_PROC_SET_ADMIN 5 +#define WP_PROC_SET_EXCLUDE_ADDRESS 6 +#define WP_PROC_STAKE 7 +#define WP_PROC_REQUEST_UNSTAKE 8 +#define WP_PROC_FINALIZE_UNSTAKE 9 +#define WP_PROC_DEPOSIT_STAKING_REWARDS 10 +#define WP_PROC_CLAIM_STAKING_REWARDS 11 + +// ─── Input/Output structs ────────────────────────────────────── + +// fn 1 – GetStatus +struct WPGetStatus_output +{ + uint64_t holderCount; + uint64_t totalTokensSnapshot; + uint64_t shareholderCount; + uint64_t totalSharesSnapshot; + uint64_t clanMemberCount; + uint64_t clanWeightedTotal; + uint64_t pendingRevenue; + uint64_t reinvestmentFund; + uint64_t totalDistributed; + uint64_t totalDeposited; + uint64_t lastPayoutTick; + uint64_t lastDistributionEpoch; + uint8_t adminAddress[32]; +}; + +// fn 2 – GetHolderInfo +struct WPGetHolderInfo_input +{ + uint8_t holderAddress[32]; +}; +struct WPGetHolderInfo_output +{ + uint64_t tokenBalance; + uint32_t isHolder; +}; + +// fn 4 – GetShareholderInfo +struct WPGetShareholderInfo_input +{ + uint8_t shareholderAddress[32]; +}; +struct WPGetShareholderInfo_output +{ + uint64_t shares; + uint32_t isShareholder; +}; + +// fn 3 – GetClanMemberInfo +struct WPGetClanMemberInfo_input +{ + uint8_t memberAddress[32]; +}; +struct WPGetClanMemberInfo_output +{ + uint64_t rank; + uint32_t isMember; +}; + +// proc 1 – DepositRevenue (no input, amount via invocationReward) + +// proc 2 – AddClanMember +struct WPAddClanMember_input +{ + uint8_t memberAddress[32]; + uint64_t rank; +}; + +// proc 3 – RemoveClanMember +struct WPRemoveClanMember_input +{ + uint8_t memberAddress[32]; +}; + +// proc 4 – SetClanRank +struct WPSetClanRank_input +{ + uint8_t memberAddress[32]; + uint64_t rank; +}; + +// proc 5 – SetAdmin +struct WPSetAdmin_input +{ + uint8_t newAdmin[32]; +}; + +// proc 6 – SetExcludeAddress +struct WPSetExcludeAddress_input +{ + uint64_t slot; + uint8_t address[32]; +}; + +// fn 5 – GetStakingInfo +struct WPGetStakingInfo_input +{ + uint8_t stakerAddress[32]; +}; +struct WPGetStakingInfo_output +{ + uint64_t stakedAmount; + uint64_t pendingRewards; + uint64_t unstakeAmount; + uint64_t unstakeEpoch; + uint64_t totalStaked; + uint64_t stakingRewardPool; + uint32_t isStaker; +}; + +// fn 6 - GetExcludeAddresses +struct WPGetExcludeAddresses_output +{ + uint8_t address1[32]; + uint8_t address2[32]; +}; + +// proc 7 – Stake +struct WPStake_input +{ + uint64_t numberOfShares; +}; + +// proc 8 – RequestUnstake +struct WPRequestUnstake_input +{ + uint64_t numberOfShares; +}; + +// proc 9 – FinalizeUnstake (no input) + +// proc 10 – DepositStakingRewards +struct WPDepositStakingRewards_input +{ + uint64_t numberOfShares; +}; + +// proc 11 – ClaimStakingRewards (no input) + +// ─── Function declarations ───────────────────────────────────── +void wpStatus(const char* nodeIp, int nodePort); +void wpHolderInfo(const char* nodeIp, int nodePort, const char* address); +void wpClanMemberInfo(const char* nodeIp, int nodePort, const char* address); +void wpShareholderInfo(const char* nodeIp, int nodePort, const char* address); +void wpDepositRevenue(const char* nodeIp, int nodePort, const char* seed, + uint64_t amount, uint32_t scheduledTickOffset); +void wpAddClanMember(const char* nodeIp, int nodePort, const char* seed, + const char* memberAddress, uint64_t rank, uint32_t scheduledTickOffset); +void wpRemoveClanMember(const char* nodeIp, int nodePort, const char* seed, + const char* memberAddress, uint32_t scheduledTickOffset); +void wpSetClanRank(const char* nodeIp, int nodePort, const char* seed, + const char* memberAddress, uint64_t rank, uint32_t scheduledTickOffset); +void wpSetAdmin(const char* nodeIp, int nodePort, const char* seed, + const char* newAdmin, uint32_t scheduledTickOffset); +void wpSetExcludeAddress(const char* nodeIp, int nodePort, const char* seed, + uint64_t slot, const char* address, uint32_t scheduledTickOffset); + +// ─── Staking ─────────────────────────────────────────────────── +void wpStakingInfo(const char* nodeIp, int nodePort, const char* address); +void wpStake(const char* nodeIp, int nodePort, const char* seed, + uint64_t numberOfShares, uint32_t scheduledTickOffset); +void wpRequestUnstake(const char* nodeIp, int nodePort, const char* seed, + uint64_t numberOfShares, uint32_t scheduledTickOffset); +void wpFinalizeUnstake(const char* nodeIp, int nodePort, const char* seed, + uint32_t scheduledTickOffset); +void wpDepositStakingRewards(const char* nodeIp, int nodePort, const char* seed, + uint64_t numberOfShares, uint32_t scheduledTickOffset); +void wpClaimStakingRewards(const char* nodeIp, int nodePort, const char* seed, + uint32_t scheduledTickOffset); +struct WPGetDistributionPreview_input { uint64_t amount; }; +struct WPGetDistributionPreview_output { + uint64_t holderShare; + uint64_t shareholderShare; + uint64_t clanShare; + uint64_t reinvestShare; +}; + +void wpDistPreview(const char* nodeIp, int nodePort, uint64_t amount); +void wpExcludeAddresses(const char* nodeIp, int nodePort); diff --git a/global.h b/global.h index c6edaf1..a5cee96 100644 --- a/global.h +++ b/global.h @@ -305,3 +305,9 @@ char* g_escrow_issuer = nullptr; int64_t g_escrow_amount = 0; int64_t g_escrow_proposedOffset = 0; int64_t g_escrow_publicOffset = 0; +// wolfpack +char* g_wp_identity = nullptr; +uint64_t g_wp_amount = 0; +uint64_t g_wp_rank = 0; +uint64_t g_wp_slot = 0; +char* g_wp_address = nullptr; diff --git a/main.cpp b/main.cpp index 0dfb9be..ddba3d2 100644 --- a/main.cpp +++ b/main.cpp @@ -24,6 +24,7 @@ #include "qbond.h" #include "qrwa.h" #include "escrow.h" +#include "ggwp.h" int run(int argc, char* argv[]) { @@ -382,6 +383,90 @@ int run(int argc, char* argv[]) sanityCheckSeed(g_seed); qrwaRevokeAssetMgmt(g_nodeIp, g_nodePort, g_seed, g_qrwa_issuer, g_qrwa_asset_name, g_qrwa_num_shares, g_offsetScheduledTick); break; + // ── WolfPack ── + case WP_STATUS: + sanityCheckNode(g_nodeIp, g_nodePort); + wpStatus(g_nodeIp, g_nodePort); + break; + case WP_EXCLUDE_INFO: + sanityCheckNode(g_nodeIp, g_nodePort); + wpExcludeAddresses(g_nodeIp, g_nodePort); + break; + case WP_DIST_PREVIEW: + sanityCheckNode(g_nodeIp, g_nodePort); + wpDistPreview(g_nodeIp, g_nodePort, g_wp_amount); + break; + case WP_HOLDER_INFO: + sanityCheckNode(g_nodeIp, g_nodePort); + wpHolderInfo(g_nodeIp, g_nodePort, g_wp_identity); + break; + case WP_CLAN_MEMBER_INFO: + sanityCheckNode(g_nodeIp, g_nodePort); + wpClanMemberInfo(g_nodeIp, g_nodePort, g_wp_identity); + break; + case WP_SHAREHOLDER_INFO: + sanityCheckNode(g_nodeIp, g_nodePort); + wpShareholderInfo(g_nodeIp, g_nodePort, g_wp_identity); + break; + case WP_DEPOSIT_REVENUE: + sanityCheckNode(g_nodeIp, g_nodePort); + sanityCheckSeed(g_seed); + wpDepositRevenue(g_nodeIp, g_nodePort, g_seed, g_wp_amount, g_offsetScheduledTick); + break; + case WP_ADD_CLAN_MEMBER: + sanityCheckNode(g_nodeIp, g_nodePort); + sanityCheckSeed(g_seed); + wpAddClanMember(g_nodeIp, g_nodePort, g_seed, g_wp_address, g_wp_rank, g_offsetScheduledTick); + break; + case WP_REMOVE_CLAN_MEMBER: + sanityCheckNode(g_nodeIp, g_nodePort); + sanityCheckSeed(g_seed); + wpRemoveClanMember(g_nodeIp, g_nodePort, g_seed, g_wp_address, g_offsetScheduledTick); + break; + case WP_SET_CLAN_RANK: + sanityCheckNode(g_nodeIp, g_nodePort); + sanityCheckSeed(g_seed); + wpSetClanRank(g_nodeIp, g_nodePort, g_seed, g_wp_address, g_wp_rank, g_offsetScheduledTick); + break; + case WP_SET_ADMIN: + sanityCheckNode(g_nodeIp, g_nodePort); + sanityCheckSeed(g_seed); + wpSetAdmin(g_nodeIp, g_nodePort, g_seed, g_wp_address, g_offsetScheduledTick); + break; + case WP_SET_EXCLUDE_ADDRESS: + sanityCheckNode(g_nodeIp, g_nodePort); + sanityCheckSeed(g_seed); + wpSetExcludeAddress(g_nodeIp, g_nodePort, g_seed, g_wp_slot, g_wp_address, g_offsetScheduledTick); + break; + case WP_STAKING_INFO: + sanityCheckNode(g_nodeIp, g_nodePort); + wpStakingInfo(g_nodeIp, g_nodePort, g_wp_identity); + break; + case WP_STAKE: + sanityCheckNode(g_nodeIp, g_nodePort); + sanityCheckSeed(g_seed); + wpStake(g_nodeIp, g_nodePort, g_seed, g_wp_amount, g_offsetScheduledTick); + break; + case WP_REQUEST_UNSTAKE: + sanityCheckNode(g_nodeIp, g_nodePort); + sanityCheckSeed(g_seed); + wpRequestUnstake(g_nodeIp, g_nodePort, g_seed, g_wp_amount, g_offsetScheduledTick); + break; + case WP_FINALIZE_UNSTAKE: + sanityCheckNode(g_nodeIp, g_nodePort); + sanityCheckSeed(g_seed); + wpFinalizeUnstake(g_nodeIp, g_nodePort, g_seed, g_offsetScheduledTick); + break; + case WP_DEPOSIT_STAKING_REWARDS: + sanityCheckNode(g_nodeIp, g_nodePort); + sanityCheckSeed(g_seed); + wpDepositStakingRewards(g_nodeIp, g_nodePort, g_seed, g_wp_amount, g_offsetScheduledTick); + break; + case WP_CLAIM_STAKING_REWARDS: + sanityCheckNode(g_nodeIp, g_nodePort); + sanityCheckSeed(g_seed); + wpClaimStakingRewards(g_nodeIp, g_nodePort, g_seed, g_offsetScheduledTick); + break; case TOOGLE_MAIN_AUX: sanityCheckNode(g_nodeIp, g_nodePort); sanityCheckSeed(g_seed); diff --git a/structs.h b/structs.h index 8520594..2825f97 100644 --- a/structs.h +++ b/structs.h @@ -230,6 +230,24 @@ enum COMMAND ESCROW_CANCEL_DEAL_CMD, ESCROW_TRANSFER_RIGHTS_CMD, ESCROW_GET_FREE_ASSET_CMD, + WP_STATUS, + WP_HOLDER_INFO, + WP_CLAN_MEMBER_INFO, + WP_SHAREHOLDER_INFO, + WP_STAKING_INFO, + WP_DEPOSIT_REVENUE, + WP_ADD_CLAN_MEMBER, + WP_REMOVE_CLAN_MEMBER, + WP_SET_CLAN_RANK, + WP_SET_ADMIN, + WP_SET_EXCLUDE_ADDRESS, + WP_STAKE, + WP_REQUEST_UNSTAKE, + WP_FINALIZE_UNSTAKE, + WP_DEPOSIT_STAKING_REWARDS, + WP_CLAIM_STAKING_REWARDS, + WP_EXCLUDE_INFO, + WP_DIST_PREVIEW, TOTAL_COMMAND // DO NOT CHANGE THIS };