Feat/token minter reward guards - #20
Merged
Merged
Conversation
Separate minting authority from the admin role. The admin can delegate minting to a designated minter address (the reward engine) via set_minter(). The mint() function now requires minter authorization instead of admin authorization. This aligns with the documented architecture where only the reward engine should mint new tokens. Changes: - storage: add write_minter/read_minter for the Minter data key - initialize: sets minter = admin by default - mint: gated by minter.require_auth() instead of admin - minter(): view function to query current minter - set_minter(): admin-gated function to delegate minting rights - tests: minter authorization, initial minter is admin, set_minter, set_minter_unauthorized
Add input validation to approve() to prevent setting nonsensical allowances: - Reject negative amounts (zero is valid for revoking an allowance) - Reject expirations that are not strictly in the future These guards prevent accidental misuse of the allowance system and complement the existing input validation on mint, transfer, and burn.
Before approving a proof or resolving a dispute in the reward engine, cross-contract query the task-registry to validate: - The task exists and is in Active status (not completed, expired, or cancelled) - The task has not passed its expiration timestamp - The payout reward_amount does not exceed the task's declared reward_amount This prevents the engine from paying out on expired, cancelled, or already-completed tasks, and prevents overpaying beyond the task's budget. A new internal helper require_active_task() encapsulates the registry query and validation logic.
When resolve_dispute is called with approve=false, the event now correctly emits reward_amount=0 instead of the caller-supplied value. This prevents misleading on-chain events suggesting a payout occurred when the dispute was rejected. Also add guard tests for the new task-status and budget checks: - Approve over task budget panics with 'reward exceeds task budget' - Approve on expired task panics with 'task has expired' - Approve on cancelled task panics with 'task is not active' - Dispute resolve approve over budget panics with 'reward exceeds task budget'
Add an on-chain counter that accumulates every reward payout made by the engine (both via approve_proof and dispute resolution). This enables transparent reporting and auditing without off-chain indexers: - TotalPaid storage key with overflow-checked accumulation - add_total_paid() increments after each successful mint - total_paid() public view function returns cumulative payout amount - Rejected proofs and rejected disputes do not increment the counter
Add set_token() and set_registry() functions to allow the admin to update the token and registry contract addresses after deployment. This mirrors the existing set_oracle() pattern and provides operational flexibility for contract upgrades or migration scenarios. Both functions require admin authorization and follow the established access control pattern used throughout the reward engine.
Add admin_cancel_task() which allows the admin to cancel any active task regardless of creator. This provides governance-level control for removing tasks that violate platform policies, are reported as fraudulent, or need to be taken down for other reasons. The existing cancel_task() remains creator-only. The new function: - Requires admin authorization - Only operates on Active tasks - Emits the same TaskCancelledEvent for audit trail - Tests cover admin success, non-admin rejection, and completed task rejection
Add input validation to create_task() that panics if the task_type string is empty. This prevents creating tasks without a meaningful type classification, which would break downstream filtering, event analysis, and off-chain indexing.
Convert the workspace root from a virtual workspace to a root package with dev-dependencies on all three contracts, enabling the previously placeholder tests/reward_integration_test.rs to run as a real integration test suite. New cross-contract integration tests cover: - Full payout lifecycle: multi-task, multi-user, balance verification - Dispute flow: reject, dispute, resolve, payout verification - Multi-user max completions with automatic task completion - Reward cap enforcement across contracts (engine rejects over-budget) - Minter role delegation from admin to reward engine - Admin cancel prevents subsequent payout approval Also creates src/lib.rs with #![no_std] for the root package.
- Add Swatinem/rust-cache@v2 for faster CI runs - Use --locked on cargo build for reproducible builds - Run cargo test --workspace explicitly (avoids virtual workspace ambiguity) - Align clippy flags with Makefile: --all-targets --all-features -- -D warnings
- verify-deploy.sh: use NETWORK env with testnet default, require all contract ID env vars with clear error messages - integration-test.sh: use NETWORK env, require env vars, fix location_hash to use sha256sum instead of broken xxd invocation - fund-accounts.sh: require address argument explicitly
Update README to reflect all contract improvements: - eco-token: minter role for minting authorization, approve validation - task-registry: admin_cancel_task for governance, empty type rejection - reward-engine: task status/cap enforcement, total_paid tracking, admin setters for token/registry, post-deployment reconfiguration - Security section updated to reflect minter separation and payout guards
Admin can pause all proof submission, approval, dispute, and resolution operations instantly to respond to exploits or incidents. Paused state is checked at entry points via require_not_paused guard. Only admin can pause/unpause. Added 6 unit tests and 1 integration test verifying the full pause/unpause lifecycle.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR hardens the EcoTask Soroban smart contracts with token access control, cross-contract reward validation, admin governance tools, integration testing, and production safety mechanisms.
What Changed
Token Security (
eco-token)set_minter(), which can be transferred at any time.Reward Engine Correctness (
reward-engine)approve_proofandresolve_disputenow verify the task isActiveand not expired before minting, preventing rewards for stale or cancelled tasks.DisputeResolvedEventnow correctly emitsreward_amount: 0when a dispute is rejected.total_paidview for on-chain transparency and auditing.set_token()andset_registry()let the admin swap dependencies without redeploying.pause()/unpause()to instantly halt all proof operations during an exploit or incident. Only admin can toggle.Task Registry Governance (
task-registry)admin_cancel_task()— admin can cancel any active task for governance reasons, rejecting completions and payouts on that task.task_typerejection —create_tasknow panics iftask_typeis empty, enforcing data quality.Testing
CI & Scripts
--lockedbuilds, aligned clippy flags (--all-targets --all-features -- -D warnings).NETWORKenv var with validation; verification script checks all required variables before proceeding.