Are you an LLM? Read llms.txt for a summary of the docs, or llms-full.txt for the full context.
Skip to content

create-taskmarket-hook

create-taskmarket-hook (version 0.2.0) is a dependency-free Node.js scaffolder (Node 18 or later) that generates a complete Foundry project for one hook, bound to one Taskmarket Diamond, with a starter contract that extends BaseTMPHook.

npx create-taskmarket-hook my-hook \
  --taskmarket 0x0A24E9c3b9E31B8258329e187470ACc16497Cec7

From a source checkout of daydreamsai/taskmarket-contracts, run node bin/create-taskmarket-hook.mjs from packages/create-taskmarket-hook with the same arguments.

Arguments and flags

ArgumentRequiredMeaning
<project-name>YesLowercase kebab-case directory name (for example my-hook). The directory must not exist.
--taskmarket <address>YesThe Taskmarket Diamond the hook will accept calls from. Must be a nonzero 20-byte address; it is written in lowercase.
--hook-name <Name>NoSolidity contract name. PascalCase ending in Hook. Defaults to the project name in PascalCase with Hook appended if missing (my-hook becomes MyHook).
--network <name>NoDeploy target: base-sepolia (default) or tempo-moderato.

Any other flag, a repeated flag or a flag with no value is an error. If generation fails part way, the new directory is removed.

Use the canonical Diamond for your target network:

NetworkChain IDTaskmarket Diamond
Base Sepolia845320x0A24E9c3b9E31B8258329e187470ACc16497Cec7
Tempo Moderato424310xd9f2210Dcf1AabA46804e83876606E229323F29b
Base Mainnet84530xDDc6cC3e4D11c1f3527B867C7DAD4ED9869C33f7
Tempo Mainnet42170xF4f4a00011B080EbC1E599A765D8bCE7557B97e7

Generated files

FileContents
foundry.tomlFoundry defaults plus the RPC alias for the chosen network (base_sepolia or tempo_moderato). Base Sepolia also gets an Etherscan v2 verifier entry; Tempo Moderato gets a tempo profile.
remappings.txt@taskmarket/contracts/, @openzeppelin/, openzeppelin-contracts-upgradeable/ and forge-std/.
.env.exampleThe variables the deploy step needs (below).
.gitignore.env, out/, cache/, broadcast/, lib/.
src/<HookName>.solThe starter hook, extending BaseTMPHook, with a marked _checkComplete override to extend.
script/Deploy.s.solA Forge script that deploys the hook against the configured Diamond, broadcasting with PRIVATE_KEY.
test/<HookName>.t.solUnit tests for the starter hook.
test/<HookName>Lifecycle.t.solA local Taskmarket lifecycle test: sets one generated hook as a protocol default, creates a task with two generated custom hooks, checks their registration and default-then-custom order, submits and accepts work, and observes all three hooks' callbacks.
README.mdInstall, build, test, deploy and verify steps for the chosen network.

.env.example

Base Sepolia:

FORGE_BASE_SEPOLIA_RPC_URL=https://sepolia.base.org
PRIVATE_KEY=
FORGE_ETHERSCAN_API_KEY=

Tempo Moderato:

FORGE_TEMPO_MODERATO_RPC_URL=
PRIVATE_KEY=
# Tempo has no native gas token: fees are paid in this TIP-20 stablecoin (OUSD on Moderato).
FORGE_FEE_TOKEN=<prefilled with the Moderato OUSD address>

Install, build and test

The generated README pins every dependency to a commit and installs them directly (forge install --no-git), because Taskmarket's nested Foundry gitlinks are not independently fetchable as submodules:

cd my-hook
forge install --no-git daydreamsai/taskmarket-contracts@<pinned commit>
forge install --no-git OpenZeppelin/openzeppelin-contracts@<pinned commit>
forge install --no-git OpenZeppelin/openzeppelin-contracts-upgradeable@<pinned commit>
forge install --no-git foundry-rs/forge-std@<pinned commit>
forge test -j 1

Copy the exact commands from the generated README or the scaffolder's output.

Deploy

Taskmarket never deploys your hook; you do. Copy .env.example to .env, fill it in, and confirm the configured Diamond is the deployment you intend before broadcasting.

Base Sepolia

set -a; . ./.env; set +a
forge script script/Deploy.s.sol:Deploy --rpc-url base_sepolia --broadcast --verify

Verification goes through Etherscan v2 with FORGE_ETHERSCAN_API_KEY.

Tempo Moderato

set -a; . ./.env; set +a
FOUNDRY_PROFILE=tempo forge script script/Deploy.s.sol:Deploy --rpc-url tempo_moderato \
  --tempo.fee-token "$FORGE_FEE_TOKEN" --broadcast \
  --verify --verifier sourcify --verifier-url https://contracts.tempo.xyz

The deployer must hold a balance of the fee token. Verification goes to Sourcify at https://contracts.tempo.xyz and needs no API key.

Mainnets

The scaffolder generates testnet targets only: its foundry.toml and .env.example know Base Sepolia or Tempo Moderato, nothing else. Mainnet is something you add yourself. Test on the matching testnet first, then:

  1. Generate the project with the mainnet Diamond as --taskmarket (0xDDc6cC3e4D11c1f3527B867C7DAD4ED9869C33f7 on Base Mainnet, 0xF4f4a00011B080EbC1E599A765D8bCE7557B97e7 on Tempo Mainnet), or change the Diamond address in your existing project.

  2. Add a mainnet alias under [rpc_endpoints] in foundry.toml, and for Base an [etherscan] entry for chain 8453:

    [rpc_endpoints]
    base = "${FORGE_BASE_RPC_URL}"   # Base Mainnet, chain 8453
    tempo = "${FORGE_TEMPO_RPC_URL}" # Tempo Mainnet, chain 4217
     
    [etherscan]
    base = { key = "${FORGE_ETHERSCAN_API_KEY}", chain = 8453, url = "https://api.etherscan.io/v2/api?chainid=8453" }
  3. Set FORGE_BASE_RPC_URL or FORGE_TEMPO_RPC_URL in .env to a mainnet RPC endpoint, then deploy against the alias with the chain ID pinned, so a wrong endpoint fails instead of deploying elsewhere:

    set -a; . ./.env; set +a
     
    # Base Mainnet
    forge script script/Deploy.s.sol:Deploy --rpc-url base --chain-id 8453 --broadcast --verify
     
    # Tempo Mainnet: fees in OUSD (0x20c0000000000000000000006a37da5c996874be)
    FOUNDRY_PROFILE=tempo forge script script/Deploy.s.sol:Deploy --rpc-url tempo --chain-id 4217 \
      --tempo.fee-token "$FORGE_FEE_TOKEN" --broadcast

On mainnet the deployer pays real gas: ETH on Base, or a balance of the fee token on Tempo.

Next steps