Initial commit: add .gitignore and README

This commit is contained in:
defiQUG
2026-02-09 21:51:54 -08:00
commit 7003349717
127 changed files with 17576 additions and 0 deletions

84
scripts/Deploy.s.sol Normal file
View File

@@ -0,0 +1,84 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {Script} from "forge-std/Script.sol";
import {AtomicExecutor} from "../contracts/AtomicExecutor.sol";
contract Deploy is Script {
function run() external {
uint256 chainId = block.chainid;
address owner = msg.sender; // Or set from env
vm.startBroadcast();
AtomicExecutor executor = new AtomicExecutor(owner);
// Get protocol addresses based on chain
address[] memory targets = getProtocolAddresses(chainId);
executor.setAllowedTargets(targets, true);
// Allow Aave Pool for flash loan callbacks (if exists on chain)
address aavePool = getAavePool(chainId);
if (aavePool != address(0)) {
executor.setAllowedPool(aavePool, true);
}
vm.stopBroadcast();
console.log("AtomicExecutor deployed at:", address(executor));
console.log("Chain ID:", chainId);
console.log("Allowed targets:", targets.length);
}
function getProtocolAddresses(uint256 chainId) internal pure returns (address[] memory) {
if (chainId == 1) {
// Mainnet
address[] memory targets = new address[](6);
targets[0] = 0x87870Bca3F3fD6335C3F4ce8392A6935B38d4Fb1; // Aave v3 Pool
targets[1] = 0xE592427A0AEce92De3Edee1F18E0157C05861564; // Uniswap V3 Router
targets[2] = 0xc3d688B66703497DAA19211EEdff47f25384cdc3; // Compound v3 Comet
targets[3] = 0xBA12222222228d8Ba445958a75a0704d566BF2C8; // Balancer Vault
targets[4] = 0x90E00ACe148ca3b23Ac1bC8C240C2a7Dd9c2d7f5; // Curve Registry
targets[5] = 0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0; // Lido wstETH
return targets;
} else if (chainId == 42161) {
// Arbitrum
address[] memory targets = new address[](4);
targets[0] = 0x794a61358D6845594F94dc1DB02A252b5b4814aD; // Aave v3 Pool
targets[1] = 0xE592427A0AEce92De3Edee1F18E0157C05861564; // Uniswap V3 Router
targets[2] = 0xA5EDBDD9646f8dFF606d7448e414884C7d905dCA; // Compound v3 Comet
targets[3] = 0xBA12222222228d8Ba445958a75a0704d566BF2C8; // Balancer Vault
return targets;
} else if (chainId == 10) {
// Optimism
address[] memory targets = new address[](4);
targets[0] = 0x794a61358D6845594F94dc1DB02A252b5b4814aD; // Aave v3 Pool
targets[1] = 0xE592427A0AEce92De3Edee1F18E0157C05861564; // Uniswap V3 Router
targets[2] = 0xb125E6687d4313864e53df431d5425969c15Eb2F; // Compound v3 Comet
targets[3] = 0xBA12222222228d8Ba445958a75a0704d566BF2C8; // Balancer Vault
return targets;
} else if (chainId == 8453) {
// Base
address[] memory targets = new address[](4);
targets[0] = 0xA238Dd80C259a72e81d7e4664a9801593F98d1c5; // Aave v3 Pool
targets[1] = 0x2626664c2603336E57B271c5C0b26F421741e481; // Uniswap V3 Router
targets[2] = 0xb125E6687d4313864e53df431d5425969c15Eb2F; // Compound v3 Comet
targets[3] = 0xBA12222222228d8Ba445958a75a0704d566BF2C8; // Balancer Vault
return targets;
}
// Default: empty array
address[] memory empty = new address[](0);
return empty;
}
function getAavePool(uint256 chainId) internal pure returns (address) {
if (chainId == 1) return 0x87870Bca3F3fD6335C3F4ce8392A6935B38d4Fb1;
if (chainId == 42161) return 0x794a61358D6845594F94dc1DB02A252b5b4814aD;
if (chainId == 10) return 0x794a61358D6845594F94dc1DB02A252b5b4814aD;
if (chainId == 8453) return 0xA238Dd80C259a72e81d7e4664a9801593F98d1c5;
return address(0);
}
}

28
scripts/Pause.s.sol Normal file
View File

@@ -0,0 +1,28 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {Script, console} from "forge-std/Script.sol";
import {AtomicExecutor} from "../contracts/AtomicExecutor.sol";
/**
* Emergency Pause Script
*
* Usage:
* forge script script/Pause.s.sol --rpc-url $RPC_URL --broadcast
*/
contract Pause is Script {
function run() external {
address executorAddr = vm.envAddress("EXECUTOR_ADDR");
AtomicExecutor executor = AtomicExecutor(executorAddr);
vm.startBroadcast();
console.log("Pausing executor at:", executorAddr);
executor.pause();
vm.stopBroadcast();
console.log("Executor paused successfully");
}
}

28
scripts/Unpause.s.sol Normal file
View File

@@ -0,0 +1,28 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {Script, console} from "forge-std/Script.sol";
import {AtomicExecutor} from "../contracts/AtomicExecutor.sol";
/**
* Unpause Script
*
* Usage:
* forge script script/Unpause.s.sol --rpc-url $RPC_URL --broadcast
*/
contract Unpause is Script {
function run() external {
address executorAddr = vm.envAddress("EXECUTOR_ADDR");
AtomicExecutor executor = AtomicExecutor(executorAddr);
vm.startBroadcast();
console.log("Unpausing executor at:", executorAddr);
executor.unpause();
vm.stopBroadcast();
console.log("Executor unpaused successfully");
}
}

178
scripts/simulate.ts Normal file
View File

@@ -0,0 +1,178 @@
import { JsonRpcProvider, Contract } from "ethers";
import { Strategy } from "../src/strategy.schema.js";
import { StrategyCompiler } from "../src/planner/compiler.js";
import { getChainConfig } from "../src/config/chains.js";
export interface SimulationResult {
success: boolean;
gasUsed?: bigint;
error?: string;
trace?: any;
stateChanges?: Array<{
address: string;
slot: string;
before: string;
after: string;
}>;
}
export async function runForkSimulation(
strategy: Strategy,
forkRpc: string,
blockNumber?: number
): Promise<SimulationResult> {
const provider = new JsonRpcProvider(forkRpc);
const chainConfig = getChainConfig(strategy.chain);
// Create snapshot before simulation
let snapshotId: string | null = null;
try {
snapshotId = await provider.send("evm_snapshot", []);
} catch (error) {
// If snapshot not supported, continue without it
console.warn("Snapshot not supported, continuing without state restore");
}
try {
// Fork at specific block if provided
if (blockNumber) {
try {
await provider.send("anvil_reset", [
{
forking: {
jsonRpcUrl: chainConfig.rpcUrl,
blockNumber,
},
},
]);
} catch (error) {
// If anvil_reset not available, try hardhat_impersonateAccount or continue
console.warn("Fork reset not supported, using current state");
}
}
// Compile strategy
const compiler = new StrategyCompiler(strategy.chain);
const executorAddr = strategy.executor || process.env.EXECUTOR_ADDR;
if (!executorAddr) {
throw new Error("Executor address required for simulation");
}
const plan = await compiler.compile(strategy, executorAddr);
// Execute calls and trace
const traces: any[] = [];
const stateChanges: Array<{
address: string;
slot: string;
before: string;
after: string;
}> = [];
for (const call of plan.calls) {
try {
// Get state before
const stateBefore = await getContractState(provider, call.to);
// Execute call
const result = await provider.call({
to: call.to,
data: call.data,
value: call.value,
});
// Get state after
const stateAfter = await getContractState(provider, call.to);
// Record state changes
for (const slot in stateAfter) {
if (stateBefore[slot] !== stateAfter[slot]) {
stateChanges.push({
address: call.to,
slot,
before: stateBefore[slot] || "0x0",
after: stateAfter[slot],
});
}
}
traces.push({
to: call.to,
data: call.data,
result,
success: true,
});
} catch (error: any) {
traces.push({
to: call.to,
data: call.data,
error: error.message,
success: false,
});
// If any call fails, simulation fails
return {
success: false,
error: `Call to ${call.to} failed: ${error.message}`,
trace: traces,
stateChanges,
};
}
}
// Estimate gas
let gasUsed: bigint | undefined;
try {
// Try to get gas estimate from trace
if (plan.calls.length > 0) {
const { estimateGasForCalls } = await import("../src/utils/gas.js");
gasUsed = await estimateGasForCalls(
provider,
plan.calls,
executorAddr
);
}
} catch (error) {
// Gas estimation failed, continue without it
}
return {
success: true,
gasUsed,
trace: traces,
stateChanges,
};
} catch (error: any) {
return {
success: false,
error: error.message,
};
} finally {
// Restore snapshot if available
if (snapshotId) {
try {
await provider.send("evm_revert", [snapshotId]);
} catch (error) {
// Ignore revert errors
}
}
}
}
async function getContractState(
provider: JsonRpcProvider,
address: string
): Promise<Record<string, string>> {
// Get storage slots (simplified - in production would get all relevant slots)
const state: Record<string, string> = {};
// Try to get balance
try {
const balance = await provider.getBalance(address);
state["balance"] = balance.toString();
} catch {
// Ignore
}
return state;
}