Address
0xbb39b48c2cbb2a552009ea7da94dff8fc77f7bf8Current Holdings
$0.00
TXs sent
not counted
First Active
2026-05-01
block 26,420,153
Last Active
137 days ago
block 26,420,153
Funded By
not identified
Net worth historyi
No net-worth snapshots recorded yet
partial matchSetDutySpellsolc 0.8.28+commit.7893614aruntime partial · creation partial
// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity ^0.8.20;
interface JugLike {
function file(bytes32 ilk, bytes32 what, uint256 data) external;
function drip(bytes32 ilk) external returns (uint256);
function ilks(bytes32) external view returns (uint256 duty, uint256 rho);
}
contract SetDutySpell {
struct IlkDutyUpdate {
bytes32 ilk;
uint256 duty;
}
struct SetDutyParams {
address jug;
address exec;
IlkDutyUpdate[] updates;
}
// ─── ALL IMMUTABLES (safe under delegatecall) ───
address public immutable JUG;
address public immutable EXEC;
uint256 public immutable COUNT;
bytes32 public immutable ILK_0; bytes32 public immutable ILK_1; bytes32 public immutable ILK_2;
bytes32 public immutable ILK_3; bytes32 public immutable ILK_4; bytes32 public immutable ILK_5;
bytes32 public immutable ILK_6; bytes32 public immutable ILK_7; bytes32 public immutable ILK_8;
bytes32 public immutable ILK_9;
uint256 public immutable DUTY_0; uint256 public immutable DUTY_1; uint256 public immutable DUTY_2;
uint256 public immutable DUTY_3; uint256 public immutable DUTY_4; uint256 public immutable DUTY_5;
uint256 public immutable DUTY_6; uint256 public immutable DUTY_7; uint256 public immutable DUTY_8;
uint256 public immutable DUTY_9;
// ─── Events ───
event DripBeforeSet(bytes32 indexed ilk, uint256 vatRate);
event DutyUpdated(bytes32 indexed ilk, uint256 oldDuty, uint256 newDuty);
event SpellExecuted(address indexed jug, uint256 count);
// ─── Errors ───
error AlreadyExecuted();
error NoUpdates();
error EmptyIlk();
error TooManyUpdates(uint256 provided, uint256 max);
error InvalidJug();
constructor(SetDutyParams memory params) {
require(params.jug != address(0), "SetDutySpell/invalid-jug");
require(params.updates.length > 0 && params.updates.length <= 10, "SetDutySpell/invalid-count");
JUG = params.jug;
EXEC = params.exec;
COUNT = params.updates.length;
// Zero-init all slots
ILK_0 = bytes32(0); ILK_1 = bytes32(0); ILK_2 = bytes32(0); ILK_3 = bytes32(0); ILK_4 = bytes32(0);
ILK_5 = bytes32(0); ILK_6 = bytes32(0); ILK_7 = bytes32(0); ILK_8 = bytes32(0); ILK_9 = bytes32(0);
DUTY_0 = 0; DUTY_1 = 0; DUTY_2 = 0; DUTY_3 = 0; DUTY_4 = 0;
DUTY_5 = 0; DUTY_6 = 0; DUTY_7 = 0; DUTY_8 = 0; DUTY_9 = 0;
for (uint256 i = 0; i < params.updates.length; i++) {
IlkDutyUpdate memory upd = params.updates[i];
require(upd.ilk != bytes32(0), "SetDutySpell/empty-ilk");
if (i == 0) { ILK_0 = upd.ilk; DUTY_0 = upd.duty; }
else if (i == 1) { ILK_1 = upd.ilk; DUTY_1 = upd.duty; }
else if (i == 2) { ILK_2 = upd.ilk; DUTY_2 = upd.duty; }
else if (i == 3) { ILK_3 = upd.ilk; DUTY_3 = upd.duty; }
else if (i == 4) { ILK_4 = upd.ilk; DUTY_4 = upd.duty; }
else if (i == 5) { ILK_5 = upd.ilk; DUTY_5 = upd.duty; }
else if (i == 6) { ILK_6 = upd.ilk; DUTY_6 = upd.duty; }
else if (i == 7) { ILK_7 = upd.ilk; DUTY_7 = upd.duty; }
else if (i == 8) { ILK_8 = upd.ilk; DUTY_8 = upd.duty; }
else if (i == 9) { ILK_9 = upd.ilk; DUTY_9 = upd.duty; }
}
emit SpellExecuted(params.jug, params.updates.length);
}
/// @notice Execute duty updates
/// @dev No re-execution guard needed: Jug.file() with same duty is idempotent.
/// Each proposal deploys a fresh spell instance anyway.
function execute() external {
uint256 count = COUNT;
for (uint256 i = 0; i < count; i++) {
bytes32 ilk;
uint256 duty;
if (i == 0) { ilk = ILK_0; duty = DUTY_0; }
else if (i == 1) { ilk = ILK_1; duty = DUTY_1; }
else if (i == 2) { ilk = ILK_2; duty = DUTY_2; }
else if (i == 3) { ilk = ILK_3; duty = DUTY_3; }
else if (i == 4) { ilk = ILK_4; duty = DUTY_4; }
else if (i == 5) { ilk = ILK_5; duty = DUTY_5; }
else if (i == 6) { ilk = ILK_6; duty = DUTY_6; }
else if (i == 7) { ilk = ILK_7; duty = DUTY_7; }
else if (i == 8) { ilk = ILK_8; duty = DUTY_8; }
else { ilk = ILK_9; duty = DUTY_9; }
require(ilk != bytes32(0), "SetDutySpell/empty-ilk");
// Phase 1: Drip at current rate
try JugLike(JUG).drip(ilk) returns (uint256 vatRate) {
emit DripBeforeSet(ilk, vatRate);
} catch {
// Safe to continue - drip can fail harmlessly
}
// Phase 2: Read old duty for events
(uint256 oldDuty, ) = JugLike(JUG).ilks(ilk);
// Phase 3: Set new duty
JugLike(JUG).file(ilk, "duty", duty);
emit DutyUpdated(ilk, oldDuty, duty);
}
}
/// @notice Get ilk state from Jug
function getIlkState(bytes32 ilk) external view returns (uint256 duty, uint256 rho) {
return JugLike(JUG).ilks(ilk);
}
/// @notice Get all updates
function getAllUpdates() external view returns (
bytes32[10] memory ilks,
uint256[10] memory duties,
uint256 count
) {
ilks[0] = ILK_0; duties[0] = DUTY_0;
ilks[1] = ILK_1; duties[1] = DUTY_1;
ilks[2] = ILK_2; duties[2] = DUTY_2;
ilks[3] = ILK_3; duties[3] = DUTY_3;
ilks[4] = ILK_4; duties[4] = DUTY_4;
ilks[5] = ILK_5; duties[5] = DUTY_5;
ilks[6] = ILK_6; duties[6] = DUTY_6;
ilks[7] = ILK_7; duties[7] = DUTY_7;
ilks[8] = ILK_8; duties[8] = DUTY_8;
ilks[9] = ILK_9; duties[9] = DUTY_9;
count = COUNT;
}
}