A self-serve Slack bot for distributing gas and test tokens to developers from a Safe multisig on Base. Supports ETH and USDC on Base, Ethereum mainnet, and Arbitrum — non-Base requests are bridged automatically via Uniswap.
1. Developer runs: /cajero request 0.01 ETH vitalik.eth testing --network eth
2. Bot checks allowlist
3. Bot resolves ENS name to 0x address (if applicable)
4. For Base: proposes a direct Safe transaction
For ETH/Arb: fetches a cross-chain quote from Uniswap and proposes a bridge transaction
5. Bot auto-executes the Safe transaction (if threshold = 1)
6. Bot posts confirmation with BaseScan link
- Multi-chain: fund recipients on Base, Ethereum, or Arbitrum
- Uniswap bridge: cross-chain requests use Uniswap's routing API from the Base Safe
- ENS + raw address support for recipients
- Safe auto-execution when threshold is met (no manual signing required)
- Allowlist restricts usage to specific Slack users
- Rate limiting at one pending request per user
- Amount caps per token (configurable)
/cajero request <amount> <token> <recipient> <reason> [--network base|eth|arb] [--project name]
Request funds. Default network is Base.
ETH and Arb requests are bridged via Uniswap.
Recipient can be an ENS name or 0x address.
/cajero status
Show your pending requests.
/cajero balance
Show the Safe's ETH and USDC balance on Base.
/cajero expenses [project-name]
Show spending totals by project and network.
/cajero request 0.01 ETH vitalik.eth testing bridge
/cajero request 0.01 ETH 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 gas --network eth
/cajero request 50 USDC 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 hackathon --network arb --project bridge-v2
/cajero balance
- Go to api.slack.com/apps > Create New App > From scratch
- Name it
El Cajero, pick your workspace
Enable Socket Mode:
- Settings > Socket Mode > Enable
- This generates an App-Level Token (
xapp-...) withconnections:writescope
Add Bot Token Scopes:
- Features > OAuth & Permissions > Bot Token Scopes:
commandschat:writechat:write.public
Create Slash Command:
- Features > Slash Commands > Create:
- Command:
/cajero - Description:
Request test funds from the team Safe - Usage hint:
request <amount> <token> <recipient> <reason> [--network base|eth|arb]
- Command:
Enable Interactivity:
- Features > Interactivity & Shortcuts > Toggle On
Install to Workspace:
- Settings > Install App > Install to Workspace
- Copy the Bot User OAuth Token (
xoxb-...) - Copy the Signing Secret from Basic Information
- Go to app.safe.global > Create new Safe on Base
- Note the Safe address
- Run the bot once to see the bot wallet address in the startup log
- Add the bot wallet as a Safe owner (Settings > Owners > Add new owner)
- Set threshold to 1 for auto-execution
Fund the Safe with ETH and/or USDC on Base. For cross-chain requests, Uniswap will route from those Base funds.
cp .env.example .envFill in all values. See .env.example for descriptions.
npm install
npm run dev # Development (with hot reload)
npm run build # Production build
npm start # Run production buildcajero/
src/
index.ts # Slack app, command routing, execution monitor
config.ts # Env validation, constants
handlers/
requestFunds.ts # /cajero request handler
uniswap/
bridge.ts # Uniswap cross-chain bridge quotes
ens/
resolve.ts # ENS name resolution (mainnet provider)
safe/
proposeTx.ts # Safe propose + auto-execute (direct + bridge)
db/
store.ts # SQLite: requests table
Slack (/cajero request)
|
v
Allowlist check --> reject if not allowed
|
v
ENS resolution (mainnet) --> resolve name or validate 0x address
|
v
Network = base?
|-- Yes --> Safe SDK: direct ETH/USDC transfer on Base
|-- No --> Uniswap API: cross-chain bridge quote
|
v
Safe SDK: propose bridge tx (approve + Universal Router call)
|
v
Execution monitor --> poll for on-chain confirmation (Base)
- Only allowlisted Slack user IDs can use the bot
- Hard caps per request (
MAX_AMOUNT_ETH/MAX_AMOUNT_USDC) - Max 1 pending request per user at a time
- Addresses validated with
ethers.isAddress()or ENS resolution - Private keys never logged to Slack or console
- All requests logged to SQLite
- Connect your GitHub repo
- Set environment variables in the dashboard
- Build command:
npm run build - Start command:
npm start
- Create a new Background Worker
- Build command:
npm install && npm run build - Start command:
npm start - Add environment variables in the dashboard
The bot uses Socket Mode (WebSocket), so no public URL or port is needed.