feat: course content hash, per-address minting, claim history, pause events - #363
Merged
DeFiVC merged 4 commits intoAug 29, 2026
Conversation
Add a content_hash field to Course so clients can verify that off-chain course content matches what the course was published with. - Course gains `content_hash: Symbol`, defaulting to the `none` sentinel meaning "unset", which keeps verification optional. - `set_course_content_hash` (admin only) sets or updates the hash and emits a `content_hash_set` event. Passing `none` unsets it again. - `get_course_content_hash` exposes it for querying. - `enroll_checked` enrolls with optional verification. `enroll` keeps its existing signature and never verifies, so the ~40 existing call sites and the cross-contract calls from credential-nft and learn-token are unaffected. Verification only runs when the course has a hash set AND the caller supplies one, so it is opt-in on both sides. Also fixes a pre-existing build break: tests/unit/progress_tests.rs constructed Course without the `archived` field added in ChainLearnOfficial#210, so the progress_tests target failed to compile on main. Closes ChainLearnOfficial#235
Add `total_minted_to(address)` returning the cumulative amount ever minted to an address, so analytics can break minting down per address instead of only seeing the global total supply. - New `TokenDataKey::TotalMintedTo(Address)` persistent entry, with `get_total_minted_to` / `add_total_minted_to` storage helpers that extend TTL on write like the other per-address entries. - Updated on both minting paths: `mint` and `claim_reward`. Reward claims mint tokens too, so omitting them would undercount. - The counter is monotonic: transfers and burns leave it untouched, so it reflects total minting rather than current holdings. Reads are a single storage get and writes piggyback on paths that already touch storage, so there is no added cost on non-minting calls. Also fixes a pre-existing build break: tests/unit/progress_tests.rs constructed Course without the `archived` field added in ChainLearnOfficial#210, so the progress_tests target failed to compile on main. Closes ChainLearnOfficial#236
Add `get_claim_history(learner)` returning every reward the learner has claimed, so users can see their reward history rather than only their current balance. - New `ClaimRecord` type holding course_id, quiz_id, amount, and the ledger timestamp of the claim. - New `TokenDataKey::ClaimHistory(Address)` persistent entry, appended to by `claim_reward` and read back in claim order. - History is immutable in practice: `claim_reward` rejects double-claims before recording, so entries are only ever appended, never modified or removed. A rejected duplicate claim leaves the history untouched. Returns the full list with no pagination, per the issue. Also fixes a pre-existing build break: tests/unit/progress_tests.rs constructed Course without the `archived` field added in ChainLearnOfficial#210, so the progress_tests target failed to compile on main. Closes ChainLearnOfficial#237
Add `paused(admin, timestamp)` and `unpaused(admin, timestamp)` events so pause activity can be audited and monitored. The issue scoped this to events only, but the contract had no pause mechanism at all -- grep for pause/halt across contracts/ and packages/ returns nothing. Events with no operation to emit them would be dead code and could not satisfy "events are emitted", so this adds the minimal pause surface the events attach to: - `pause` / `unpause`, admin-only, rejecting redundant transitions, each emitting its event with the acting admin and ledger timestamp. - `is_paused` for querying the current state. - A `Paused` persistent flag, defaulting to unpaused. Both events follow the existing Symbol::new topic convention used by the other events here, so indexers can match on them consistently. The flag is enforced on the state-changing entrypoints -- transfer, transfer_from, burn, burn_from, mint, and claim_reward -- since a pause flag that blocked nothing would misrepresent the contract as pausable. Read-only calls stay available while paused. Also fixes a pre-existing build break: tests/unit/progress_tests.rs constructed Course without the `archived` field added in ChainLearnOfficial#210, so the progress_tests target failed to compile on main. Closes ChainLearnOfficial#238
Johnalex-hub
force-pushed
the
feat/235-238-contract-enhancements
branch
from
August 29, 2026 23:33
08e36ac to
13a9b0e
Compare
|
@Johnalex-hub Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
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.
Bundles four contract enhancements. Detail is in the individual commit messages.
Closes #235
Closes #236
Closes #237
Closes #238
Changes
content_hashonCourse, adminset_course_content_hash,get_course_content_hash, andenroll_checkedfor opt-in verification.total_minted_to(address), updated on both mint paths (mintandclaim_reward).get_claim_history(learner)returning course, quiz, amount, and timestamp per claim.paused/unpausedevents, plus the minimalpause/unpause/is_pausedsurface they attach to.Notes for review
enrollsignature is unchanged. . Add course content hash verification #235 says "verify hash in enrollment", but changingenrollwould break ~40 call sites plus cross-contract calls from credential-nft and learn-token.enroll_checkedtakes the optional hash instead, which also matches the "hash verification is optional" criterion.contracts/orpackages/. Events with no operation to emit them would be dead code, so this adds the adminpause/unpausesurface and enforces the flag on the six state-changing entrypoints. Read-only calls stay available while paused. Happy to trim this back to event definitions alone if you'd prefer.tests/unit/progress_tests.rsconstructedCoursewithout thearchivedfield added in Add course archiving #210, so theprogress_teststarget did not compile onmain.mainis notcargo fmtclean, so formatting was deliberately left untouched on lines unrelated to these changes to keep the diff scoped.Testing
cargo test --workspace— 208 pass, 0 fail. learn-token 35 → 52 tests, progress-tracker 24 → 32.