Skip to content
Merged

Dev #138

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
174 changes: 174 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
## AGENTS.md – Bloxchain Protocol

This file is a **briefing document for AI agents** working on this repo. It complements `README.md` and the docs under `sdk/typescript/docs`.

Focus areas:
- Core Solidity contracts under `contracts/core`
- TypeScript SDK under `sdk/typescript`

---

## 1. Tech Stack & Targets

- **Language / Runtime**
- Solidity `0.8.34` (upgradeable, OZ upgradeable patterns)
- TypeScript (Viem‑based SDK)
- **Core Domains**
- `contracts/core` – source of truth for all protocol behavior
- `sdk/typescript` – thin, type‑safe wrappers and helpers for the core contracts
- **Do not treat** `contracts/` and `sdk/typescript/` as independent systems: the SDK is an integration layer over the Solidity core.

When in doubt, **derive behavior from Solidity first**, then align the SDK and docs.

---

## 2. Project Structure (for Agents)

Key paths you should care about:

- `contracts/core/`
- `lib/EngineBlox.sol` – central state machine library (`SecureOperationState`, tx lifecycle, RBAC, function schemas, meta‑tx, whitelists).
- `base/BaseStateMachine.sol` – upgrade‑safe wrapper that owns `_secureState` and exposes shared queries and helpers.
- `security/SecureOwnable.sol` – owner / broadcaster / recovery roles, timelock configuration.
- `access/RuntimeRBAC.sol` – dynamic, non‑protected roles and function permissions, batch config.
- `execution/GuardController.sol` – guarded execution, time‑lock workflows, target whitelists.
- `pattern/Account.sol` – abstract pattern that **combines all three components**; basis for account‑style contracts (e.g. `AccountBlox`).
- `lib/utils/SharedValidation.sol` – common validation helpers and custom errors.
- `*/lib/definitions/*.sol` – definition libraries with function schemas, operation types, and default permissions.

- `sdk/typescript/`
- `contracts/core/*.tsx` – class wrappers for core contracts (`SecureOwnable`, `RuntimeRBAC`, `GuardController`, `BaseStateMachine`).
- `lib/EngineBlox.tsx` – TS mirror of `EngineBlox` pure helpers and constants.
- `utils/metaTx/metaTransaction.tsx` – EIP‑712 + meta‑tx helpers that must match the Solidity domain / struct hashes.
- `utils/*` – error handling, validation, interface IDs, ERC‑20 helpers.
- `docs/` – SDK and architecture docs (up‑to‑date; treat as user‑facing source of truth).

---

## 3. Commands for Agents

When you need to **build, test, or regenerate docs**, prefer these:

```bash
# Compile & size‑check contracts (Truffle / Foundry flows may coexist)
npm run compile:foundry
npm run compile:truffle:size

# Run protocol & sanity tests
npm run test:foundry
npm run test:sanity-sdk:core

# Regenerate Solidity‑based docs (NatSpec)
npm run docgen
```

Always keep changes compatible with existing tests; if you modify core behavior, update the relevant sanity scripts under `scripts/sanity-sdk`.

---

## 4. Documentation & Alignment Rules

For **any change to core behavior**:

1. **Solidity first**
- Update the relevant file under `contracts/core`.
- Maintain or improve NatSpec; it is the canonical machine‑readable spec.
2. **SDK second**
- Update the corresponding wrapper under `sdk/typescript/contracts/core`.
- Ensure types in `sdk/typescript/types` and interfaces in `sdk/typescript/interfaces` stay consistent.
3. **Docs third**
- Update or add markdown under `sdk/typescript/docs`, especially:
- `api-reference.md`
- Component guides: `secure-ownable.md`, `runtime-rbac.md`, `guard-controller.md`
- Architecture docs: `bloxchain-architecture.md`, `state-machine-engine.md`, `core-contract-graph.md`, `account-pattern.md`, `getting-started.md`

Agents should **never** introduce new public methods or change signatures without:
- Updating NatSpec
- Updating TS types/wrappers
- Updating affected docs

---

## 5. Code Style & Safety Constraints

High‑level rules for agents:

- **Security first**
- Preserve and extend reentrancy protections (`nonReentrant`, CEI).
- Never weaken input validation or access control (`SharedValidation`, role checks, whitelist checks).
- Do not bypass state‑machine entrypoints with “shortcut” external functions.
- **Upgradeability**
- Core components use OZ upgradeable patterns – **no constructors** on upgradeable contracts.
- Keep storage layout stable; use gaps as already defined.
- **Custom errors over strings**
- Prefer existing custom errors in `SharedValidation` and related libraries.

TypeScript:
- Use existing helpers (e.g. `EngineBlox`, meta‑tx utils, validation helpers) before adding new ad‑hoc logic.
- Keep Viem types (`PublicClient`, `WalletClient`, `Address`, `Hex`) accurate and explicit.

---

## 6. Boundaries & Things Agents Must Not Do

Agents **must not**:

- Commit secrets or modify:
- `.env`
- Deployment keys or secret configs
- Hard‑code private keys, RPC URLs, or production contract addresses in source; use envs or `deployed-addresses.json`.
- Change CI / security enforcement to “work around” tests or linters (e.g. disabling checks, lowering coverage, skipping Slither/Semgrep).
- Remove or weaken timelock, RBAC, or whitelist checks to “simplify” flows.

If an operation requires touching live deployments or production infra, stop and request explicit instructions.

---

## 7. Guidance for Different Agent Types

- **AI audit agents**
- Start from:
- `contracts/core/lib/EngineBlox.sol`
- `contracts/core/base/BaseStateMachine.sol`
- `contracts/core/security/SecureOwnable.sol`
- `contracts/core/access/RuntimeRBAC.sol`
- `contracts/core/execution/GuardController.sol`
- Cross‑reference:
- `sdk/typescript/docs/core-contract-graph.md`
- `sdk/typescript/docs/bloxchain-architecture.md`
- `sdk/typescript/docs/state-machine-engine.md`
- Focus on invariants: role separation, timelock enforcement, meta‑tx replay protection, whitelist enforcement, upgrade safety.

- **AI builder agents**
- Prefer building on **Account‑based contracts** (`contracts/core/pattern/Account.sol` and its implementations).
- Use SDK entrypoints:
- `SecureOwnable`, `RuntimeRBAC`, `GuardController`, `BaseStateMachine` wrappers
- `lib/EngineBlox.tsx` and `utils/metaTx/metaTransaction.tsx`
- Follow examples from:
- `scripts/sanity-sdk/*`
- `sdk/typescript/docs/examples-basic.md`
- `sdk/typescript/docs/getting-started.md`

- **AI operational agents**
- When wiring flows (role config, guard config, meta‑tx ops), follow the same ordering and constraints as the definition libraries:
- `contracts/core/access/lib/definitions/RuntimeRBACDefinitions.sol`
- `contracts/core/execution/lib/definitions/GuardControllerDefinitions.sol`
- Use `deployed-addresses.json` as the canonical source for contract addresses per network.

---

## 8. How to Ask the Repo for Help

When you need more context:

- Read:
- `README.md`
- `sdk/typescript/docs/index.md`
- `sdk/typescript/docs/getting-started.md`
- `sdk/typescript/docs/account-pattern.md`
- Look at:
- Existing tests under `scripts/sanity-sdk`
- NatSpec in the relevant Solidity files

Prefer **deriving intent from tests and NatSpec** over guessing new behaviors. If required behavior is unclear or ambiguous, surface a question to a human rather than inventing protocol‑level semantics.

12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,22 +111,22 @@ Addresses are written to **`deployed-addresses.json`**.

| Contract | Address |
|----------|---------|
| EngineBlox | [`0x51c870ce35fecf1917fa633e06c708563deedd2a`](https://sepolia.etherscan.io/address/0x51c870ce35fecf1917fa633e06c708563deedd2a) |
| SecureOwnableDefinitions | [`0x7353a3977bdae344c34cf2a3ab14063bd6408d52`](https://sepolia.etherscan.io/address/0x7353a3977bdae344c34cf2a3ab14063bd6408d52) |
| RuntimeRBACDefinitions | [`0x49b67fe22865b69b7e95cbd1886531ff3a3a3b24`](https://sepolia.etherscan.io/address/0x49b67fe22865b69b7e95cbd1886531ff3a3a3b24) |
| GuardControllerDefinitions | [`0x3fe69cc06dc2484a5fac2af21b9158e9c4f16cd7`](https://sepolia.etherscan.io/address/0x3fe69cc06dc2484a5fac2af21b9158e9c4f16cd7) |
| EngineBlox | [`0xb090b28379f1de23ed81d4a151c7ae693d23ba61`](https://sepolia.etherscan.io/address/0xb090b28379f1de23ed81d4a151c7ae693d23ba61) |
| SecureOwnableDefinitions | [`0xca0bb5092f7abdac176a750f5eb7e747662bfc45`](https://sepolia.etherscan.io/address/0xca0bb5092f7abdac176a750f5eb7e747662bfc45) |
| RuntimeRBACDefinitions | [`0x6a2d53655c38ba4bba11afaf7700a1edce54bfc4`](https://sepolia.etherscan.io/address/0x6a2d53655c38ba4bba11afaf7700a1edce54bfc4) |
| GuardControllerDefinitions | [`0x0fdfede18ae02da6116154f2beff0c6c5379ffd1`](https://sepolia.etherscan.io/address/0x0fdfede18ae02da6116154f2beff0c6c5379ffd1) |

#### Account

| Contract | Address |
|----------|---------|
| AccountBlox | [`0xa44c8f4f70b9615278544b6cc89a2fb5ef609522`](https://sepolia.etherscan.io/address/0xa44c8f4f70b9615278544b6cc89a2fb5ef609522) |
| AccountBlox | [`0x05afa7bfd78d60e4affec9a3194b12aea3b28479`](https://sepolia.etherscan.io/address/0x05afa7bfd78d60e4affec9a3194b12aea3b28479) |

#### Examples

| Contract | Address |
|----------|---------|
| CopyBlox | [`0x1731bd93e9275983aec8813562af2fbba1d5fa68`](https://sepolia.etherscan.io/address/0x1731bd93e9275983aec8813562af2fbba1d5fa68) |
| CopyBlox | [`0xa5f9dbde2b3ac26f6cf78e0e4d93d7bfe47e80da`](https://sepolia.etherscan.io/address/0xa5f9dbde2b3ac26f6cf78e0e4d93d7bfe47e80da) |

## 📖 Usage Examples

Expand Down
59 changes: 45 additions & 14 deletions migrations/2_deploy_guardian_contracts.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ module.exports = async function(deployer, network, accounts) {
await deployer.deploy(AccountBlox);
accountBlox = await AccountBlox.deployed();
console.log("✅ AccountBlox deployed at:", accountBlox.address);

// Get web3 from deployed contract instance (available for error handling)
const web3 = accountBlox.constructor.web3 || global.web3;

Expand All @@ -96,9 +97,6 @@ module.exports = async function(deployer, network, accounts) {
console.log(` ⚠️ Warning: Nonce sync failed after max retries, proceeding anyway`);
}

// Save network info to artifact (fixes issue when network_id is "*")
await saveArtifactNetwork(AccountBlox, accountBlox.address, web3, network);

// Initialize AccountBlox
console.log("🔧 Initializing AccountBlox...");
try {
Expand All @@ -111,27 +109,60 @@ module.exports = async function(deployer, network, accounts) {
);
console.log("✅ AccountBlox initialized successfully");
console.log(" Transaction hash:", tx.tx);

// Save network info to artifact only after successful initialization
await saveArtifactNetwork(AccountBlox, accountBlox.address, web3, network);
} catch (error) {
console.log("❌ AccountBlox initialization failed:");
console.log(" Error message:", error.message);
console.log(" Error reason:", error.reason);
console.log(" Error data:", error.data);
console.log(" Full error:", JSON.stringify(error, null, 2));

// If the provider threw a connection error after broadcasting the tx,
// it's possible that the contract was actually initialized on-chain.
// Check the owner() state to detect this and avoid double-initializing.
let initializedOnChain = false;
try {
const currentOwner = await accountBlox.owner();
if (currentOwner && currentOwner !== "0x0000000000000000000000000000000000000000") {
initializedOnChain = true;
console.log("⚠️ initialize() reported an error, but owner() is set on-chain:", currentOwner);
console.log(" Treating AccountBlox as initialized based on contract state.");
} else {
console.log(" owner() check indicates AccountBlox is not initialized (owner is zero address).");
Comment on lines +127 to +133
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

owner() alone is not a safe success signal for initialization.

Treating non-zero owner() as success can persist network metadata even when other initializer state is still wrong/missing (e.g., broadcaster/recovery/timelock), leading to a partially usable deployment being marked healthy.

💡 Suggested hardening
-                const currentOwner = await accountBlox.owner();
-                if (currentOwner && currentOwner !== "0x0000000000000000000000000000000000000000") {
+                const zero = "0x0000000000000000000000000000000000000000";
+                const currentOwner = await accountBlox.owner();
+                const broadcasters = await accountBlox.getBroadcasters();
+                const recovery = await accountBlox.getRecovery();
+                const timelock = await accountBlox.getTimeLockPeriodSec();
+                if (
+                    currentOwner && currentOwner !== zero &&
+                    Array.isArray(broadcasters) && broadcasters.length > 0 &&
+                    recovery && recovery !== zero &&
+                    Number(timelock) > 0
+                ) {
                     initializedOnChain = true;
                     console.log("⚠️  initialize() reported an error, but owner() is set on-chain:", currentOwner);
                     console.log("   Treating AccountBlox as initialized based on contract state.");
                 } else {
-                    console.log("   owner() check indicates AccountBlox is not initialized (owner is zero address).");
+                    console.log("   On-chain checks indicate AccountBlox is not fully initialized.");
                 }

Also applies to: 139-147

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@migrations/2_deploy_guardian_contracts.cjs` around lines 127 - 133, The
migration treats a non-zero accountBlox.owner() as sufficient evidence of full
initialization; instead, update the check to verify all essential initializer
state (e.g., broadcaster(), recovery(), timelock() or an isInitialized() helper)
before setting initializedOnChain true. Specifically, augment the owner check in
the block that references accountBlox.owner() and the similar block later (lines
around the other owner() use) to also call and validate broadcaster(),
recovery(), and timelock (or an explicit isInitialized() if available), ensure
none are the zero address / default values, and only then set initializedOnChain
= true; if any required field is missing, log which field failed and treat the
contract as uninitialized.

}
} catch (ownerCheckError) {
console.log(" Additional owner() check failed:", ownerCheckError.message);
}

// Try to decode the error if it's a revert
if (error.data) {
if (initializedOnChain) {
// In this case, persist network info so sanity tests and tooling
// can still discover the deployed/initialized contract.
try {
const decodedError = await web3.eth.call({
to: accountBlox.address,
data: error.data
});
console.log(" Decoded error data:", decodedError);
} catch (decodeError) {
console.log(" Could not decode error data:", decodeError.message);
await saveArtifactNetwork(AccountBlox, accountBlox.address, web3, network);
console.log("✅ Saved AccountBlox network info after owner() state check.");
} catch (saveError) {
console.log("⚠️ Failed to save AccountBlox network info after owner() check:", saveError.message);
}
} else {
// Try to decode the error if it's a revert
if (error.data) {
try {
const decodedError = await web3.eth.call({
to: accountBlox.address,
data: error.data
});
console.log(" Decoded error data:", decodedError);
} catch (decodeError) {
console.log(" Could not decode error data:", decodeError.message);
}
}

console.log("⚠️ Contract deployed but not initialized. This must be resolved before using this deployment.");
// Fail the migration so callers know initialization did not succeed
throw new Error("AccountBlox initialization failed – migration aborted.");
}

console.log("⚠️ Contract deployed but not initialized. This may be expected for upgradeable contracts.");
}
} else {
console.log("\n📦 Step 2: Skipping AccountBlox deployment (disabled)");
Expand Down
10 changes: 9 additions & 1 deletion scripts/deployment/deploy-foundation-libraries.js
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,15 @@ async function main() {
],
account: deployerAccount,
});
await waitForTransactionReceipt(publicClient, { hash: initHash });
const initReceipt = await waitForTransactionReceipt(publicClient, { hash: initHash });
if (initReceipt.status !== "success" && initReceipt.status !== 1n) {
console.error(
`⚠️ AccountBlox initialization transaction did not succeed (status: ${String(
initReceipt.status
)}). Please inspect tx: ${initHash}`
);
throw new Error("AccountBlox initialization failed");
}
console.log(` ✅ AccountBlox initialized (tx: ${initHash})`);

console.log("\n🎉 Foundation libraries deployment complete.");
Expand Down
Loading