feat: add Conductor plugin for Context-Driven Development

Add comprehensive Conductor plugin implementing Context-Driven Development
methodology with tracks, specs, and phased implementation plans.

Components:
- 5 commands: setup, new-track, implement, status, revert
- 1 agent: conductor-validator
- 3 skills: context-driven-development, track-management, workflow-patterns
- 18 templates for project artifacts

Documentation updates:
- README.md: Updated counts (68 plugins, 100 agents, 110 skills, 76 tools)
- docs/plugins.md: Added Conductor to Workflows section
- docs/agents.md: Added conductor-validator agent
- docs/agent-skills.md: Added Conductor skills section

Also includes Prettier formatting across all project files.
This commit is contained in:
Seth Hobson
2026-01-15 17:38:21 -05:00
parent 87231b828d
commit f662524f9a
94 changed files with 11610 additions and 1728 deletions

View File

@@ -150,6 +150,7 @@ contract GameItems is ERC1155, Ownable {
## Metadata Standards
### Off-Chain Metadata (IPFS)
```json
{
"name": "NFT #1",
@@ -175,6 +176,7 @@ contract GameItems is ERC1155, Ownable {
```
### On-Chain Metadata
```solidity
contract OnChainNFT is ERC721 {
struct Traits {

View File

@@ -20,9 +20,11 @@ Master smart contract security best practices, vulnerability prevention, and sec
## Critical Vulnerabilities
### 1. Reentrancy
Attacker calls back into your contract before state is updated.
**Vulnerable Code:**
```solidity
// VULNERABLE TO REENTRANCY
contract VulnerableBank {
@@ -41,6 +43,7 @@ contract VulnerableBank {
```
**Secure Pattern (Checks-Effects-Interactions):**
```solidity
contract SecureBank {
mapping(address => uint256) public balances;
@@ -60,6 +63,7 @@ contract SecureBank {
```
**Alternative: ReentrancyGuard**
```solidity
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
@@ -81,6 +85,7 @@ contract SecureBank is ReentrancyGuard {
### 2. Integer Overflow/Underflow
**Vulnerable Code (Solidity < 0.8.0):**
```solidity
// VULNERABLE
contract VulnerableToken {
@@ -95,6 +100,7 @@ contract VulnerableToken {
```
**Secure Pattern (Solidity >= 0.8.0):**
```solidity
// Solidity 0.8+ has built-in overflow/underflow checks
contract SecureToken {
@@ -109,6 +115,7 @@ contract SecureToken {
```
**For Solidity < 0.8.0, use SafeMath:**
```solidity
import "@openzeppelin/contracts/utils/math/SafeMath.sol";
@@ -126,6 +133,7 @@ contract SecureToken {
### 3. Access Control
**Vulnerable Code:**
```solidity
// VULNERABLE: Anyone can call critical functions
contract VulnerableContract {
@@ -139,6 +147,7 @@ contract VulnerableContract {
```
**Secure Pattern:**
```solidity
import "@openzeppelin/contracts/access/Ownable.sol";
@@ -166,6 +175,7 @@ contract RoleBasedContract {
### 4. Front-Running
**Vulnerable:**
```solidity
// VULNERABLE TO FRONT-RUNNING
contract VulnerableDEX {
@@ -179,6 +189,7 @@ contract VulnerableDEX {
```
**Mitigation:**
```solidity
contract SecureDEX {
mapping(bytes32 => bool) public usedCommitments;
@@ -206,6 +217,7 @@ contract SecureDEX {
## Security Best Practices
### Checks-Effects-Interactions Pattern
```solidity
contract SecurePattern {
mapping(address => uint256) public balances;
@@ -226,6 +238,7 @@ contract SecurePattern {
```
### Pull Over Push Pattern
```solidity
// Prefer this (pull)
contract SecurePayment {
@@ -256,6 +269,7 @@ contract RiskyPayment {
```
### Input Validation
```solidity
contract SecureContract {
function transfer(address to, uint256 amount) public {
@@ -273,6 +287,7 @@ contract SecureContract {
```
### Emergency Stop (Circuit Breaker)
```solidity
import "@openzeppelin/contracts/security/Pausable.sol";
@@ -294,6 +309,7 @@ contract EmergencyStop is Pausable, Ownable {
## Gas Optimization
### Use `uint256` Instead of Smaller Types
```solidity
// More gas efficient
contract GasEfficient {
@@ -315,6 +331,7 @@ contract GasInefficient {
```
### Pack Storage Variables
```solidity
// Gas efficient (3 variables in 1 slot)
contract PackedStorage {
@@ -334,6 +351,7 @@ contract UnpackedStorage {
```
### Use `calldata` Instead of `memory` for Function Arguments
```solidity
contract GasOptimized {
// More gas efficient
@@ -349,6 +367,7 @@ contract GasOptimized {
```
### Use Events for Data Storage (When Appropriate)
```solidity
contract EventStorage {
// Emitting events is cheaper than storage
@@ -394,45 +413,44 @@ const { expect } = require("chai");
const { ethers } = require("hardhat");
describe("Security Tests", function () {
it("Should prevent reentrancy attack", async function () {
const [attacker] = await ethers.getSigners();
it("Should prevent reentrancy attack", async function () {
const [attacker] = await ethers.getSigners();
const VictimBank = await ethers.getContractFactory("SecureBank");
const bank = await VictimBank.deploy();
const VictimBank = await ethers.getContractFactory("SecureBank");
const bank = await VictimBank.deploy();
const Attacker = await ethers.getContractFactory("ReentrancyAttacker");
const attackerContract = await Attacker.deploy(bank.address);
const Attacker = await ethers.getContractFactory("ReentrancyAttacker");
const attackerContract = await Attacker.deploy(bank.address);
// Deposit funds
await bank.deposit({value: ethers.utils.parseEther("10")});
// Deposit funds
await bank.deposit({ value: ethers.utils.parseEther("10") });
// Attempt reentrancy attack
await expect(
attackerContract.attack({value: ethers.utils.parseEther("1")})
).to.be.revertedWith("ReentrancyGuard: reentrant call");
});
// Attempt reentrancy attack
await expect(
attackerContract.attack({ value: ethers.utils.parseEther("1") }),
).to.be.revertedWith("ReentrancyGuard: reentrant call");
});
it("Should prevent integer overflow", async function () {
const Token = await ethers.getContractFactory("SecureToken");
const token = await Token.deploy();
it("Should prevent integer overflow", async function () {
const Token = await ethers.getContractFactory("SecureToken");
const token = await Token.deploy();
// Attempt overflow
await expect(
token.transfer(attacker.address, ethers.constants.MaxUint256)
).to.be.reverted;
});
// Attempt overflow
await expect(token.transfer(attacker.address, ethers.constants.MaxUint256))
.to.be.reverted;
});
it("Should enforce access control", async function () {
const [owner, attacker] = await ethers.getSigners();
it("Should enforce access control", async function () {
const [owner, attacker] = await ethers.getSigners();
const Contract = await ethers.getContractFactory("SecureContract");
const contract = await Contract.deploy();
const Contract = await ethers.getContractFactory("SecureContract");
const contract = await Contract.deploy();
// Attempt unauthorized withdrawal
await expect(
contract.connect(attacker).withdraw(100)
).to.be.revertedWith("Ownable: caller is not the owner");
});
// Attempt unauthorized withdrawal
await expect(contract.connect(attacker).withdraw(100)).to.be.revertedWith(
"Ownable: caller is not the owner",
);
});
});
```

View File

@@ -32,30 +32,30 @@ module.exports = {
settings: {
optimizer: {
enabled: true,
runs: 200
}
}
runs: 200,
},
},
},
networks: {
hardhat: {
forking: {
url: process.env.MAINNET_RPC_URL,
blockNumber: 15000000
}
blockNumber: 15000000,
},
},
goerli: {
url: process.env.GOERLI_RPC_URL,
accounts: [process.env.PRIVATE_KEY]
}
accounts: [process.env.PRIVATE_KEY],
},
},
gasReporter: {
enabled: true,
currency: 'USD',
coinmarketcap: process.env.COINMARKETCAP_API_KEY
currency: "USD",
coinmarketcap: process.env.COINMARKETCAP_API_KEY,
},
etherscan: {
apiKey: process.env.ETHERSCAN_API_KEY
}
apiKey: process.env.ETHERSCAN_API_KEY,
},
};
```
@@ -64,7 +64,10 @@ module.exports = {
```javascript
const { expect } = require("chai");
const { ethers } = require("hardhat");
const { loadFixture, time } = require("@nomicfoundation/hardhat-network-helpers");
const {
loadFixture,
time,
} = require("@nomicfoundation/hardhat-network-helpers");
describe("Token Contract", function () {
// Fixture for test setup
@@ -94,8 +97,11 @@ describe("Token Contract", function () {
it("Should transfer tokens between accounts", async function () {
const { token, owner, addr1 } = await loadFixture(deployTokenFixture);
await expect(token.transfer(addr1.address, 50))
.to.changeTokenBalances(token, [owner, addr1], [-50, 50]);
await expect(token.transfer(addr1.address, 50)).to.changeTokenBalances(
token,
[owner, addr1],
[-50, 50],
);
});
it("Should fail if sender doesn't have enough tokens", async function () {
@@ -103,7 +109,7 @@ describe("Token Contract", function () {
const initialBalance = await token.balanceOf(addr1.address);
await expect(
token.connect(addr1).transfer(owner.address, 1)
token.connect(addr1).transfer(owner.address, 1),
).to.be.revertedWith("Insufficient balance");
});
@@ -219,6 +225,7 @@ contract TokenTest is Test {
## Advanced Testing Patterns
### Snapshot and Revert
```javascript
describe("Complex State Changes", function () {
let snapshotId;
@@ -242,6 +249,7 @@ describe("Complex State Changes", function () {
```
### Mainnet Forking
```javascript
describe("Mainnet Fork Tests", function () {
let uniswapRouter, dai, usdc;
@@ -249,23 +257,25 @@ describe("Mainnet Fork Tests", function () {
before(async function () {
await network.provider.request({
method: "hardhat_reset",
params: [{
forking: {
jsonRpcUrl: process.env.MAINNET_RPC_URL,
blockNumber: 15000000
}
}]
params: [
{
forking: {
jsonRpcUrl: process.env.MAINNET_RPC_URL,
blockNumber: 15000000,
},
},
],
});
// Connect to existing mainnet contracts
uniswapRouter = await ethers.getContractAt(
"IUniswapV2Router",
"0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D"
"0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D",
);
dai = await ethers.getContractAt(
"IERC20",
"0x6B175474E89094C44Da98b954EedeAC495271d0F"
"0x6B175474E89094C44Da98b954EedeAC495271d0F",
);
});
@@ -276,19 +286,22 @@ describe("Mainnet Fork Tests", function () {
```
### Impersonating Accounts
```javascript
it("Should impersonate whale account", async function () {
const whaleAddress = "0x...";
await network.provider.request({
method: "hardhat_impersonateAccount",
params: [whaleAddress]
params: [whaleAddress],
});
const whale = await ethers.getSigner(whaleAddress);
// Use whale's tokens
await dai.connect(whale).transfer(addr1.address, ethers.utils.parseEther("1000"));
await dai
.connect(whale)
.transfer(addr1.address, ethers.utils.parseEther("1000"));
});
```
@@ -299,8 +312,11 @@ const { expect } = require("chai");
describe("Gas Optimization", function () {
it("Compare gas usage between implementations", async function () {
const Implementation1 = await ethers.getContractFactory("OptimizedContract");
const Implementation2 = await ethers.getContractFactory("UnoptimizedContract");
const Implementation1 =
await ethers.getContractFactory("OptimizedContract");
const Implementation2 = await ethers.getContractFactory(
"UnoptimizedContract",
);
const contract1 = await Implementation1.deploy();
const contract2 = await Implementation2.deploy();
@@ -337,7 +353,7 @@ npx hardhat coverage
// Verify on Etherscan
await hre.run("verify:verify", {
address: contractAddress,
constructorArguments: [arg1, arg2]
constructorArguments: [arg1, arg2],
});
```
@@ -362,7 +378,7 @@ jobs:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: '16'
node-version: "16"
- run: npm install
- run: npx hardhat compile