Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
195 changes: 195 additions & 0 deletions skills/waves-claim/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
---
name: waves-claim
description: Claim free SURF Waves Card NFTs on Base. One random card every 2 hours.
homepage: https://opensea.io/collection/surf-waves-cards
metadata:
openclaw:
emoji: "🎴"
category: "web3"
requires:
bins: ["cast", "jq"]
---

# Waves Claim Skill

Claim free SURF Waves Card NFTs on Base blockchain.

## Install

```bash
clawhub install waves-claim
```

Or one-click:
```bash
curl -sL https://raw.githubusercontent.com/openclaw/clawhub/main/skills/waves-claim/install.sh | bash
```

## Overview

The WavesTCG ClaimVault distributes free trading card NFTs. Any wallet can claim one random card every 2 hours.

## Contract Info

| Property | Value |
|----------|-------|
| **ClaimVault** | `0xAF1906B749339adaE38A1cba9740fffA168897c2` |
| **NFT Contract** | `0xcc2d6ba8564541e6e51fe5522e26d4f4bbdd458b` |
| **Network** | Base (Chain ID: 8453) |
| **Cooldown** | 2 hours |
| **RPC** | `https://mainnet.base.org` |

## Prerequisites

- Wallet with private key
- Small amount of ETH on Base for gas (~0.0001 ETH)
- Foundry's `cast` CLI (at `~/.foundry/bin/cast`)

## Quick Claim (cast)

```bash
export PATH="$HOME/.foundry/bin:$PATH"
export VAULT="0xAF1906B749339adaE38A1cba9740fffA168897c2" # ClaimVault address
export RPC="https://mainnet.base.org"
export PRIVATE_KEY="0x..." # Your private key

# 1. Check if you can claim
CAN_CLAIM=$(cast call $VAULT "canClaim(address)" $(cast wallet address --private-key $PRIVATE_KEY) --rpc-url $RPC)
echo "Can claim: $CAN_CLAIM"

# 2. If true, claim!
if [ "$CAN_CLAIM" = "0x0000000000000000000000000000000000000000000000000000000000000001" ]; then
cast send $VAULT "claim()" --rpc-url $RPC --private-key $PRIVATE_KEY
fi
```

## Check Cooldown

```bash
# Get seconds until next claim
cast call $VAULT "timeUntilClaim(address)" YOUR_ADDRESS --rpc-url $RPC | cast to-dec
```

## Check Available Cards

```bash
cast call $VAULT "availableCount()" --rpc-url $RPC | cast to-dec
```

## Full Claim Script

```bash
#!/bin/bash
# waves-claim.sh - Claim a free SURF Waves card

export PATH="$HOME/.foundry/bin:$PATH"
VAULT="0xAF1906B749339adaE38A1cba9740fffA168897c2" # UPDATE THIS
RPC="https://mainnet.base.org"

# Load private key from credentials
PRIVATE_KEY=$(jq -r '.private_key' ~/.config/clawtasks/credentials.json)
WALLET=$(cast wallet address --private-key $PRIVATE_KEY)

echo "🌊 SURF Waves Claim"
echo "Wallet: $WALLET"

# Check available
AVAILABLE=$(cast call $VAULT "availableCount()" --rpc-url $RPC | cast to-dec)
echo "Available cards: $AVAILABLE"

if [ "$AVAILABLE" = "0" ]; then
echo "❌ No cards available"
exit 1
fi

# Check cooldown
CAN_CLAIM=$(cast call $VAULT "canClaim(address)" $WALLET --rpc-url $RPC)

if [ "$CAN_CLAIM" != "0x0000000000000000000000000000000000000000000000000000000000000001" ]; then
REMAINING=$(cast call $VAULT "timeUntilClaim(address)" $WALLET --rpc-url $RPC | cast to-dec)
HOURS=$((REMAINING / 3600))
MINS=$(((REMAINING % 3600) / 60))
echo "⏰ Cooldown: ${HOURS}h ${MINS}m remaining"
exit 1
fi

echo "🎯 Claiming..."
TX=$(cast send $VAULT "claim()" --rpc-url $RPC --private-key $PRIVATE_KEY --json)
HASH=$(echo $TX | jq -r '.transactionHash')

echo "✅ Claimed! TX: $HASH"
echo "View on BaseScan: https://basescan.org/tx/$HASH"
```

## Scheduled Claiming

To claim automatically every 2 hours, use OpenClaw cron:

```
/cron add "waves-claim" "0 */2 * * *" "Run ~/.openclaw/skills/waves-claim/claim.sh and report result"
```

## JavaScript Example

```javascript
import { createPublicClient, createWalletClient, http } from 'viem';
import { base } from 'viem/chains';
import { privateKeyToAccount } from 'viem/accounts';

const VAULT = '0x...'; // ClaimVault address

const abi = [
'function canClaim(address) view returns (bool)',
'function availableCount() view returns (uint256)',
'function claim()'
];

export async function claimWavesCard(privateKey) {
const account = privateKeyToAccount(privateKey);

const publicClient = createPublicClient({
chain: base,
transport: http()
});

const walletClient = createWalletClient({
account,
chain: base,
transport: http()
});

// Check eligibility
const [canClaim, available] = await Promise.all([
publicClient.readContract({ address: VAULT, abi, functionName: 'canClaim', args: [account.address] }),
publicClient.readContract({ address: VAULT, abi, functionName: 'availableCount' })
]);

if (!canClaim) return { success: false, reason: 'cooldown' };
if (available === 0n) return { success: false, reason: 'empty' };

const hash = await walletClient.writeContract({
address: VAULT,
abi,
functionName: 'claim'
});

return { success: true, txHash: hash };
}
```

## Troubleshooting

**"Cooldown not expired"**
Wait for 2 hours since your last claim.

**"No NFTs available"**
The vault is empty. Cards are periodically added by the owner.

**"insufficient funds"**
You need ETH on Base for gas. Bridge from mainnet or get from faucet.

## Links

- **Mini-App**: https://wavestcg.xyz/claim
- **OpenSea**: https://opensea.io/collection/surf-waves-cards
- **BaseScan NFT**: https://basescan.org/token/0xcc2d6ba8564541e6e51fe5522e26d4f4bbdd458b
49 changes: 49 additions & 0 deletions skills/waves-claim/install.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#!/bin/bash
# One-click install for SURF Waves Cards auto-claim skill
# Usage: curl -sL https://raw.githubusercontent.com/openclaw/clawhub/main/skills/waves-claim/install.sh | bash

set -e

SKILL_DIR="${OPENCLAW_SKILLS:-$HOME/.openclaw/skills}/waves-claim"
REPO_URL="https://raw.githubusercontent.com/openclaw/clawhub/main/skills/waves-claim"

echo "🎴 Installing SURF Waves Claim Skill..."

# Create directories
mkdir -p "$SKILL_DIR/scripts"

# Download files with error checking
download_file() {
local url="$1"
local dest="$2"
local http_code

http_code=$(curl -sL -w "%{http_code}" -o "$dest" "$url")

if [ "$http_code" != "200" ]; then
echo "❌ Failed to download $url (HTTP $http_code)"
rm -f "$dest"
return 1
fi
}

echo "📥 Downloading skill files..."

download_file "$REPO_URL/SKILL.md" "$SKILL_DIR/SKILL.md" || exit 1
download_file "$REPO_URL/scripts/check-claim.sh" "$SKILL_DIR/scripts/check-claim.sh" || exit 1
download_file "$REPO_URL/scripts/claim.sh" "$SKILL_DIR/scripts/claim.sh" || exit 1

# Make scripts executable
chmod +x "$SKILL_DIR/scripts/"*.sh

echo ""
echo "✅ Installed to: $SKILL_DIR"
echo ""
echo "📋 Prerequisites:"
echo " - Foundry cast: curl -L https://foundry.paradigm.xyz | bash"
echo " - jq: sudo apt install jq (or brew install jq)"
echo " - ETH on Base for gas (~0.0001 ETH)"
echo ""
echo "🚀 Usage:"
echo " Check status: $SKILL_DIR/scripts/check-claim.sh <wallet>"
echo " Claim card: PRIVATE_KEY=0x... $SKILL_DIR/scripts/claim.sh"
66 changes: 66 additions & 0 deletions skills/waves-claim/scripts/check-claim.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#!/bin/bash
# Check if wallet can claim from SURF Waves ClaimVault
# Usage: ./check-claim.sh [wallet_address]

set -e

# Contract addresses
CLAIM_VAULT="${CLAIM_VAULT:-0xAF1906B749339adaE38A1cba9740fffA168897c2}"
NFT_CONTRACT="${NFT_CONTRACT:-0xcc2d6ba8564541e6e51fe5522e26d4f4bbdd458b}"
RPC_URL="${RPC_URL:-https://mainnet.base.org}"

# Check for cast
if ! command -v cast &> /dev/null; then
echo "❌ Foundry 'cast' not found. Install: curl -L https://foundry.paradigm.xyz | bash"
exit 1
fi

# Get wallet from arg or derive from private key
WALLET="${1:-}"
if [ -z "$WALLET" ] && [ -n "$PRIVATE_KEY" ]; then
WALLET=$(cast wallet address "$PRIVATE_KEY" 2>&1) || {
echo "❌ Failed to derive wallet from PRIVATE_KEY"
exit 1
}
fi

if [ -z "$WALLET" ]; then
echo "Usage: ./check-claim.sh <wallet_address>"
echo " Or: PRIVATE_KEY=0x... ./check-claim.sh"
exit 1
fi

echo "🎴 SURF Waves ClaimVault Status"
echo " Vault: $CLAIM_VAULT"
echo " Wallet: $WALLET"
echo ""

# Get available count (convert hex to decimal)
AVAILABLE_HEX=$(cast call "$CLAIM_VAULT" "availableCount()(uint256)" --rpc-url "$RPC_URL" 2>&1) || {
echo "❌ RPC error fetching availableCount: $AVAILABLE_HEX"
exit 1
}
AVAILABLE=$(cast to-dec "$AVAILABLE_HEX" 2>/dev/null || echo "0")
echo "📦 Cards available: $AVAILABLE"

# Check if can claim
CAN_CLAIM=$(cast call "$CLAIM_VAULT" "canClaim(address)(bool)" "$WALLET" --rpc-url "$RPC_URL" 2>&1) || {
echo "❌ RPC error checking canClaim: $CAN_CLAIM"
exit 1
}

if [ "$CAN_CLAIM" = "true" ]; then
echo "✅ You CAN claim now!"
echo ""
echo "Run: ./claim.sh"
else
# Get time until next claim (convert hex to decimal)
TIME_HEX=$(cast call "$CLAIM_VAULT" "timeUntilClaim(address)(uint256)" "$WALLET" --rpc-url "$RPC_URL" 2>&1) || {
echo "❌ RPC error fetching timeUntilClaim: $TIME_HEX"
exit 1
}
TIME_LEFT=$(cast to-dec "$TIME_HEX" 2>/dev/null || echo "0")
MINUTES=$((TIME_LEFT / 60))
SECONDS=$((TIME_LEFT % 60))
echo "⏳ Cooldown: ${MINUTES}m ${SECONDS}s remaining"
fi
Loading