Initial commit: add .gitignore and README
This commit is contained in:
84
scripts/Deploy.s.sol
Normal file
84
scripts/Deploy.s.sol
Normal 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
28
scripts/Pause.s.sol
Normal 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
28
scripts/Unpause.s.sol
Normal 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
178
scripts/simulate.ts
Normal 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;
|
||||
}
|
||||
Reference in New Issue
Block a user