chore: .gitignore and README updates

Made-with: Cursor
This commit is contained in:
defiQUG
2026-04-21 22:00:55 -07:00
parent 843cdbf71c
commit 768168de5e
37 changed files with 505 additions and 118 deletions

View File

@@ -12,9 +12,9 @@ import {CompliantWrappedToken} from "../../contracts/tokens/CompliantWrappedToke
* Env:
* PRIVATE_KEY (required)
* CW_BRIDGE_ADDRESS (required) — address that can mint/burn (e.g. CCIP receiver or custom bridge)
* CW_STRICT_MODE=1 (optional) — revoke deployer MINTER/BURNER after bridge grant
* CW_STRICT_MODE=0 (optional override) — by default deployer MINTER/BURNER are revoked after bridge grant
* CW_GOVERNANCE_ADMIN=0x... (optional) — grant DEFAULT_ADMIN_ROLE to governance; if strict, revoke deployer admin when governance is set
* CW_FREEZE_OPERATIONAL_ROLES=1 (optional) — freeze future MINTER/BURNER changes after setup
* CW_FREEZE_OPERATIONAL_ROLES=0 (optional override) — by default freeze future MINTER/BURNER changes after setup
* DEPLOY_CWUSDT=1, DEPLOY_CWUSDC=1, DEPLOY_CWUSDW=1, DEPLOY_CWEURC=1, ... (default all 1; set 0 to skip a token)
*/
contract DeployCWTokens is Script {
@@ -24,8 +24,8 @@ contract DeployCWTokens is Script {
uint256 pk = vm.envUint("PRIVATE_KEY");
address deployer = vm.addr(pk);
address bridge = vm.envAddress("CW_BRIDGE_ADDRESS");
bool strictMode = vm.envOr("CW_STRICT_MODE", uint256(0)) == 1;
bool freezeOperationalRoles = vm.envOr("CW_FREEZE_OPERATIONAL_ROLES", uint256(0)) == 1;
bool strictMode = vm.envOr("CW_STRICT_MODE", uint256(1)) == 1;
bool freezeOperationalRoles = vm.envOr("CW_FREEZE_OPERATIONAL_ROLES", uint256(1)) == 1;
address governanceAdmin = vm.envOr("CW_GOVERNANCE_ADMIN", address(0));
require(bridge != address(0), "CW_BRIDGE_ADDRESS required");

View File

@@ -14,6 +14,9 @@ import {CompliantWrappedToken} from "../../contracts/tokens/CompliantWrappedToke
* CW_TOKEN_NAME (required)
* CW_TOKEN_SYMBOL (required)
* CW_TOKEN_DECIMALS (optional, default 6)
* CW_STRICT_MODE=0 (optional override) — by default deployer MINTER/BURNER are revoked after bridge grant
* CW_GOVERNANCE_ADMIN=0x... (optional) — grant DEFAULT_ADMIN_ROLE to governance; if strict, revoke deployer admin when governance is set
* CW_FREEZE_OPERATIONAL_ROLES=0 (optional override) — by default freeze future MINTER/BURNER changes after setup
*/
contract DeploySingleCWToken is Script {
function run() external {
@@ -23,6 +26,9 @@ contract DeploySingleCWToken is Script {
string memory tokenName = vm.envString("CW_TOKEN_NAME");
string memory tokenSymbol = vm.envString("CW_TOKEN_SYMBOL");
uint8 decimals_ = uint8(vm.envOr("CW_TOKEN_DECIMALS", uint256(6)));
bool strictMode = vm.envOr("CW_STRICT_MODE", uint256(1)) == 1;
bool freezeOperationalRoles = vm.envOr("CW_FREEZE_OPERATIONAL_ROLES", uint256(1)) == 1;
address governanceAdmin = vm.envOr("CW_GOVERNANCE_ADMIN", address(0));
require(bridge != address(0), "CW_BRIDGE_ADDRESS required");
require(bytes(tokenName).length != 0, "CW_TOKEN_NAME required");
@@ -34,10 +40,32 @@ contract DeploySingleCWToken is Script {
token.grantRole(token.MINTER_ROLE(), bridge);
token.grantRole(token.BURNER_ROLE(), bridge);
if (strictMode) {
token.revokeRole(token.MINTER_ROLE(), admin);
token.revokeRole(token.BURNER_ROLE(), admin);
}
if (governanceAdmin != address(0) && governanceAdmin != admin) {
token.grantRole(token.DEFAULT_ADMIN_ROLE(), governanceAdmin);
}
if (freezeOperationalRoles) {
token.freezeOperationalRoles();
}
if (strictMode && governanceAdmin != address(0) && governanceAdmin != admin) {
token.revokeRole(token.DEFAULT_ADMIN_ROLE(), admin);
}
vm.stopBroadcast();
console.log(tokenSymbol, address(token));
console.log(" bridge", bridge);
console.log(" strictMode", strictMode);
console.log(" governanceAdmin", governanceAdmin);
console.log(" operationalRolesFrozen", token.operationalRolesFrozen());
console.log(" deployerHasMinter", token.hasRole(token.MINTER_ROLE(), admin));
console.log(" deployerHasBurner", token.hasRole(token.BURNER_ROLE(), admin));
console.log(" bridgeHasMinter", token.hasRole(token.MINTER_ROLE(), bridge));
console.log(" bridgeHasBurner", token.hasRole(token.BURNER_ROLE(), bridge));
}

View File

@@ -7,9 +7,10 @@ import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
/**
* @title AddLiquidityPMMPoolsChain138
* @notice Add liquidity to the three DODO PMM pools on Chain 138 (cUSDT/cUSDC, cUSDT/USDT, cUSDC/USDC).
* @notice Add liquidity to the canonical DODO PMM pools on Chain 138, including the stable/WETH lanes.
* @dev Env: PRIVATE_KEY, RPC_URL_138, DODO_PMM_INTEGRATION_ADDRESS (or DODO_PMM_INTEGRATION),
* POOL_CUSDTCUSDC, POOL_CUSDTUSDT, POOL_CUSDCUSDC,
* optional POOL_CUSDTWETH, POOL_CUSDCWETH, POOL_CEURTWETH,
* ADD_LIQUIDITY_BASE_AMOUNT, ADD_LIQUIDITY_QUOTE_AMOUNT (e.g. 1000000e6 for 1M units, 6 decimals).
* Optional: ADD_LIQUIDITY_CUSDTCUSDC_BASE, ADD_LIQUIDITY_CUSDTCUSDC_QUOTE, etc. for per-pool amounts.
* Optional: NEXT_NONCE — set to pending nonce (e.g. after mints) to avoid -32001 "Nonce too low" on broadcast.
@@ -31,6 +32,9 @@ contract AddLiquidityPMMPoolsChain138 is Script {
address poolCusdtCusdc = vm.envOr("POOL_CUSDTCUSDC", address(0));
address poolCusdtUsdt = vm.envOr("POOL_CUSDTUSDT", address(0));
address poolCusdcUsdc = vm.envOr("POOL_CUSDCUSDC", address(0));
address poolCusdtWeth = vm.envOr("POOL_CUSDTWETH", address(0));
address poolCusdcWeth = vm.envOr("POOL_CUSDCWETH", address(0));
address poolCeurtWeth = vm.envOr("POOL_CEURTWETH", address(0));
uint256 defaultBase = vm.envOr("ADD_LIQUIDITY_BASE_AMOUNT", uint256(0));
uint256 defaultQuote = vm.envOr("ADD_LIQUIDITY_QUOTE_AMOUNT", uint256(0));
@@ -40,6 +44,8 @@ contract AddLiquidityPMMPoolsChain138 is Script {
address cusdc = integration.compliantUSDC();
address usdt = integration.officialUSDT();
address usdc = integration.officialUSDC();
address ceurt = vm.envOr("CEURT_ADDRESS_138", address(0xdf4b71c61E5912712C1Bdd451416B9aC26949d72));
address weth = vm.envOr("WETH9_ADDRESS_138", vm.envOr("WETH_ADDRESS_138", address(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2)));
// On Chain 138, cUSDT/USDT and cUSDC/USDC should point at live local mirror quote tokens.
// If the configured quote-side addresses have no code on 138, skip those pools to avoid "call to non-contract".
@@ -73,6 +79,30 @@ contract AddLiquidityPMMPoolsChain138 is Script {
console.log("Added liquidity to cUSDC/USDC pool:", poolCusdcUsdc);
}
}
if (poolCusdtWeth != address(0) && (defaultBase > 0 || defaultQuote > 0)) {
uint256 b = vm.envOr("ADD_LIQUIDITY_CUSDTWETH_BASE", defaultBase);
uint256 q = vm.envOr("ADD_LIQUIDITY_CUSDTWETH_QUOTE", defaultQuote);
if (b > 0 && q > 0) {
_approveAndAdd(integration, cusdt, weth, poolCusdtWeth, b, q);
console.log("Added liquidity to cUSDT/WETH pool:", poolCusdtWeth);
}
}
if (poolCusdcWeth != address(0) && (defaultBase > 0 || defaultQuote > 0)) {
uint256 b = vm.envOr("ADD_LIQUIDITY_CUSDCWETH_BASE", defaultBase);
uint256 q = vm.envOr("ADD_LIQUIDITY_CUSDCWETH_QUOTE", defaultQuote);
if (b > 0 && q > 0) {
_approveAndAdd(integration, cusdc, weth, poolCusdcWeth, b, q);
console.log("Added liquidity to cUSDC/WETH pool:", poolCusdcWeth);
}
}
if (poolCeurtWeth != address(0) && (defaultBase > 0 || defaultQuote > 0)) {
uint256 b = vm.envOr("ADD_LIQUIDITY_CEURTWETH_BASE", defaultBase);
uint256 q = vm.envOr("ADD_LIQUIDITY_CEURTWETH_QUOTE", defaultQuote);
if (b > 0 && q > 0) {
_approveAndAdd(integration, ceurt, weth, poolCeurtWeth, b, q);
console.log("Added liquidity to cEURT/WETH pool:", poolCeurtWeth);
}
}
vm.stopBroadcast();
}

View File

@@ -22,9 +22,9 @@ interface IDODOPMMPoolQuote {
* FLASH_QUOTE_AMOUNT_RAW gross USDC borrowed / pushed (6 decimals raw)
*
* Optional:
* POOL_CWUSDC_USDC_MAINNET default 0x69776fc607e9edA8042e320e7e43f54d06c68f0E
* CWUSDC_MAINNET default canonical cWUSDC
* USDC_MAINNET default official USDC
* MAX_FLASH_QUOTE_AMOUNT_RAW optional tighter local cap; must not exceed the defended-lane safe cap
* MIN_OUT_PMM if unset, derived from querySellQuote(receiver, amount) * MIN_OUT_PMM_NUM / MIN_OUT_PMM_DEN (defaults 985/1000)
* MIN_OUT_PMM_NUM / MIN_OUT_PMM_DEN
* MIN_OUT_UNWIND if unset, amount + ceil(amount * AAVE_FLASH_PREMIUM_BPS / 10000) + MIN_OUT_UNWIND_BUFFER_RAW
@@ -50,6 +50,7 @@ contract RunMainnetAaveCwusdcUsdcQuotePushOnce is Script {
address internal constant DEFAULT_POOL = 0x69776fc607e9edA8042e320e7e43f54d06c68f0E;
address internal constant DEFAULT_CWUSDC = 0x2de5F116bFcE3d0f922d9C8351e0c5Fc24b9284a;
address internal constant DEFAULT_USDC = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48;
uint256 internal constant DEFENDED_SAFE_CAP_RAW = 2_964_298;
function run() external {
uint256 pk = vm.envUint("PRIVATE_KEY");
@@ -60,6 +61,9 @@ contract RunMainnetAaveCwusdcUsdcQuotePushOnce is Script {
address usdc = vm.envOr("USDC_MAINNET", DEFAULT_USDC);
address unwinder = vm.envAddress("QUOTE_PUSH_EXTERNAL_UNWINDER_MAINNET");
uint256 amount = vm.envUint("FLASH_QUOTE_AMOUNT_RAW");
uint256 localCap = vm.envOr("MAX_FLASH_QUOTE_AMOUNT_RAW", DEFENDED_SAFE_CAP_RAW);
_validateDefendedLane(pool, amount, localCap);
uint256 minPmmNum = vm.envOr("MIN_OUT_PMM_NUM", uint256(985));
uint256 minPmmDen = vm.envOr("MIN_OUT_PMM_DEN", uint256(1000));
@@ -150,4 +154,10 @@ contract RunMainnetAaveCwusdcUsdcQuotePushOnce is Script {
AaveQuotePushFlashReceiver(receiver).flashQuotePush(usdc, amount, p);
vm.stopBroadcast();
}
function _validateDefendedLane(address pool, uint256 amount, uint256 localCap) internal pure {
require(pool == DEFAULT_POOL, "defended pool only");
require(localCap <= DEFENDED_SAFE_CAP_RAW, "local cap exceeds defended safe cap");
require(amount <= localCap, "flash amount exceeds cap");
}
}

View File

@@ -31,6 +31,7 @@ contract RunManagedMainnetAaveCwusdcUsdcQuotePushCycle is Script {
address internal constant DEFAULT_POOL = 0x69776fc607e9edA8042e320e7e43f54d06c68f0E;
address internal constant DEFAULT_CWUSDC = 0x2de5F116bFcE3d0f922d9C8351e0c5Fc24b9284a;
address internal constant DEFAULT_USDC = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48;
uint256 internal constant DEFENDED_SAFE_CAP_RAW = 2_964_298;
function run() external {
uint256 pk = vm.envUint("PRIVATE_KEY");
@@ -42,9 +43,12 @@ contract RunManagedMainnetAaveCwusdcUsdcQuotePushCycle is Script {
address usdc = vm.envOr("USDC_MAINNET", DEFAULT_USDC);
address unwinder = vm.envAddress("QUOTE_PUSH_EXTERNAL_UNWINDER_MAINNET");
uint256 amount = vm.envUint("FLASH_QUOTE_AMOUNT_RAW");
uint256 localCap = vm.envOr("MAX_FLASH_QUOTE_AMOUNT_RAW", DEFENDED_SAFE_CAP_RAW);
bool harvest = vm.envOr("QUOTE_PUSH_TREASURY_HARVEST", uint256(1)) == 1;
uint256 gasHoldbackTargetRaw = vm.envOr("QUOTE_PUSH_TREASURY_GAS_HOLDBACK_TARGET_RAW", uint256(0));
_validateDefendedLane(pool, amount, localCap);
QuotePushTreasuryManager manager = QuotePushTreasuryManager(managerAddr);
AaveQuotePushFlashReceiver.QuotePushParams memory p =
_loadQuotePushParams(receiver, pool, integration, baseToken, unwinder, amount);
@@ -70,6 +74,12 @@ contract RunManagedMainnetAaveCwusdcUsdcQuotePushCycle is Script {
console.log("receiverSweepableAfter", manager.receiverSweepableQuote());
}
function _validateDefendedLane(address pool, uint256 amount, uint256 localCap) internal pure {
require(pool == DEFAULT_POOL, "defended pool only");
require(localCap <= DEFENDED_SAFE_CAP_RAW, "local cap exceeds defended safe cap");
require(amount <= localCap, "flash amount exceeds cap");
}
function _loadQuotePushParams(
address receiver,
address pool,

View File

@@ -95,6 +95,14 @@ contract ImportProviderPoolsToIntegration is Script {
_importIfNeeded(json, providerSource, integration, explicitBase, explicitQuote, lpFeeRate, initialPrice, kFactor, enableTwap);
}
for (uint256 i = 0; json.keyExists(string.concat(".plannedPairs[", vm.toString(i), "]")); i++) {
string memory baseKey = string.concat(".plannedPairs[", vm.toString(i), "].baseSymbol");
string memory quoteKey = string.concat(".plannedPairs[", vm.toString(i), "].quoteSymbol");
string memory plannedBase = json.readString(baseKey);
string memory plannedQuote = json.readString(quoteKey);
_importIfNeeded(json, providerSource, integration, plannedBase, plannedQuote, lpFeeRate, initialPrice, kFactor, enableTwap);
}
vm.stopBroadcast();
}