import { getAddressDecoder } from '@solana/kit';
import { assert } from '@hyperlane-xyz/utils';
import { decodeAccountData, decodeDiscriminatorPrefixed, } from '../codecs/account-data.js';
import { ByteCursor } from '../codecs/binary.js';
import { decodeMapU32GasOracle, decodeMapU32H256, decodeMapU32U64, InterchainGasPaymasterTypeKind, } from '../codecs/shared.js';
const IGP_PROGRAM_DATA_DISCRIMINATOR = ascii8('PRGMDATA');
const IGP_ACCOUNT_DISCRIMINATOR = ascii8('IGP_____');
const OVERHEAD_IGP_ACCOUNT_DISCRIMINATOR = ascii8('OVRHDIGP');
export function decodeHyperlaneTokenAccount(raw) {
    const wrapped = decodeAccountData(raw, decodeHyperlaneTokenInner);
    return wrapped.data;
}
export function decodeIgpProgramDataAccount(raw) {
    const wrapped = decodeAccountData(raw, (cursor) => decodeDiscriminatorPrefixed(cursor, IGP_PROGRAM_DATA_DISCRIMINATOR, (c) => ({
        bumpSeed: c.readU8(),
        paymentCount: c.readU64LE(),
    })));
    return wrapped.data;
}
export function decodeIgpAccount(raw) {
    const wrapped = decodeAccountData(raw, (cursor) => decodeDiscriminatorPrefixed(cursor, IGP_ACCOUNT_DISCRIMINATOR, (c) => ({
        bumpSeed: c.readU8(),
        salt: c.readBytes(32),
        owner: readOptionAddress(c),
        beneficiary: readAddress(c),
        gasOracles: decodeMapU32GasOracle(c),
    })));
    return wrapped.data;
}
export function decodeOverheadIgpAccount(raw) {
    const wrapped = decodeAccountData(raw, (cursor) => decodeDiscriminatorPrefixed(cursor, OVERHEAD_IGP_ACCOUNT_DISCRIMINATOR, (c) => ({
        bumpSeed: c.readU8(),
        salt: c.readBytes(32),
        owner: readOptionAddress(c),
        inner: readAddress(c),
        gasOverheads: decodeMapU32U64(c),
    })));
    return wrapped.data;
}
function decodeHyperlaneTokenInner(cursor) {
    // Kept manual because payload ends with trailing pluginData (remainder bytes).
    const bump = cursor.readU8();
    const mailbox = readAddress(cursor);
    const mailboxProcessAuthority = readAddress(cursor);
    const dispatchAuthorityBump = cursor.readU8();
    const decimals = cursor.readU8();
    const remoteDecimals = cursor.readU8();
    const owner = readOptionAddress(cursor);
    const interchainSecurityModule = readOptionAddress(cursor);
    const interchainGasPaymaster = readOptionIgpConfig(cursor);
    const destinationGas = decodeMapU32U64(cursor);
    const remoteRouters = decodeMapU32H256(cursor);
    const pluginData = cursor.readBytes(cursor.remaining());
    return {
        bump,
        mailbox,
        mailboxProcessAuthority,
        dispatchAuthorityBump,
        decimals,
        remoteDecimals,
        owner,
        interchainSecurityModule,
        interchainGasPaymaster,
        destinationGas,
        remoteRouters,
        pluginData,
    };
}
export function decodeNativePlugin(pluginData) {
    if (pluginData.length < 1)
        throw new Error(`NativePlugin: need 1 byte, got ${pluginData.length}`);
    return { nativeCollateralBump: pluginData[0] };
}
export function decodeSyntheticPlugin(pluginData) {
    if (pluginData.length < 34)
        throw new Error(`SyntheticPlugin: need 34 bytes, got ${pluginData.length}`);
    const cursor = new ByteCursor(pluginData);
    return {
        mint: readAddress(cursor),
        mintBump: cursor.readU8(),
        ataPayerBump: cursor.readU8(),
    };
}
export function decodeCollateralPlugin(pluginData) {
    if (pluginData.length < 98)
        throw new Error(`CollateralPlugin: need 98 bytes, got ${pluginData.length}`);
    const cursor = new ByteCursor(pluginData);
    return {
        splTokenProgram: readAddress(cursor),
        mint: readAddress(cursor),
        escrow: readAddress(cursor),
        escrowBump: cursor.readU8(),
        ataPayerBump: cursor.readU8(),
    };
}
function ascii8(value) {
    if (value.length !== 8)
        throw new Error(`Expected 8-char discriminator, got ${value}`);
    return Uint8Array.from(value, (char) => char.charCodeAt(0));
}
const addressDecoder = getAddressDecoder();
function readAddress(cursor) {
    return addressDecoder.decode(cursor.readBytes(32));
}
function readOptionAddress(cursor) {
    const tag = cursor.readU8();
    assert(tag === 0 || tag === 1, `Invalid option tag: ${tag}`);
    return tag === 1 ? readAddress(cursor) : null;
}
function readOptionIgpConfig(cursor) {
    const tag = cursor.readU8();
    assert(tag === 0 || tag === 1, `Invalid option tag: ${tag}`);
    if (tag === 0)
        return null;
    const programId = readAddress(cursor);
    const igpKindByte = cursor.readU8();
    assert(igpKindByte === InterchainGasPaymasterTypeKind.Igp ||
        igpKindByte === InterchainGasPaymasterTypeKind.OverheadIgp, `Unknown InterchainGasPaymasterType kind: ${igpKindByte}`);
    return {
        programId,
        igpType: {
            kind: igpKindByte,
            account: readAddress(cursor),
        },
    };
}
//# sourceMappingURL=token.js.map