Back to challenges
Open to all

Badge Handshake

Confirm your badge by reading the phrase stored on Arkiv and replaying it in a handshake entity that sets the badge payload to handshake="confirmed".

Beginner

Reward Details

$150 worth of GLM tokens

Badge Handshake

Difficulty: Beginner A welcome bot issues every registrant a badge phrase - prove you can echo it back to enter the workshop.

Objective

Confirm your badge by reading the phrase stored on Arkiv and replaying it in a handshake entity that sets the badge payload to handshake="confirmed".

How To Join

Install the Arkiv SDK and follow the quickstart at https://arkiv.network/#getting-started.

Choose and fund the wallet you will use, then export it as ARKIV_PRIVATE_KEY (the 0x prefix is optional). Use the Mendoza faucet at https://mendoza.hoodi.arkiv.network/faucet/ and inspect your entities with https://explorer.mendoza.hoodi.arkiv.network/.

Point your tools at the Mendoza public endpoints:

export ARKIV_RPC_URL=https://mendoza.hoodi.arkiv.network/rpc
export ARKIV_WS_URL=wss://mendoza.hoodi.arkiv.network/rpc/ws

Register on-chain by creating an entity with register_for="badge-handshake" and team="<team name>".

Example registration snippet:

#!/usr/bin/env bun

import { createWalletClient, http, type Hex } from "@arkiv-network/sdk"
import { privateKeyToAccount } from "@arkiv-network/sdk/accounts"
import { mendoza } from "@arkiv-network/sdk/chains"
import { ExpirationTime, jsonToPayload } from "@arkiv-network/sdk/utils"

const SLUG = "badge-handshake"
const RPC_URL = process.env.ARKIV_RPC_URL ?? "https://mendoza.hoodi.arkiv.network/rpc"

async function register(team: string): Promise<void> {
    const privateKey = (process.env.ARKIV_PRIVATE_KEY ?? "").trim() as Hex
    if (!privateKey) {
        throw new Error("Set ARKIV_PRIVATE_KEY before running this script")
    }

    const account = privateKeyToAccount(privateKey)
    const walletClient = createWalletClient({ chain: mendoza, transport: http(RPC_URL), account })

    const { entityKey, txHash } = await walletClient.createEntity({
        payload: jsonToPayload({ intent: "register" }),
        contentType: "application/json",
        attributes: [
            { key: "register_for", value: SLUG },
            { key: "team", value: team },
        ],
        expiresIn: ExpirationTime.fromMinutes(10),
    })

    console.log(`Registered ${team} entity=${entityKey} tx=${txHash}`)
}

register("your-team-name").catch((error) => {
    console.error(error)
    process.exit(1)
})

After registration the server mints a badge entity annotated ctf="badge-handshake", team, and badge_for="<registration entity>". Read the JSON payload to capture badge_phrase, then craft a handshake entity with annotations handshake_for_badge="<badge id>" and team. The handshake payload is a JSON object like {"phrase": "<badge_phrase>", "visitor": "<optional shoutout>"}—the phrase key must exactly match what you received.

Support

Drop a message in the #CTFs channel on Discord.