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 0x0A24E9c3b9E31B8258329e187470ACc16497Cec7From 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
| Argument | Required | Meaning |
|---|---|---|
<project-name> | Yes | Lowercase kebab-case directory name (for example my-hook). The directory must not exist. |
--taskmarket <address> | Yes | The Taskmarket Diamond the hook will accept calls from. Must be a nonzero 20-byte address; it is written in lowercase. |
--hook-name <Name> | No | Solidity contract name. PascalCase ending in Hook. Defaults to the project name in PascalCase with Hook appended if missing (my-hook becomes MyHook). |
--network <name> | No | Deploy 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:
| Network | Chain ID | Taskmarket Diamond |
|---|---|---|
| Base Sepolia | 84532 | 0x0A24E9c3b9E31B8258329e187470ACc16497Cec7 |
| Tempo Moderato | 42431 | 0xd9f2210Dcf1AabA46804e83876606E229323F29b |
| Base Mainnet | 8453 | 0xDDc6cC3e4D11c1f3527B867C7DAD4ED9869C33f7 |
| Tempo Mainnet | 4217 | 0xF4f4a00011B080EbC1E599A765D8bCE7557B97e7 |
Generated files
| File | Contents |
|---|---|
foundry.toml | Foundry 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.example | The variables the deploy step needs (below). |
.gitignore | .env, out/, cache/, broadcast/, lib/. |
src/<HookName>.sol | The starter hook, extending BaseTMPHook, with a marked _checkComplete override to extend. |
script/Deploy.s.sol | A Forge script that deploys the hook against the configured Diamond, broadcasting with PRIVATE_KEY. |
test/<HookName>.t.sol | Unit tests for the starter hook. |
test/<HookName>Lifecycle.t.sol | A 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.md | Install, 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 1Copy 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 --verifyVerification 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.xyzThe 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:
-
Generate the project with the mainnet Diamond as
--taskmarket(0xDDc6cC3e4D11c1f3527B867C7DAD4ED9869C33f7on Base Mainnet,0xF4f4a00011B080EbC1E599A765D8bCE7557B97e7on Tempo Mainnet), or change the Diamond address in your existing project. -
Add a mainnet alias under
[rpc_endpoints]infoundry.toml, and for Base an[etherscan]entry for chain8453:[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" } -
Set
FORGE_BASE_RPC_URLorFORGE_TEMPO_RPC_URLin.envto 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.