ido: sync IdoParams commitment to 127-byte layout, enforce NFT-pinned min PLP
libriften 0941c88 grew the ORB IdoParams NFT commitment 121->127 bytes, inserting minPlpAfterDiscount/minPlpShare (4-byte pIntLE numerators over PERMANENT_LIQUIDITY_SHARE_DENOMINATOR) between maxExpireDuration and entryExecutionFee, and shrinking paramsUseFee 4->2 bytes. - Parse the two new fields; shift entryExecutionFee/createExecutionFee offsets. - Drop the hardcoded MIN_PLP_SHARE / MIN_PLP_AFTER_DISCOUNT statics; enforce both minimums from the NFT commitment inside the version-verified block (permanentLiquidityShareNumerator >= minPlpShare, and maxDiscountRateNumerator + minPlpAfterDiscount <= permanentLiquidityShareNumerator). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
8967e115e9
commit
4b5fd93db4
1 changed files with 36 additions and 23 deletions
|
|
@ -70,11 +70,12 @@ const OFFERING_ENTRY_FLAG_XWNT: u8 = 0x20; // exchange with native token (legacy
|
||||||
static PERMANENT_LIQUIDITY_SHARE_DENOMINATOR: LazyLock<Integer> =
|
static PERMANENT_LIQUIDITY_SHARE_DENOMINATOR: LazyLock<Integer> =
|
||||||
LazyLock::new(|| Integer::from(100_000_000i64));
|
LazyLock::new(|| Integer::from(100_000_000i64));
|
||||||
|
|
||||||
static MIN_PLP_SHARE: LazyLock<Integer> = LazyLock::new(|| Integer::from(20_000_000i64)); // 20%
|
|
||||||
static MAX_PLP_SHARE: LazyLock<Integer> = LazyLock::new(|| Integer::from(80_000_000i64)); // 80%
|
static MAX_PLP_SHARE: LazyLock<Integer> = LazyLock::new(|| Integer::from(80_000_000i64)); // 80%
|
||||||
static MAX_PLP_ANNUAL_DISCOUNT: LazyLock<Integer> = LazyLock::new(|| Integer::from(10_000_000i64)); // 10%
|
static MAX_PLP_ANNUAL_DISCOUNT: LazyLock<Integer> = LazyLock::new(|| Integer::from(10_000_000i64)); // 10%
|
||||||
static MIN_PLP_ANNUAL_DISCOUNT: LazyLock<Integer> = LazyLock::new(|| Integer::from(0i64)); // 0%
|
static MIN_PLP_ANNUAL_DISCOUNT: LazyLock<Integer> = LazyLock::new(|| Integer::from(0i64)); // 0%
|
||||||
static MIN_PLP_AFTER_DISCOUNT: LazyLock<Integer> = LazyLock::new(|| Integer::from(5_000_000i64)); // 5%
|
// The minimum PLP share and minimum PLP-after-discount are no longer hardcoded:
|
||||||
|
// they are pinned per-IdoParams NFT (minPlpShare / minPlpAfterDiscount, numerators
|
||||||
|
// over PERMANENT_LIQUIDITY_SHARE_DENOMINATOR) and enforced against the offering.
|
||||||
|
|
||||||
// The ORB IdoParams NFT category (display byte order, like a token id). Every
|
// The ORB IdoParams NFT category (display byte order, like a token id). Every
|
||||||
// preinit must include this NFT (input #1, preserved at output #10); its
|
// preinit must include this NFT (input #1, preserved at output #10); its
|
||||||
|
|
@ -141,7 +142,7 @@ static REBUILD_IPFS_PLACEHOLDER_BCMR_FOR_GENESIS_WITH_AUTHGUARD_CONTRACT: LazyLo
|
||||||
hex::decode("0902a9147ca97e01877e57897c6b00c08851d100887c635ab2756d51cd016a88674d0301404142434445464748494a4b4c4d4e4f505152535455565758595a6162636465666768696a6b6c6d6e6f707172737475767778797a303132333435363738392d5f6b007c8253a26365537f7c76011299527f77816c766b7c7f77517f75785c99527f77013f84816c766b7c7f77517f757e785699527f77013f84816c766b7c7f77517f757e7c527f77013f84816c766b7c7f77517f757e7b7c7e7c82539f666882760087636d677d537c94007c807e76011299527f77816c766b7c7f77517f75785c99527f77013f84816c766b7c7f77517f757e785699527f77013f84816c766b7c7f77517f757e7c527f77013f84816c766b7c7f77517f757e7c51937f757e686c7554893a10303132333435363738396162636465667c006b65517f7c5279785f84817f77517f756c7e6b52797c5499817f77517f756c7e6b82009c666d6c5689097f7b827b7c7f777e7e538978a8886b518ac0ce568a65766c537a538a6b74519c66756c766ba804015512207c7e548a01757c7e6b528a6c7c6b65766c537a538a6b74519c66756c6ca87c7e076a0442434d52207c7e51cd886801206c0f51ce8851d0009d6300cdc0c78868517e7e578a00cd8800ce00d18800d2008800d000d38800c600cca26952d10088c45387").unwrap()
|
hex::decode("0902a9147ca97e01877e57897c6b00c08851d100887c635ab2756d51cd016a88674d0301404142434445464748494a4b4c4d4e4f505152535455565758595a6162636465666768696a6b6c6d6e6f707172737475767778797a303132333435363738392d5f6b007c8253a26365537f7c76011299527f77816c766b7c7f77517f75785c99527f77013f84816c766b7c7f77517f757e785699527f77013f84816c766b7c7f77517f757e7c527f77013f84816c766b7c7f77517f757e7b7c7e7c82539f666882760087636d677d537c94007c807e76011299527f77816c766b7c7f77517f75785c99527f77013f84816c766b7c7f77517f757e785699527f77013f84816c766b7c7f77517f757e7c527f77013f84816c766b7c7f77517f757e7c51937f757e686c7554893a10303132333435363738396162636465667c006b65517f7c5279785f84817f77517f756c7e6b52797c5499817f77517f756c7e6b82009c666d6c5689097f7b827b7c7f777e7e538978a8886b518ac0ce568a65766c537a538a6b74519c66756c766ba804015512207c7e548a01757c7e6b528a6c7c6b65766c537a538a6b74519c66756c6ca87c7e076a0442434d52207c7e51cd886801206c0f51ce8851d0009d6300cdc0c78868517e7e578a00cd8800ce00d18800d2008800d000d38800c600cca26952d10088c45387").unwrap()
|
||||||
});
|
});
|
||||||
|
|
||||||
/// The 121-byte commitment of the ORB IdoParams NFT (libriften
|
/// The 127-byte commitment of the ORB IdoParams NFT (libriften
|
||||||
/// packages/cauldron/src/orb/v0). Byte layout:
|
/// packages/cauldron/src/orb/v0). Byte layout:
|
||||||
/// [0] version (must equal IDO_PARAMS_VERSION)
|
/// [0] version (must equal IDO_PARAMS_VERSION)
|
||||||
/// [1..33] orbPoolParamsCategory
|
/// [1..33] orbPoolParamsCategory
|
||||||
|
|
@ -150,12 +151,14 @@ static REBUILD_IPFS_PLACEHOLDER_BCMR_FOR_GENESIS_WITH_AUTHGUARD_CONTRACT: LazyLo
|
||||||
/// [97..101] platformFee (pIntLE, raw-equal to platformFeeNumerator)
|
/// [97..101] platformFee (pIntLE, raw-equal to platformFeeNumerator)
|
||||||
/// [101..105] minExpireDuration (pIntLE, seconds)
|
/// [101..105] minExpireDuration (pIntLE, seconds)
|
||||||
/// [105..109] maxExpireDuration (pIntLE, seconds)
|
/// [105..109] maxExpireDuration (pIntLE, seconds)
|
||||||
/// [109..113] entryExecutionFee (pIntLE, sats)
|
/// [109..113] minPlpAfterDiscount (pIntLE, numerator / PERMANENT_LIQUIDITY_SHARE_DENOMINATOR)
|
||||||
/// [113..117] createExecutionFee (pIntLE, sats)
|
/// [113..117] minPlpShare (pIntLE, numerator / PERMANENT_LIQUIDITY_SHARE_DENOMINATOR)
|
||||||
/// [117..121] paramsUseFee (pIntLE, sats)
|
/// [117..121] entryExecutionFee (pIntLE, sats)
|
||||||
|
/// [121..125] createExecutionFee (pIntLE, sats)
|
||||||
|
/// [125..127] paramsUseFee (pIntLE, sats/100 — not parsed here)
|
||||||
/// Categories and the nfth are stored in the same byte order the announcement
|
/// Categories and the nfth are stored in the same byte order the announcement
|
||||||
/// uses, so equality checks against announced parameters are direct compares.
|
/// uses, so equality checks against announced parameters are direct compares.
|
||||||
const IDO_PARAMS_COMMITMENT_SIZE: usize = 121;
|
const IDO_PARAMS_COMMITMENT_SIZE: usize = 127;
|
||||||
|
|
||||||
/// The only ORB IdoParams NFT commitment version this indexer understands
|
/// The only ORB IdoParams NFT commitment version this indexer understands
|
||||||
/// (libriften `ORB_IDO_PARAMS_VERSION`). Any other value means the params NFT
|
/// (libriften `ORB_IDO_PARAMS_VERSION`). Any other value means the params NFT
|
||||||
|
|
@ -170,6 +173,8 @@ pub struct IdoParamsNftCommitment {
|
||||||
pub platformFee: Integer,
|
pub platformFee: Integer,
|
||||||
pub minExpireDuration: Integer,
|
pub minExpireDuration: Integer,
|
||||||
pub maxExpireDuration: Integer,
|
pub maxExpireDuration: Integer,
|
||||||
|
pub minPlpAfterDiscount: Integer,
|
||||||
|
pub minPlpShare: Integer,
|
||||||
pub entryExecutionFee: Integer,
|
pub entryExecutionFee: Integer,
|
||||||
pub createExecutionFee: Integer,
|
pub createExecutionFee: Integer,
|
||||||
}
|
}
|
||||||
|
|
@ -190,8 +195,10 @@ fn parse_ido_params_nft_commitment(commitment: &[u8]) -> Result<IdoParamsNftComm
|
||||||
platformFee: vm_number_to_bigint(&commitment[97..101]),
|
platformFee: vm_number_to_bigint(&commitment[97..101]),
|
||||||
minExpireDuration: vm_number_to_bigint(&commitment[101..105]),
|
minExpireDuration: vm_number_to_bigint(&commitment[101..105]),
|
||||||
maxExpireDuration: vm_number_to_bigint(&commitment[105..109]),
|
maxExpireDuration: vm_number_to_bigint(&commitment[105..109]),
|
||||||
entryExecutionFee: vm_number_to_bigint(&commitment[109..113]),
|
minPlpAfterDiscount: vm_number_to_bigint(&commitment[109..113]),
|
||||||
createExecutionFee: vm_number_to_bigint(&commitment[113..117]),
|
minPlpShare: vm_number_to_bigint(&commitment[113..117]),
|
||||||
|
entryExecutionFee: vm_number_to_bigint(&commitment[117..121]),
|
||||||
|
createExecutionFee: vm_number_to_bigint(&commitment[121..125]),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1566,13 +1573,6 @@ fn parse_ido_preinit_tx_params(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if preinit_parameters.permanentLiquidityShareNumerator < *MIN_PLP_SHARE {
|
|
||||||
invalid_ido_reasons.push(anyhow::anyhow!(
|
|
||||||
"preinit_parameters.permanentLiquidityShareNumerator < *MIN_PLP_SHARE"
|
|
||||||
));
|
|
||||||
is_valid_ido = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if preinit_parameters.permanentLiquidityShareNumerator > *MAX_PLP_SHARE {
|
if preinit_parameters.permanentLiquidityShareNumerator > *MAX_PLP_SHARE {
|
||||||
invalid_ido_reasons.push(anyhow::anyhow!(
|
invalid_ido_reasons.push(anyhow::anyhow!(
|
||||||
"preinit_parameters.permanentLiquidityShareNumerator > *MAX_PLP_SHARE"
|
"preinit_parameters.permanentLiquidityShareNumerator > *MAX_PLP_SHARE"
|
||||||
|
|
@ -1602,13 +1602,6 @@ fn parse_ido_preinit_tx_params(
|
||||||
invalid_ido_reasons.push(anyhow::anyhow!("preinit_parameters.offering.offer.maxDiscountRateNumerator < Integer::from(0)"));
|
invalid_ido_reasons.push(anyhow::anyhow!("preinit_parameters.offering.offer.maxDiscountRateNumerator < Integer::from(0)"));
|
||||||
is_valid_ido = false;
|
is_valid_ido = false;
|
||||||
}
|
}
|
||||||
if &preinit_parameters.offering.offer.maxDiscountRateNumerator
|
|
||||||
+ &MIN_PLP_AFTER_DISCOUNT.clone()
|
|
||||||
> preinit_parameters.permanentLiquidityShareNumerator
|
|
||||||
{
|
|
||||||
invalid_ido_reasons.push(anyhow::anyhow!("preinit_parameters.offering.offer.maxDiscountRateNumerator + MIN_PLP_AFTER_DISCOUNT > preinit_parameters.permanentLiquidityShareNumerator"));
|
|
||||||
is_valid_ido = false;
|
|
||||||
}
|
|
||||||
if preinit_parameters.offeredTokenAmount <= 0 {
|
if preinit_parameters.offeredTokenAmount <= 0 {
|
||||||
invalid_ido_reasons.push(anyhow::anyhow!(
|
invalid_ido_reasons.push(anyhow::anyhow!(
|
||||||
"preinit_parameters.offeredTokenAmount <= Integer::from(0)"
|
"preinit_parameters.offeredTokenAmount <= Integer::from(0)"
|
||||||
|
|
@ -1698,6 +1691,26 @@ fn parse_ido_preinit_tx_params(
|
||||||
));
|
));
|
||||||
is_valid_ido = false;
|
is_valid_ido = false;
|
||||||
}
|
}
|
||||||
|
// The permanent-liquidity minimums are pinned by the IdoParams
|
||||||
|
// NFT (numerators over PERMANENT_LIQUIDITY_SHARE_DENOMINATOR,
|
||||||
|
// directly comparable to permanentLiquidityShareNumerator).
|
||||||
|
if preinit_parameters.permanentLiquidityShareNumerator
|
||||||
|
< ido_params.minPlpShare
|
||||||
|
{
|
||||||
|
invalid_ido_reasons.push(anyhow::anyhow!(
|
||||||
|
"preinit_parameters.permanentLiquidityShareNumerator < ido_params.minPlpShare"
|
||||||
|
));
|
||||||
|
is_valid_ido = false;
|
||||||
|
}
|
||||||
|
if &preinit_parameters.offering.offer.maxDiscountRateNumerator
|
||||||
|
+ &ido_params.minPlpAfterDiscount
|
||||||
|
> preinit_parameters.permanentLiquidityShareNumerator
|
||||||
|
{
|
||||||
|
invalid_ido_reasons.push(anyhow::anyhow!(
|
||||||
|
"preinit_parameters.offering.offer.maxDiscountRateNumerator + ido_params.minPlpAfterDiscount > preinit_parameters.permanentLiquidityShareNumerator"
|
||||||
|
));
|
||||||
|
is_valid_ido = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue