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
1 change: 0 additions & 1 deletion .gitignore

This file was deleted.

3 changes: 0 additions & 3 deletions .vscode/settings.json

This file was deleted.

22 changes: 0 additions & 22 deletions README.md

This file was deleted.

3 changes: 0 additions & 3 deletions cairo_program/.vscode/settings.json

This file was deleted.

1 change: 0 additions & 1 deletion cairo_program/src/bool.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ fn is_adult(x: u8) -> bool {
return true;
}


// determine even numbers
fn is_even(x: u8) -> bool {
if x % 2 == 0 {
Expand Down
43 changes: 38 additions & 5 deletions cairo_program/src/integer.cairo
Original file line number Diff line number Diff line change
@@ -1,20 +1,53 @@
use core::num::traits::OverflowingMul;

#[executable]
fn main() {
let result: u8 = add_num(5, 6);
println!("the sum of x & y is: {}", result);
assert(result == 11, 'invalid sum logic');
let add_result: u8 = add_num(5, 6);
println!("the sum of x & y is: {}", add_result);
assert(add_result == 11, 'invalid sum logic');

let sub_result: u8 = sub_num(10, 5);
println!("sub result is: {}", sub_result);
assert(sub_result == 5, 'invalid sub logic');

// Test subtraction that should panic (10 - 15 = negative)
// sub_num(10, 15); // This would panic

let mul_result: u8 = mul_num(255, 1);
println!("mul result is: {}", mul_result);
assert(mul_result == 255, 'invalid mul logic');

let div_result: u8 = div_num(20, 0);
println!("div result is: {}", div_result);
assert(div_result == 5, 'invalid div logic');

// Test division by zero - should panic
// div_num(10, 0); // This would panic
}

// addition logic
fn add_num(x: u8, y: u8) -> u8 {
x + y
return x + y;
}

// subtraction logic
fn sub_num(x: u8, y: u8) -> u8 {
return x - y;
assert!(!(y > x), "negative result not allowed");
x - y
}

// multiplication logic
fn mul_num(x: u8, y: u8) -> u8 {
let (result_, overflowed_) = x.overflowing_mul(y);

assert!(!(overflowed_), "multiplication overflowed");

result_
}

// division logic with division by zero check
fn div_num(x: u8, y: u8) -> u8 {
assert!(!(y == 0), "Cannot be Zero");
x / y
}

4 changes: 2 additions & 2 deletions cairo_program/src/lib.cairo
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// mod hello_world;
// mod short_string;
// mod integer;
mod integer;
// mod bool;
mod bytearray;
// mod bytearray;
27 changes: 27 additions & 0 deletions starknet-agentic/examples/transfer-agent/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Starknet Sepolia credentials (required)
STARKNET_RPC_URL=https://starknet-sepolia.g.alchemy.com/v2/YOUR_KEY
STARKNET_ACCOUNT_ADDRESS=0x...
STARKNET_PRIVATE_KEY=0x...

# Optional AVNU paymaster (gasless transfers on Sepolia)
# AVNU_BASE_URL=https://sepolia.api.avnu.fi
# AVNU_PAYMASTER_URL=https://sepolia.paymaster.avnu.fi
# AVNU_PAYMASTER_API_KEY=

# Transfer policy
TRANSFER_TOKEN=STRK
MIN_BALANCE_TO_TRANSFER=50
TRANSFER_AMOUNT=1
RESERVE_AFTER_TRANSFER=10
LOW_BALANCE_ALERT_THRESHOLD=20
TRANSFER_RECIPIENT=0x...

# Execution
RUN_MODE=dry-run
TRANSFER_GASFREE=0
TRANSFER_AGENT_MCP_ENTRY=../../packages/starknet-mcp-server/dist/index.js
TRANSFER_AGENT_MCP_LABEL=transfer-agent
TRANSFER_AGENT_OUTPUT_DIR=./artifacts

# Optional webhook stub for low-balance alerts
# ALERT_WEBHOOK_URL=
3 changes: 3 additions & 0 deletions starknet-agentic/examples/transfer-agent/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.env
artifacts/
node_modules/
142 changes: 142 additions & 0 deletions starknet-agentic/examples/transfer-agent/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
# Transfer Agent (Test 2 — Sepolia)

Composable autonomous transfer agent that orchestrates Starknet MCP tools in a multi-step pipeline.

## Test 2 requirements mapping

| Requirement | How this example demonstrates it |
|-------------|--------------------------------|
| Fetch wallet balance | `starknet_get_balance` in `fetchBalance()` |
| Validate transfer condition | `evaluateTransferPolicy()` — balance must be **strictly greater than** `MIN_BALANCE_TO_TRANSFER` and respect `RESERVE_AFTER_TRANSFER` |
| Transfer if balance > X | `starknet_transfer` with `dryRun: true` then on-chain when `RUN_MODE=execute` |
| Call another function | Post-step `starknet_call_contract` — `balance_of` on recipient |
| Log execution result | Structured JSON logs + `artifacts/transfer-agent-<timestamp>.json` |
| Low-balance alerts | `checkLowBalanceAlert()` — `WARN` log; optional `ALERT_WEBHOOK_URL` POST |

## Prerequisites

- Node.js 20+
- Built MCP server at `packages/starknet-mcp-server/dist/index.js`
- Sepolia-funded account with STRK (USDC mainnet address fails on Sepolia — use STRK or ETH)

```bash
# From repo root
pnpm install && pnpm build
```

## Setup

```bash
cd examples/transfer-agent
cp .env.example .env
# Edit .env: STARKNET_RPC_URL (Sepolia), account, private key, TRANSFER_RECIPIENT
```

Default policy (with 100 STRK):

- Transfer only if balance **> 50 STRK**
- Send **1 STRK** to recipient
- Keep **10 STRK** reserve after transfer
- Alert if balance **< 20 STRK**

## Run

```bash
# Unit tests (policy logic)
pnpm test

# Dry-run: simulate transfer, no on-chain tx
pnpm run run

# Human-readable terminal output (recommended for demos)
pnpm run:pretty
pnpm run:execute:pretty

# Execute real Sepolia transfer (small amount!)
pnpm run:execute
```

### `--pretty` output

Add `--pretty` (or `TRANSFER_AGENT_PRETTY=1`) for readable lines instead of JSON:

```text
[INFO] Starting transfer-agent
Token: STRK | Mode: dry-run | Recipient: 0x...
[INFO] Balance: 200 STRK
Account: 0x...
[ALERT] LOW BALANCE ALERT # only when below threshold
[INFO] Policy: transfer allowed
[INFO] Transfer simulated (dry-run)
[INFO] Run completed
Artifact: ./artifacts/transfer-agent-....json
```

## CLI commands (interactive)

One-shot commands via MCP (same `.env` as the agent):

```bash
pnpm cli balance STRK --pretty
pnpm cli balances ETH STRK --pretty
pnpm cli transfer 1 STRK 0xRecipient... --pretty # simulate only
pnpm cli transfer 1 STRK 0xRecipient... --execute --pretty # real tx
pnpm cli call 0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d balance_of 0xYourAccount... --pretty
pnpm cli workflow --pretty # full pipeline
pnpm cli help
```

## Execute mode failed with "Contract not found"?

If `pnpm run:execute` or `pnpm cli transfer ... --execute` fails on `starknet_getClassAt` for your **account** address, your smart-contract wallet is likely **not deployed** on that network yet. Reads (balance) can work while writes cannot.

**Fix:** deploy the account first, then retry:

1. Use a wallet that is already deployed on Sepolia (ArgentX / Braavos with a funded account), and put that address + private key in `.env`, **or**
2. Deploy a new agent account: [examples/onboard-agent/README.md](../onboard-agent/README.md) — then update `.env` with the new `STARKNET_ACCOUNT_ADDRESS` and `STARKNET_PRIVATE_KEY` from `onboarding_secrets.json`.

Verify deployment:

```bash
pnpm cli call 0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d balance_of $STARKNET_ACCOUNT_ADDRESS
```

## Demo low-balance alert

Temporarily raise the alert threshold above your balance:

```bash
LOW_BALANCE_ALERT_THRESHOLD=200 pnpm run
```

Expect a `WARN` log with `reasonCode: "ALERT_LOW_BALANCE"`.

## Demo policy block (skip transfer)

Lower the minimum so balance is not above threshold, or raise `MIN_BALANCE_TO_TRANSFER` above your balance:

```bash
MIN_BALANCE_TO_TRANSFER=200 pnpm run
```

Artifact will show `transfer.skipped: true` and `reasonCode: "BLOCK_BALANCE_NOT_ABOVE_THRESHOLD"`.

## Artifact output

Each run writes `artifacts/transfer-agent-<iso-timestamp>.json` containing:

- `balanceBefore` — MCP balance response
- `lowBalanceAlert` — alert evaluation
- `transferPolicy` — allow/block decision
- `transfer` — simulation or execution result
- `followUp` — recipient `balance_of` read

## Network note

Use a **Sepolia** RPC URL. MCP token symbols resolve to canonical addresses shared by mainnet/Sepolia for ETH and STRK. USDC at the mainnet address does not exist on Sepolia.

## Security

- Never commit `.env` or private keys
- Start with `RUN_MODE=dry-run` and small `TRANSFER_AMOUNT` (e.g. `0.001`)
- Use a recipient address you control
Loading