From b2f325b26307809e2c2923dcf869e0e435e05faa Mon Sep 17 00:00:00 2001 From: Lane Rettig Date: Sat, 3 Jan 2026 13:11:42 +0800 Subject: [PATCH 1/2] Create new prod task --- .../4-near-rewards-merkle-verification.md | 4 +- tasks/production/5-update-rewards-contract.md | 207 ++++++++++++++++++ 2 files changed, 209 insertions(+), 2 deletions(-) create mode 100644 tasks/production/5-update-rewards-contract.md diff --git a/tasks/production/4-near-rewards-merkle-verification.md b/tasks/production/4-near-rewards-merkle-verification.md index c4b9068..a452c14 100644 --- a/tasks/production/4-near-rewards-merkle-verification.md +++ b/tasks/production/4-near-rewards-merkle-verification.md @@ -1,4 +1,4 @@ -# Task 6: NEAR Rewards Merkle Verification +# Task 4: NEAR Rewards Merkle Verification **Environment:** `PRODUCTION` @@ -172,7 +172,7 @@ near contract call-function as-read-only $DAO_ACCOUNT_ID get_policy \ ### 3.1 Set Environment Variables ```bash -export CLAIMS_ACCOUNT_ID="[TBD - account created by NF]" +export CLAIMS_ACCOUNT_ID="rewards.hos-dao.near" export DAO_ACCOUNT_ID="rewards-claims2.sputnik-dao.near" export MIN_STORAGE_DEPOSIT="100000000000000000000000" # 0.1 NEAR ``` diff --git a/tasks/production/5-update-rewards-contract.md b/tasks/production/5-update-rewards-contract.md new file mode 100644 index 0000000..54b2f72 --- /dev/null +++ b/tasks/production/5-update-rewards-contract.md @@ -0,0 +1,207 @@ +# Task 5: Update Rewards Contract + +**Environment:** `PRODUCTION` + +**Created by:** `lane.near` + +## Background + +The rewards merkle claim contract was previously deployed to `rewards.hos-dao.near`. This task re-deploys it to `rewards.dao` using the new MPC-derived key feature of the `near` CLI, and transfers remaining funds to the new contract. + +### Part 1. Building Smart Contracts + +### 1.1 Clone and Build + +```bash +git clone https://github.com/voteagora/near-merkle-claim +cd near-merkle-claim +git checkout c7587d357be507744c1e961d42f6fdc56e8803aa +cargo near build +``` + +### 1.2 Verify the Build + +```bash +export CONTRACT_HASH=$(cat target/near/near_merkle_claim.wasm | sha256sum | awk '{ print $1 }' | xxd -r -p | base58) +echo $CONTRACT_HASH +# Expected: FMgQ6iPcerbU6whoDpYrj9LbMRBEnPV3brvgmHWCMqMA + +ls -l target/near/near_merkle_claim.wasm +# Expected size: 159744 bytes +``` + +**Verification Checklist:** + +- [ ] Contract hash matches: `FMgQ6iPcerbU6whoDpYrj9LbMRBEnPV3brvgmHWCMqMA` +- [ ] Contract size is 159744 bytes + +--- + +## Part 2: Verify the Owner DAO + +The owner DAO was deployed in the previous task. In this task we just verify the deployment. + +### 2.1 Verify the DAO Deployment + +```bash +export DAO_NAME="rewards-claims2" +export DAO_ACCOUNT_ID="$DAO_NAME.sputnik-dao.near" + +near contract call-function as-read-only $DAO_ACCOUNT_ID get_policy \ + json-args '{}' \ + network-config mainnet now +``` + +**Verification Checklist:** + +- [ ] DAO created at `rewards-claims2.sputnik-dao.near` +- [ ] SecurityCouncil role has all 6 members +- [ ] CampaignOperator role has `gauntlet-hos.near` +- [ ] `call` vote policy threshold is `1` +- [ ] Default vote policy threshold is `2` + +--- + +## Part 3: Add Derived Public Key + +```bash +near account add-key dao grant-full-access use-mpc-contract hos-root.sputnik-dao.near ed25519 derivation-path dao network-config mainnet +``` + +--- + +## Part 4: Deploy the Merkle Claim Contract + +### 4.1 Set Environment Variables + +```bash +export CLAIMS_ACCOUNT_ID="rewards.dao" +export DAO_ACCOUNT_ID="rewards-claims2.sputnik-dao.near" +export MIN_STORAGE_DEPOSIT="100000000000000000000000" # 0.1 NEAR +``` + +### 4.2 Create the Account + +```bash +near account create-account fund-myself $CLAIMS_ACCOUNT_ID '0.1 NEAR' autogenerate-new-keypair save-to-keychain sign-as dao network-config mainnet sign-with-mpc hos-root.sputnik-dao.near ed25519 derivation-path dao prepaid-gas '15.0 Tgas' attached-deposit '1 yoctoNEAR' submit-mpc-as-dao-proposal $SIGNER_ACCOUNT_ID 'Creating reward.dao account' prepaid-gas '10.0 Tgas' attached-deposit '1 NEAR' +``` + +### 4.3 Deploy and Initialize + +```bash +near contract deploy $CLAIMS_ACCOUNT_ID \ + use-file target/near/near_merkle_claim.wasm \ + with-init-call new json-args '{ + "config": { + "owner_account_id": "'"$DAO_ACCOUNT_ID"'", + "min_storage_deposit": "'"$MIN_STORAGE_DEPOSIT"'" + } + }' \ + prepaid-gas '10.0 Tgas' \ + attached-deposit '1 NEAR' \ + network-config mainnet sign-with-keychain send +``` + +### 4.4 Delete Access Keys (Critical!) + +This makes the contract immutable - only the owner DAO can upgrade it. + +```bash +# List current keys +near account list-keys $CLAIMS_ACCOUNT_ID network-config mainnet now + +# Delete each full access key (repeat for each key shown) +near account delete-keys $CLAIMS_ACCOUNT_ID public-keys 'ed25519:...' \ + network-config mainnet sign-with-keychain send + +# Verify no keys remain +near account list-keys $CLAIMS_ACCOUNT_ID network-config mainnet now +``` + +### 4.5 Verify Deployment + +```bash +near contract call-function as-read-only $CLAIMS_ACCOUNT_ID get_config \ + json-args '{}' \ + network-config mainnet now +``` + +Expected output: + +```json +{ + "owner_account_id": "rewards-claims2.sputnik-dao.near", + "min_storage_deposit": "100000000000000000000000" +} +``` + +**Verification Checklist:** + +- [ ] Contract deployed to correct account +- [ ] Owner is the DAO (`rewards-claims2.sputnik-dao.near`) +- [ ] All access keys deleted +- [ ] `min_storage_deposit` is correct + +### 4.6 Fund the Contract + +Transfer NEAR to the claims contract for reward distribution: + +```bash +near tokens $SIGNER_ACCOUNT_ID send-near $CLAIMS_ACCOUNT_ID '[AMOUNT] NEAR' \ + network-config mainnet sign-with-keychain send +``` + +--- + +## Part 5: Campaign Operations + +As in the [previous task](4-near-rewards-merkle-verification.md), this part remains unchanged. + +--- + +## Part 6: Security Council Verification & Approval + +As in the [previous task](4-near-rewards-merkle-verification.md), this part remains unchanged. + +--- + +## Part 7: User Claims + +As in the [previous task](4-near-rewards-merkle-verification.md), this part remains unchanged. + +--- + +## Deployment Checklist Summary + +### Initial Deployment + +- [ ] Merkle claim contract built and hash verified +- [ ] Owner DAO created with correct policy +- [ ] Derived pubkey added to security council DAO +- [ ] Merkle claim contract deployed with DAO as owner +- [ ] All access keys deleted from claims contract +- [ ] Claims contract funded with NEAR + +### Per-Campaign + +As before. + +--- + +## Contract Addresses (PRODUCTION) + +| Contract | Account ID | Environment | +|----------|------------|-------------| +| Owner DAO | `rewards-claims2.sputnik-dao.near` | PRODUCTION | +| Merkle Claim | `rewards.dao` | PRODUCTION | +| veNEAR | `venear.dao` | PRODUCTION | + +--- + +## Transaction Links (PRODUCTION) + +- Add derived public key: https://nearblocks.io/txns/21u1dAbCx3GqVmu5PxexMheSgz2qwc71J7cxfYpPZiqR +- DAO creation: https://nearblocks.io/txns/EqX1nag1WDh7Whb3Ne32xQsGr68mmrYZVctt8eXGpGcu +- Claims contract deployment: https://nearblocks.io/txns/Vs2xJMdzMe5rCmL4hSTCEQLhFPbVgzzzaGqDejgfoiJ +- Key deletion: https://nearblocks.io/txns/EcL7BjbrnBeybww5LubNy6zJiKPWi47m83iVQFGFuJvS + From eff83c8cd3764608950657686a1e17e6ba06eb98 Mon Sep 17 00:00:00 2001 From: Lane Rettig Date: Sat, 3 Jan 2026 07:57:03 +0000 Subject: [PATCH 2/2] Flesh out new task Add full steps to verify campaign status, transfer funds, etc. --- .../4-near-rewards-merkle-verification.md | 17 +- tasks/production/5-update-rewards-contract.md | 184 +++++++++++++++++- 2 files changed, 188 insertions(+), 13 deletions(-) diff --git a/tasks/production/4-near-rewards-merkle-verification.md b/tasks/production/4-near-rewards-merkle-verification.md index a452c14..5a3b843 100644 --- a/tasks/production/4-near-rewards-merkle-verification.md +++ b/tasks/production/4-near-rewards-merkle-verification.md @@ -177,7 +177,16 @@ export DAO_ACCOUNT_ID="rewards-claims2.sputnik-dao.near" export MIN_STORAGE_DEPOSIT="100000000000000000000000" # 0.1 NEAR ``` -### 3.2 Deploy and Initialize +### 3.2 Create the Account + +Note: this step requires adding the `hos-dao.near` key to the local keychain first. + +```bash +near account create-account fund-myself $CLAIMS_ACCOUNT_ID '3 NEAR' autogenerate-new-keypair save-to-keychain sign-as hos-dao.near network-config mainnet sign-with-keychain send + +``` + +### 3.3 Deploy and Initialize ```bash near contract deploy $CLAIMS_ACCOUNT_ID \ @@ -193,7 +202,7 @@ near contract deploy $CLAIMS_ACCOUNT_ID \ network-config mainnet sign-with-keychain send ``` -### 3.3 Delete Access Keys (Critical!) +### 3.4 Delete Access Keys (Critical!) This makes the contract immutable - only the owner DAO can upgrade it. @@ -209,7 +218,7 @@ near account delete-keys $CLAIMS_ACCOUNT_ID public-keys 'ed25519:...' \ near account list-keys $CLAIMS_ACCOUNT_ID network-config mainnet now ``` -### 3.4 Verify Deployment +### 3.5 Verify Deployment ```bash near contract call-function as-read-only $CLAIMS_ACCOUNT_ID get_config \ @@ -233,7 +242,7 @@ Expected output: - [ ] All access keys deleted - [ ] `min_storage_deposit` is correct -### 3.5 Fund the Contract +### 3.6 Fund the Contract Transfer NEAR to the claims contract for reward distribution: diff --git a/tasks/production/5-update-rewards-contract.md b/tasks/production/5-update-rewards-contract.md index 54b2f72..7d0451a 100644 --- a/tasks/production/5-update-rewards-contract.md +++ b/tasks/production/5-update-rewards-contract.md @@ -83,7 +83,7 @@ export MIN_STORAGE_DEPOSIT="100000000000000000000000" # 0.1 NEAR ### 4.2 Create the Account ```bash -near account create-account fund-myself $CLAIMS_ACCOUNT_ID '0.1 NEAR' autogenerate-new-keypair save-to-keychain sign-as dao network-config mainnet sign-with-mpc hos-root.sputnik-dao.near ed25519 derivation-path dao prepaid-gas '15.0 Tgas' attached-deposit '1 yoctoNEAR' submit-mpc-as-dao-proposal $SIGNER_ACCOUNT_ID 'Creating reward.dao account' prepaid-gas '10.0 Tgas' attached-deposit '1 NEAR' +near account create-account fund-myself $CLAIMS_ACCOUNT_ID '0.1 NEAR' autogenerate-new-keypair save-to-keychain sign-as dao network-config mainnet sign-with-mpc hos-root.sputnik-dao.near ed25519 derivation-path dao prepaid-gas '15.0 Tgas' attached-deposit '1 yoctoNEAR' submit-mpc-as-dao-proposal $SIGNER_ACCOUNT_ID 'Creating '"$CLAIMS_ACCOUNT_ID"' account' prepaid-gas '10.0 Tgas' attached-deposit '1 NEAR' ``` ### 4.3 Deploy and Initialize @@ -142,30 +142,195 @@ Expected output: - [ ] All access keys deleted - [ ] `min_storage_deposit` is correct -### 4.6 Fund the Contract +--- + +## Part 5: Withdraw Funds from Old Contract + +> **WARNING:** Do NOT proceed if there is an active campaign with unclaimed rewards. Users must be able to claim their rewards before withdrawing funds. + +### 5.1 Check for Active Campaigns + +```bash +export OLD_CLAIMS_ACCOUNT_ID="rewards.hos-dao.near" + +# Get the last campaign ID +near contract call-function as-read-only $OLD_CLAIMS_ACCOUNT_ID get_last_campaign_id \ + json-args '{}' \ + network-config mainnet now + +# Check campaign details (replace CAMPAIGN_ID with the result above) +near contract call-function as-read-only $OLD_CLAIMS_ACCOUNT_ID get_campaign \ + json-args '{"campaign_id": CAMPAIGN_ID}' \ + network-config mainnet now +``` -Transfer NEAR to the claims contract for reward distribution: +The `claim_end` field is a UNIX timestamp in **nanoseconds**. To check if the campaign has ended: ```bash -near tokens $SIGNER_ACCOUNT_ID send-near $CLAIMS_ACCOUNT_ID '[AMOUNT] NEAR' \ +# Set the claim_end value from the campaign (in nanoseconds) +export CLAIM_END_NS= + +# Convert to seconds and compare with current time +export CLAIM_END_SEC=$((CLAIM_END_NS / 1000000000)) +echo "Current time: $(date +%s) ($(date))" +echo "Claim end: $CLAIM_END_SEC ($(date -d @$CLAIM_END_SEC))" + +# Check if campaign has ended +if [ $(date +%s) -gt $CLAIM_END_SEC ]; then + echo "✅ Campaign has ended - safe to proceed" +else + echo "❌ Campaign is still active - DO NOT proceed" +fi +``` + +If the campaign is still active, **STOP** and wait for it to end. + +### 5.2 Verify Owner and Check Balance + +```bash +# Check the owner of the old contract +near contract call-function as-read-only $OLD_CLAIMS_ACCOUNT_ID get_config \ + json-args '{}' \ + network-config mainnet now + +# The old contract is owned by the NEW DAO (ownership was transferred) +# Verify owner_account_id matches $DAO_ACCOUNT_ID from Part 4 + +# Check remaining balance +near account view-account-summary $OLD_CLAIMS_ACCOUNT_ID network-config mainnet now +``` + +### 5.3 Create Proposal to Withdraw Funds + +```bash +near contract call-function as-transaction $DAO_ACCOUNT_ID add_proposal \ + json-args '{ + "proposal": { + "description": "Withdraw remaining funds from old rewards contract to DAO", + "kind": { + "FunctionCall": { + "receiver_id": "'"$OLD_CLAIMS_ACCOUNT_ID"'", + "actions": [{ + "method_name": "withdraw", + "args": "", + "deposit": "0", + "gas": "50000000000000" + }] + } + } + } + }' \ + prepaid-gas '30.0 Tgas' \ + attached-deposit '0.1 NEAR' \ + sign-as $SIGNER_ACCOUNT_ID \ network-config mainnet sign-with-keychain send ``` +### 5.4 Check and Approve Withdraw Proposal + +```bash +# Record the proposal ID from the previous step +export WITHDRAW_PROPOSAL_ID= + +# Verify the proposal contents +near contract call-function as-read-only $DAO_ACCOUNT_ID get_proposal \ + json-args '{"id": '"$WITHDRAW_PROPOSAL_ID"'}' \ + network-config mainnet now +``` + +**Verify the proposal contains:** +- `receiver_id`: `rewards.hos-dao.near` (the old claims contract) +- `method_name`: `withdraw` +- `deposit`: `0` + +```bash +# Approve the proposal (repeat for each required signer) +near contract call-function as-transaction $DAO_ACCOUNT_ID act_proposal \ + json-args '{"id": '"$WITHDRAW_PROPOSAL_ID"', "action": "VoteApprove"}' \ + prepaid-gas '150.0 Tgas' \ + attached-deposit '0 NEAR' \ + sign-as $SIGNER_ACCOUNT_ID \ + network-config mainnet sign-with-keychain send +``` + +### 5.5 Create Proposal to Transfer Funds to New Contract + +After the withdraw proposal executes, the funds are now in the DAO. Create a proposal to transfer them to the new claims contract: + +```bash +# Check the DAO balance to determine transfer amount +near account view-account-summary $DAO_ACCOUNT_ID network-config mainnet now + +# Set the amount to transfer (in yoctoNEAR, e.g., "1000000000000000000000000" = 1 NEAR) +export TRANSFER_AMOUNT="" + +near contract call-function as-transaction $DAO_ACCOUNT_ID add_proposal \ + json-args '{ + "proposal": { + "description": "Transfer funds to new rewards contract at '"$CLAIMS_ACCOUNT_ID"'", + "kind": { + "Transfer": { + "token_id": "", + "receiver_id": "'"$CLAIMS_ACCOUNT_ID"'", + "amount": "'"$TRANSFER_AMOUNT"'" + } + } + } + }' \ + prepaid-gas '30.0 Tgas' \ + attached-deposit '0.1 NEAR' \ + sign-as $SIGNER_ACCOUNT_ID \ + network-config mainnet sign-with-keychain send +``` + +### 5.6 Check and Approve Transfer Proposal + +```bash +# Record the proposal ID from the previous step +export TRANSFER_PROPOSAL_ID= + +# Check proposal status +near contract call-function as-read-only $DAO_ACCOUNT_ID get_proposal \ + json-args '{"id": '"$TRANSFER_PROPOSAL_ID"'}' \ + network-config mainnet now + +# Approve the proposal (repeat for each required signer) +near contract call-function as-transaction $DAO_ACCOUNT_ID act_proposal \ + json-args '{"id": '"$TRANSFER_PROPOSAL_ID"', "action": "VoteApprove"}' \ + prepaid-gas '150.0 Tgas' \ + attached-deposit '0 NEAR' \ + sign-as $SIGNER_ACCOUNT_ID \ + network-config mainnet sign-with-keychain send +``` + +### 5.7 Verify Funds Received + +```bash +near account view-account-summary $CLAIMS_ACCOUNT_ID network-config mainnet now +``` + +**Verification Checklist:** + +- [ ] No active campaigns on old contract (claim_end has passed) +- [ ] Withdraw proposal created and approved +- [ ] Transfer proposal created and approved +- [ ] New claims contract has received the funds + --- -## Part 5: Campaign Operations +## Part 6: Campaign Operations As in the [previous task](4-near-rewards-merkle-verification.md), this part remains unchanged. --- -## Part 6: Security Council Verification & Approval +## Part 7: Security Council Verification & Approval As in the [previous task](4-near-rewards-merkle-verification.md), this part remains unchanged. --- -## Part 7: User Claims +## Part 8: User Claims As in the [previous task](4-near-rewards-merkle-verification.md), this part remains unchanged. @@ -180,7 +345,7 @@ As in the [previous task](4-near-rewards-merkle-verification.md), this part rema - [ ] Derived pubkey added to security council DAO - [ ] Merkle claim contract deployed with DAO as owner - [ ] All access keys deleted from claims contract -- [ ] Claims contract funded with NEAR +- [ ] Funds withdrawn from old contract and transferred to new contract ### Per-Campaign @@ -193,7 +358,8 @@ As before. | Contract | Account ID | Environment | |----------|------------|-------------| | Owner DAO | `rewards-claims2.sputnik-dao.near` | PRODUCTION | -| Merkle Claim | `rewards.dao` | PRODUCTION | +| Merkle Claim (new) | `rewards.dao` | PRODUCTION | +| Merkle Claim (old) | `rewards.hos-dao.near` | PRODUCTION | | veNEAR | `venear.dao` | PRODUCTION | ---