wp-evm-algebra-interfaces 0.1.10

sol!-generated bindings for Algebra V1.9 protocol interfaces
Documentation
//! Algebra custom-pool-deployer NFPM read ABI — 12-field `positions()` that
//! includes the per-position `deployer` (Blackhole and other custom-deployer
//! Algebra forks). Distinct from the 11-field `nfpm::IAlgebraNonfungiblePositionManager`
//! (QuickSwap) — both share selector 0x99fbab88, so decoding a 12-field return
//! with the 11-field codec silently misaligns every field after `token1`.

use alloy_sol_types::sol;

sol! {
    interface IAlgebraCustomDeployerNfpm {
        function positions(uint256 tokenId) external view returns (
            uint88 nonce,
            address operator,
            address token0,
            address token1,
            address deployer,
            int24 tickLower,
            int24 tickUpper,
            uint128 liquidity,
            uint256 feeGrowthInside0LastX128,
            uint256 feeGrowthInside1LastX128,
            uint128 tokensOwed0,
            uint128 tokensOwed1
        );
        function ownerOf(uint256 tokenId) external view returns (address);
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use alloy_primitives::{address, aliases::U88, U256};
    use alloy_sol_types::SolCall;

    #[test]
    fn positions_selector_is_shared_99fbab88() {
        // Same selector as the 11-field NFPM (the args are identical `uint256`);
        // the difference is the RETURN shape, which the decode-lock below guards.
        assert_eq!(IAlgebraCustomDeployerNfpm::positionsCall::SELECTOR, [0x99, 0xfb, 0xab, 0x88]);
    }

    /// 12-field decode lock with a NON-ZERO `deployer` and NON-ZERO `tokensOwed`,
    /// so the test is NOT blind to an 11-vs-12 field misalignment (a zero deployer
    /// would also decode as zero under the wrong codec). Encode a known return,
    /// decode with the 12-field codec, and assert the 11-field codec MISALIGNS.
    #[test]
    fn twelve_field_return_decodes_with_deployer_at_slot4() {
        use crate::periphery::nfpm::IAlgebraNonfungiblePositionManager as Eleven;

        let token0 = address!("2222222222222222222222222222222222222222");
        let token1 = address!("3333333333333333333333333333333333333333");
        let deployer = address!("5D433A94A4a2aA8f9AA34D8D15692Dc2E9960584"); // non-zero
        let ret = IAlgebraCustomDeployerNfpm::positionsReturn {
            nonce: U88::from(7u64),
            operator: address!("1111111111111111111111111111111111111111"),
            token0,
            token1,
            deployer,
            tickLower: alloy_primitives::aliases::I24::try_from(-180i32).unwrap(),
            tickUpper: alloy_primitives::aliases::I24::try_from(180i32).unwrap(),
            liquidity: 32_339_078u128,
            feeGrowthInside0LastX128: U256::from(111u64),
            feeGrowthInside1LastX128: U256::from(222u64),
            tokensOwed0: 1000u128, // non-zero
            tokensOwed1: 2000u128, // non-zero
        };
        let bytes = IAlgebraCustomDeployerNfpm::positionsCall::abi_encode_returns(&ret);

        // 12-field codec: deployer + tokensOwed read correctly.
        let d12 = IAlgebraCustomDeployerNfpm::positionsCall::abi_decode_returns(&bytes).unwrap();
        assert_eq!(d12.deployer, deployer);
        assert_eq!(d12.token0, token0);
        assert_eq!(d12.token1, token1);
        assert_eq!(d12.tokensOwed0, 1000u128);
        assert_eq!(d12.tokensOwed1, 2000u128);

        // 11-field codec on the SAME bytes: token0/token1 occupy slots 2/3 in BOTH
        // tuples, so they decode the same; the divergence starts at the `deployer`
        // slot (word 4). The 11-field codec reads word 10 as tokensOwed1, which is
        // the 12-field's tokensOwed0 (1000), not 2000 — the misalignment guard.
        let d11 = Eleven::positionsCall::abi_decode_returns(&bytes).unwrap();
        assert_eq!(d11.token0, token0); // slots 2/3 coincide
        assert_eq!(d11.token1, token1);
        assert_ne!(
            d11.tokensOwed1, d12.tokensOwed1,
            "11-field codec must misalign from the deployer slot onward"
        );
        assert_eq!(
            d11.tokensOwed1, d12.tokensOwed0,
            "11-field tokensOwed1 reads the 12-field tokensOwed0 slot (off-by-one shift)"
        );
    }
}