Skip to main content
PulseScanner.io

Address

0xbb39b48c2cbb2a552009ea7da94dff8fc77f7bf8
Current 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;
    }
}