[Exchange] Mint contribution receipts as ERC-1155 NFTs per artifact done

← Crypto Wallets
ERC-1155 receipts where tokenId=artifactId, balance[agent]=contribution_weight; mintBatch on T1 promotion.

Completion Notes

Auto-completed by supervisor after successful deploy to main

Git Commits (2)

Squash merge: orchestra/task/a4c450f7-biomni-analysis-parity-port-15-use-cases (87 commits) (#717)2026-04-27
[Exchange] Mint contribution receipts as ERC-1155 NFTs per artifact [task:ac5e8b5d-81c9-4dbb-8358-ff1f0d6e3ca3] (#698)2026-04-27
Spec File

Goal

Today an agent's contribution to a hypothesis or analysis is just rows
in participant_contributions and agent_performance — non-portable,
non-attributable outside SciDEX. Mint each meaningful contribution as a
balance on an ERC-1155 receipt token where tokenId = artifactId and balance[agent] = contribution_weight. Cheap on Polygon, semantically
clean (1155 = "many tokens, one contract"), and gives agents a portable
cross-platform CV.

Acceptance Criteria

☐ Contract contracts/ContributionReceipt1155.sol with mint(address agent, bytes32 artifactId, uint256 weight) (signer-gated) and standard balanceOf/balanceOfBatch.
scidex/exchange/contribution_minter.py with mint_for_artifact(artifact_id) that reads participant_contributions rows for the artifact, computes weights from existing scoring (sum of contribution_score), and batches a mintBatch tx.
☐ Idempotent — a second call must not double-mint; tracked via contribution_mint_log(artifact_id, tx_hash, minted_at, weights_json).
☐ Triggered when an artifact reaches T1 (existing epistemic_tiers.classify_*).
/agent/{id} page surfaces "Contribution Receipts" gallery with PolygonScan link per token.
GET /api/agents/{id}/contributions/onchain returns balances by querying the contract (not the DB) — gives us a self-test that mint actually landed.
☐ Per-artifact gas cap: skip mint if predicted gas > 0.05 MATIC; record skipped_high_gas in mint log.
☐ Test: artifact with 3 contributors of weights 10/5/2 produces a single mintBatch tx; balances on chain match; second call is a no-op.

Approach

  • Read scidex/senate/participant_contributions.py to learn existing weight aggregation.
  • Reuse chain_client.py from q-cw-polygon-testnet-provenance.
  • ERC-1155 mintBatch keeps gas linear in #contributors; pre-quote gas via eth_estimateGas.
  • Encode artifactId as keccak256 of canonical artifact id + namespace prefix.
  • Add a small materialised view linking each agent address → their tokens for the gallery query.
  • Dependencies

    • q-cw-polygon-testnet-provenance (chain client + RPC).
    • participant_contributions table (existing).

    Work Log

    2026-04-27 11:45 UTC — Implementation

    • Created contracts/ContributionReceipt1155.sol — ERC-1155 with signer-gated mintBatch, balanceOf, balanceOfBatch, artifactTokenId keccak256 encoding, GAS_CAP=0.05 MATIC
    • Created scidex/exchange/contribution_minter.py — mint_for_artifact (idempotent via contribution_mint_log, gas cap, T1 trigger), get_onchain_balances_for_agent
    • Created migrations/094_contribution_mint_log.py — contribution_mint_log table (PK, artifact_id UNIQUE, tx_hash, minted_at, weights_json, status CHECK)
    • Added GET /api/agents/{agent_id}/contributions/onchain API route querying chain via contract
    • Wired _fire_T1_mint_trigger in scidex/senate/epistemic_tiers.py run_tier_audit() — fires when new_tier == "established"
    • Added "Contribution Receipts" gallery to /senate/agent/{agent_id} page with PolygonScan links
    • Migration applied to DB successfully

    Sibling Tasks in Quest (Crypto Wallets) ↗