ido more fixes +two unittests
This commit is contained in:
parent
a944db4702
commit
c4eaad4cec
2 changed files with 177 additions and 71 deletions
|
|
@ -10,7 +10,7 @@ use bitcoin_hashes::sha256d;
|
|||
//use bitcoin_hashes::hash160;
|
||||
use bitcoin_hashes::Hash;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_with::serde_as;
|
||||
use serde_with::{serde_as, DisplayFromStr};
|
||||
use bitcoincash::blockdata::transaction::Transaction;
|
||||
use bitcoincash::{Txid, BlockHash, TokenID, Network};
|
||||
use std::sync::LazyLock;
|
||||
|
|
@ -56,12 +56,22 @@ static MIN_PLP_AFTER_DISCOUNT: LazyLock<BigInt> = LazyLock::new(|| BigInt::from(
|
|||
static ENTRY_EXECUTION_FEE: LazyLock<BigInt> = LazyLock::new(|| BigInt::from(10000i64)); // 10k sats
|
||||
static IDO_CREATE_EXECUTION_FEE: LazyLock<BigInt> = LazyLock::new(|| BigInt::from(30000i64)); // 30k sats
|
||||
static PLATFORM_FEE: LazyLock<BigInt> = LazyLock::new(|| BigInt::from(10_000_000i64)); // 10%
|
||||
const DELPHI_TOKEN_ID: &[u8; 32] = &[
|
||||
0xd0, 0xd4, 0x6f, 0x5c, 0xbd, 0x82, 0x18, 0x8a, 0xce,
|
||||
0xde, 0x0d, 0x3e, 0x49, 0xc7, 0x57, 0x00, 0xc1, 0x9c,
|
||||
0xb8, 0x33, 0x1a, 0x30, 0x10, 0x1f, 0x0b, 0xb6, 0xa2,
|
||||
0x60, 0x06, 0x6a, 0xc9, 0x72
|
||||
|
||||
|
||||
const CHIPNET_DELPHI_TOKEN_ID: &[u8; 32] = &[
|
||||
0x1b, 0x94, 0x82, 0x40, 0xc9, 0xcf, 0xaa, 0x82, 0x24,
|
||||
0x38, 0x3d, 0xb1, 0x6e, 0x47, 0x35, 0xef, 0xa0, 0x9c,
|
||||
0x94, 0x26, 0xd1, 0x71, 0x3d, 0x26, 0x5e, 0x84, 0x9a,
|
||||
0x8e, 0x91, 0xf2, 0x66, 0x9a
|
||||
];
|
||||
const MAINNET_DELPHI_TOKEN_ID: &[u8; 32] = &[
|
||||
0xbe, 0x0d, 0x0d, 0x83, 0x24, 0xe8, 0xcd, 0xa4, 0x1d,
|
||||
0x34, 0xb8, 0x5b, 0xd2, 0x03, 0xce, 0x24, 0x82, 0x25,
|
||||
0x6e, 0xb3, 0x37, 0xa0, 0xad, 0x0f, 0xea, 0x82, 0xc2,
|
||||
0xdd, 0xd7, 0x30, 0x6c, 0x88
|
||||
];
|
||||
|
||||
|
||||
// TODO:: set the platform fee nfth
|
||||
const CHIPNET_PLATFORM_FEE_NFTH: &[u8; 32] = &[
|
||||
0x07, 0x2d, 0x5f, 0xbe, 0xcf, 0xa1, 0xbc, 0x37,
|
||||
|
|
@ -88,7 +98,7 @@ static DISTRIBUTOR_DEPLOY_CONTRACT: LazyLock<Vec<u8>> = LazyLock::new(|| hex::de
|
|||
static DISTRIBUTOR_REFUND_CONTRACT: LazyLock<Vec<u8>> = LazyLock::new(|| hex::decode("c0009d00ce01207f7551ce01207f75788851cf517f755f84538851ca51ca82770136940120947f7701207f7551cf517f75760120840100876451cc51c6a26951d100886751d352d09d51d152ce886802aa200120537a7e55797eaa7e01877e51cd8800cf577f77547f75817651a06300cf517f7500cf517f77567f757e788c54807e00cf5b7f77587f757e00cf01137f77587f757e00cf011b7f77587f757e00d28800ce00d18800c700cd88c4529e6352d10088c4539d686755608500cf517f77567f757e00cf5b7f77587f757e00cf01137f77587f757e00cf011b7f77587f757e00d288527900d18800d3009d02aa20012055797e56797eaa7e01877e00cd8852d100885352790120840100876475526876ce54798876cf517f755f845488c4539e6353d10088c4549d6875686d6d7551").unwrap());
|
||||
static EXECUTION_FEE_PAYOUT_CONTRACT: LazyLock<Vec<u8>> = LazyLock::new(|| hex::decode("c0ce00ce01207f758800cf517f755f84528800cf577f77547f758151a169c0cf517f7701207f7502aa2001207b7e7b7eaa7e01877e52cd8852ccc0c6a2").unwrap());
|
||||
static OFFERING_INITIATOR_CONTRACT: LazyLock<Vec<u8>> = LazyLock::new(|| hex::decode("c0c9009dc0c85b79c8885a79c9577a9d5979ce827701209d567900a263c0c85b79c8885a79c957799d68c0c800d1788800d2578800d3009d00cd5a7a88c08bc0c878c88876c9547a9d76ca827778ca7853947f77527f75817bca7b53945279947f777c7f75c05293c0c878c88876c9557a9d76ca827778ca7853947f77527f75817bca7b53945279947f777c7f75c05393c0c878c88876c9567a9d76ca827778ca7853947f77527f75815178529302ff00a063755367785293014ba063755268685379ca537a5394537a947b947f7702aa20525352807e5b797e7b7eaa7e01877e54cd8854cc7cc6a26954d10088c05493c0c878c88876c9567a9d76ca827778ca7853947f77527f75815178529302ff00a063755367785293014ba063755268685379ca537a5394537a947b947f7702aa20525352807e5a797e7b7eaa7e01877e55cd8855cc7cc6a26955d100885779d07600a0690100557a7e04000000007e51d28851d15479527e8851d3789d51cd02aa20547aaa7e01877e885153d28853d153798853d3009d53cd02aa20537aaa7e01877e8802aa20525352807e567a7eaa7e01877e52cd8852cc5579c6a26952d1557ace8852d39d52d20088c05593c0c878c88876c9537a9d76c7827778c77853947f77527f75817bc77b53945279947f777c7f7576827700a06376517f75768176014b9f788b547982779f9a635279788b7f77537a757c6b7c6c5279517f757b757c6878016a8764016a537a757c6b7c6c686d67016a776856cd8856d1008857d100876457d101207f75788791696857cd567f75066a0442434d52879169c4589e6358d100876458d101207f75788791696858cd567f75066a0442434d52879169c4599e6359d100876459d101207f75788791696859cd567f75066a0442434d52879169c45a9e635ad10087645ad101207f7578879169685acd567f75066a0442434d52879169c45b9e635bd10087645bd101207f7578879169685bcd567f75066a0442434d52879169c45c9d686868686d7551").unwrap());
|
||||
static OFFERING_INTEGRATED_TIMELOCKED_P2NFTH_CONTRACT: LazyLock<Vec<u8>> = LazyLock::new(|| hex::decode("c0cf527f7701207f75c0cf01227f77815479ce01207f757b88537acf567f75817600a0699f6978ce7bcf7eaa88c0cf517f77517f7581c0c85279c8887cc99cs").unwrap());
|
||||
static OFFERING_INTEGRATED_TIMELOCKED_P2NFTH_CONTRACT: LazyLock<Vec<u8>> = LazyLock::new(|| hex::decode("c0cf527f7701207f75c0cf01227f77815479ce01207f757b88537acf567f75817600a0699f6978ce7bcf7eaa88c0cf517f77517f7581c0c85279c8887cc99c").unwrap());
|
||||
|
||||
static IDO_INITIATOR_CONTRACT: LazyLock<Vec<u8>> = LazyLock::new(|| hex::decode("c0ce827701209dc0cf827700a0695579827701209dc0c85779c8885679c99dc0c85779c8885679c99d5479529376ca827778ca7853947f77527f75817bca7b53945279947f777c7f7501157f7701207f75c0cec0cf7eaa88547ac852d1827701209d52d300a06902aa20c101147f755479827751807e54797e5379827751807e537a7e01207e7b7e01207e52d17e01207e547a7e587e52d358807e537a7eaa7e01877e57cd8857ccc0c6a26957d1c0ce8857d2c0cf8857d3c0d09d02aa20525752807e7b7eaa7e01877e7658cd8858cc02e803a26958d1008859cd8859cc78c6a26959d178ce8859d278cf8859d37cd09c").unwrap());
|
||||
static IDO_POSTLAUNCH_CONTRACT: LazyLock<Vec<u8>> = LazyLock::new(|| hex::decode("5879009c63c0009dc0c9009e69c0cdc0c788c0ccc0c6a269c0d1c0ce88c0d3c0d09dc0d2c0cf8802aa20520052807e597a7eaa7e01877ec0c851c88851c9589d7651cd8851cc51c6a26951d151ce8851d351d09dc0c852c88852c9599d52cd8852cc52c6a26952d152ce8852d352d09dc353a06353ce0088c3549d6853d10088c4549d6d6d6d6d51675879519c63c0009dc0c9009dc0cdc0c788c0d1c0ce88c0d3c0d09dc0d2c0cf88c0c852c88852c9529d52cd52c78852cc52c6a26952d152ce8852d352d09d02aa200120c0cec0cf7eaa7e587a7eaa7e01877e00005376c75479876376ce59798763527978d093537a757c6b7c6c6776ce0088686ec6937b757c6776ce008868768bc378a06376c75579876376ce5a798763537978d093547a757c6b7c6b7c6c6c6776ce008868527978c693537a757c6b7c6c6776ce008868768b77c378a06376c75579876376ce5a798763537978d093547a757c6b7c6b7c6c6c6776ce008868527978c693537a757c6b7c6c6776ce008868768b77c378a06376c75579876376ce5a798763537978d093547a757c6b7c6b7c6c6c6776ce008868527978c693537a757c6b7c6c6776ce008868768b77c378a06376c75579876376ce5a798763537978d093547a757c6b7c6b7c6c6c6776ce008868527978c693537a757c6b7c6c6776ce008868768b77c378a06376c75579876376ce5a798763537978d093547a757c6b7c6b7c6c6c6776ce008868527978c693537a757c6b7c6c6776ce008868768b77c378a06376c75579876376ce5a798763537978d093547a757c6b7c6b7c6c6c6776ce008868527978c693537a757c6b7c6c6776ce008868768b77c378a06376c75579876376ce5a798763537978d093547a757c6b7c6b7c6c6c6776ce008868527978c693537a757c6b7c6c6776ce008868768b77c378a06376c75579876376ce5a798763537978d093547a757c6b7c6b7c6c6c6776ce008868527978c693537a757c6b7c6c6776ce008868768b77c3789d6868686868686868c0ccc0c6547a93a269c0c851c88851c9519d51cd51c78851cc51c6a26951d0537a937600a06351d159798851d378a26951d200886751d100886853d10088c4549d6d6d6d6d6d6d5167587a529dc0009dc0c9009d5379827701209d53ce567a8853cf517f755f845588c0c653cf577f77587f7581a269c0c851c88851c9519d53cf5f7f77587f75817600a06351d078a2696851d000a06351ce5679886851cf0088c0c852c88852c9529d52ce567988000053cf517f75608401008763557981537994765679950400e1f505967652d0a06352d07768765679950500e87648179653cf01177f77587f758194760500e8764817955779967802e803a27800a09a6378567a757c6b7c6b7c6b7c6b7c6c6c6c6c765379a16376557a757c6b7c6b7c6b7c6c6c6c675279557a757c6b7c6b7c6b7c6c6c6c68686d6d68c0c651c69352c69352799451d052d093527994537900a0537900a09a6302aa2005746376a914000114807e2b88ac67c0d1c0ce88c25288c0cdc0c788c0c6c0d095c0c6c0cc9490539502e80396c0cc7c94c0d3957ca2687eaa7e01877e00cd8800cc54799d00d15a798800d353799d00d20088096a0653554d4d4f4e14000114807e51cd8851cc009d51d100886700d1008800cd016a8851d1008851cd016a886802aa2001205a7a7e5b7a7eaa7e01877e52cd8852cc7ba2697600a06352d378a26952d158798852d200886752d100886853d10088c4549d6d6d6d6d75516868").unwrap());
|
||||
|
|
@ -99,6 +109,7 @@ static P2NFTH_CONTRACT: LazyLock<Vec<u8>> = LazyLock::new(|| hex::decode("78ce7b
|
|||
static CASHTOKENS_STUDIO_PAY2CATEGORY_CONTRACT: LazyLock<Vec<u8>> = LazyLock::new(|| hex::decode("51ce8851d0009d6300cdc0c7886851").unwrap());
|
||||
static REBUILD_IPFS_PLACEHOLDER_BCMR_FOR_GENESIS_WITH_AUTHGUARD_CONTRACT: LazyLock<Vec<u8>> = LazyLock::new(|| hex::decode("0902a9147ca97e01877e57897c6b00c08851d100887c635ab2756d51cd016a88674d0301404142434445464748494a4b4c4d4e4f505152535455565758595a6162636465666768696a6b6c6d6e6f707172737475767778797a303132333435363738392d5f6b007c8253a26365537f7c76011299527f77816c766b7c7f77517f75785c99527f77013f84816c766b7c7f77517f757e785699527f77013f84816c766b7c7f77517f757e7c527f77013f84816c766b7c7f77517f757e7b7c7e7c82539f666882760087636d677d537c94007c807e76011299527f77816c766b7c7f77517f75785c99527f77013f84816c766b7c7f77517f757e785699527f77013f84816c766b7c7f77517f757e7c527f77013f84816c766b7c7f77517f757e7c51937f757e686c7554893a10303132333435363738396162636465667c006b65517f7c5279785f84817f77517f756c7e6b52797c5499817f77517f756c7e6b82009c666d6c5689097f7b827b7c7f777e7e538978a8886b518ac0ce568a65766c537a538a6b74519c66756c766ba804015512207c7e548a01757c7e6b528a6c7c6b65766c537a538a6b74519c66756c6ca87c7e076a0442434d52207c7e51cd886801206c0f51ce8851d0009d6300cdc0c78868517e7e578a00cd8800ce00d18800d2008800d000d38800c600cca26952d10088c45387").unwrap());
|
||||
|
||||
|
||||
#[serde_as]
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
pub struct IpfsBcmrWithPlaceholderMetadata {
|
||||
|
|
@ -132,19 +143,27 @@ pub struct IdoPreInitLockParameters {
|
|||
offeredTokenTotalSupply: BigInt,
|
||||
}
|
||||
|
||||
#[serde_as]
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
pub struct IdoParametersOfferingLaunchConditions {
|
||||
#[serde_as(as = "DisplayFromStr")]
|
||||
expiresAt: BigInt,
|
||||
#[serde_as(as = "DisplayFromStr")]
|
||||
deployThreshold: BigInt,
|
||||
#[serde_as(as = "DisplayFromStr")]
|
||||
immediateDeployThreshold: BigInt,
|
||||
}
|
||||
|
||||
#[serde_as]
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
pub struct IdoParametersOfferingOffer {
|
||||
#[serde_as(as = "DisplayFromStr")]
|
||||
maxDiscountRateNumerator: BigInt,
|
||||
#[serde_as(as = "DisplayFromStr")]
|
||||
discountAnnualRateNumerator: BigInt,
|
||||
#[serde_as(as = "DisplayFromStr")]
|
||||
priceNumerator: BigInt,
|
||||
#[serde_as(as = "DisplayFromStr")]
|
||||
minOffer: BigInt,
|
||||
#[serde_as(as = "Option<serde_with::hex::Hex>")]
|
||||
xTokenCategory: Option<Vec<u8>>,
|
||||
|
|
@ -153,6 +172,7 @@ pub struct IdoParametersOfferingOffer {
|
|||
#[serde_as]
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
pub struct IdoParametersOffering {
|
||||
#[serde_as(as = "DisplayFromStr")]
|
||||
platformFeeNumerator: BigInt,
|
||||
#[serde_as(as = "serde_with::hex::Hex")]
|
||||
platformFeeNFTH: Vec<u8>,
|
||||
|
|
@ -160,6 +180,7 @@ pub struct IdoParametersOffering {
|
|||
delphiCategory: Vec<u8>,
|
||||
launchConditions: IdoParametersOfferingLaunchConditions,
|
||||
offer: IdoParametersOfferingOffer,
|
||||
#[serde_as(as = "DisplayFromStr")]
|
||||
executionFee: BigInt,
|
||||
}
|
||||
|
||||
|
|
@ -169,9 +190,13 @@ pub struct IdoPreInitParameters {
|
|||
preInitBcmr: IdoPreInitBcmrParameters,
|
||||
#[serde_as(as = "serde_with::hex::Hex")]
|
||||
authguardLockingBytecode: Vec<u8>,
|
||||
#[serde_as(as = "DisplayFromStr")]
|
||||
authguardNftOutputIndex: BigInt,
|
||||
#[serde_as(as = "DisplayFromStr")]
|
||||
permanentLiquidityShareNumerator: BigInt,
|
||||
#[serde_as(as = "DisplayFromStr")]
|
||||
offeredTokenTotalSupply: BigInt,
|
||||
#[serde_as(as = "DisplayFromStr")]
|
||||
offeredTokenAmount: BigInt,
|
||||
offering: IdoParametersOffering,
|
||||
}
|
||||
|
|
@ -182,7 +207,9 @@ pub struct IdoActiveParameters {
|
|||
preInitBcmr: IdoPreInitBcmrParameters,
|
||||
#[serde_as(as = "serde_with::hex::Hex")]
|
||||
collectorNFTH: Vec<u8>,
|
||||
#[serde_as(as = "DisplayFromStr")]
|
||||
permanentLiquidityShareNumerator: BigInt,
|
||||
#[serde_as(as = "DisplayFromStr")]
|
||||
offeredTokenAmount: BigInt,
|
||||
offering: IdoParametersOffering,
|
||||
}
|
||||
|
|
@ -201,48 +228,74 @@ pub struct IdoPreInitState {
|
|||
authguardCategory: Vec<u8>,
|
||||
#[serde_as(as = "serde_with::hex::Hex")]
|
||||
idoCategory: Vec<u8>,
|
||||
#[serde_as(as = "DisplayFromStr")]
|
||||
nextTxSetterFlag: BigInt,
|
||||
#[serde_as(as = "DisplayFromStr")]
|
||||
oTokenGenerated: BigInt,
|
||||
}
|
||||
|
||||
|
||||
#[serde_as]
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
pub struct IdoActiveState {
|
||||
#[serde_as(as = "DisplayFromStr")]
|
||||
counter: BigInt,
|
||||
}
|
||||
|
||||
#[serde_as]
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
pub struct IdoDistributingState {
|
||||
isRefund: bool,
|
||||
#[serde_as(as = "DisplayFromStr")]
|
||||
timestamp: BigInt,
|
||||
#[serde_as(as = "DisplayFromStr")]
|
||||
counter: BigInt,
|
||||
#[serde_as(as = "DisplayFromStr")]
|
||||
earnedAmount: BigInt,
|
||||
#[serde_as(as = "DisplayFromStr")]
|
||||
refundAmount: BigInt,
|
||||
#[serde_as(as = "DisplayFromStr")]
|
||||
discountAmount: BigInt,
|
||||
#[serde_as(as = "DisplayFromStr")]
|
||||
platformEarnedAmount: BigInt,
|
||||
}
|
||||
|
||||
#[serde_as]
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
pub struct IdoPostLaunchState {
|
||||
isRefund: bool,
|
||||
#[serde_as(as = "DisplayFromStr")]
|
||||
timestamp: BigInt,
|
||||
#[serde_as(as = "DisplayFromStr")]
|
||||
earnedAmount: BigInt,
|
||||
#[serde_as(as = "DisplayFromStr")]
|
||||
refundAmount: BigInt,
|
||||
#[serde_as(as = "DisplayFromStr")]
|
||||
discountAmount: BigInt,
|
||||
#[serde_as(as = "DisplayFromStr")]
|
||||
platformEarnedAmount: BigInt,
|
||||
}
|
||||
|
||||
#[serde_as]
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
pub struct IdoPermanentPoolV0 {
|
||||
#[serde_as(as = "DisplayFromStr")]
|
||||
tokenAmount: BigInt,
|
||||
#[serde_as(as = "DisplayFromStr")]
|
||||
satoshiAmount: BigInt,
|
||||
}
|
||||
|
||||
#[serde_as]
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
pub struct IdoDistributedState {
|
||||
permanentPool: Option<IdoPermanentPoolV0>,
|
||||
#[serde_as(as = "DisplayFromStr")]
|
||||
refundAmount: BigInt,
|
||||
#[serde_as(as = "DisplayFromStr")]
|
||||
discountAmount: BigInt,
|
||||
#[serde_as(as = "DisplayFromStr")]
|
||||
collectorEarnedAmount: BigInt,
|
||||
#[serde_as(as = "DisplayFromStr")]
|
||||
platformEarnedAmount: BigInt,
|
||||
}
|
||||
|
||||
|
|
@ -273,9 +326,8 @@ fn build_p2nfth_script(nfthash: &[u8]) -> Script {
|
|||
}
|
||||
|
||||
fn build_storage_script(governingOutpointIndex: u32) -> Script {
|
||||
let encoded = encode_padded_vm_number(&BigInt::from(governingOutpointIndex), 2).unwrap();
|
||||
let mut bytes = Builder::new()
|
||||
.push_slice(&encoded)
|
||||
.push_slice(&encode_padded_vm_number(&BigInt::from(governingOutpointIndex), 2).unwrap())
|
||||
.into_script()
|
||||
.to_bytes();
|
||||
bytes.extend_from_slice(&STORAGE_CONTRACT);
|
||||
|
|
@ -287,7 +339,7 @@ fn build_storage_script_with_data_and_size(governingOutpointIndex: u32, data: &[
|
|||
data_and_size.extend_from_slice(data);
|
||||
data_and_size.extend_from_slice(&encode_padded_vm_number(&BigInt::from(data.len()), 2).unwrap());
|
||||
let mut bytes = Builder::new()
|
||||
.push_slice(&bigint_to_vm_number(&BigInt::from(governingOutpointIndex)))
|
||||
.push_slice(&encode_padded_vm_number(&BigInt::from(governingOutpointIndex), 2).unwrap())
|
||||
.into_script()
|
||||
.to_bytes();
|
||||
bytes.extend_from_slice(&STORAGE_CONTRACT);
|
||||
|
|
@ -358,6 +410,7 @@ fn build_offering_bytecode(maxDiscountRate: &BigInt, discountAnnualRate: &BigInt
|
|||
}
|
||||
|
||||
fn build_launcher_bytecode(collectorNFTH: &[u8], platformFeeNFTH: &[u8], platformFee: &BigInt, delphiCategory: &[u8], expiresAt: &BigInt, deployThreshold: &BigInt, immediateDeployThreshold: &BigInt) -> Vec<u8> {
|
||||
let rev_delphi_cat: Vec<u8> = delphiCategory.iter().copied().rev().collect();
|
||||
let mut input_bytecode = Builder::new()
|
||||
.push_slice(collectorNFTH)
|
||||
.push_slice(platformFeeNFTH)
|
||||
|
|
@ -366,7 +419,7 @@ fn build_launcher_bytecode(collectorNFTH: &[u8], platformFeeNFTH: &[u8], platfor
|
|||
.push_slice(&STORAGE_CONTRACT)
|
||||
.push_slice(&OFFERING_INTEGRATED_TIMELOCKED_P2NFTH_CONTRACT)
|
||||
.push_slice(&P2NFTH_CONTRACT)
|
||||
.push_slice(delphiCategory)
|
||||
.push_slice(&rev_delphi_cat)
|
||||
.into_script()
|
||||
.to_bytes();
|
||||
input_bytecode.extend_from_slice(&bigint_to_push_opcode(expiresAt));
|
||||
|
|
@ -390,7 +443,8 @@ fn build_partial_offering_initiator_bytecode(extensionOutpointIndex: &BigInt, to
|
|||
bytecode.extend_from_slice(&bigint_to_push_opcode(distDeployOutpointIndex));
|
||||
bytecode.extend_from_slice(&bigint_to_push_opcode(launcherBytecodeOutpointIndex));
|
||||
bytecode.extend_from_slice(&bigint_to_push_opcode(offeringBytecodeOutpointIndex));
|
||||
bytecode.extend_from_slice(&bigint_to_push_opcode(executionFee));
|
||||
bytecode.push(0x04); // OP_PUSH4
|
||||
bytecode.extend_from_slice(&encode_padded_vm_number(executionFee, 4).unwrap());
|
||||
bytecode.extend_from_slice(&OFFERING_INITIATOR_CONTRACT);
|
||||
bytecode
|
||||
}
|
||||
|
|
@ -855,8 +909,8 @@ async fn txchain_trim_tracker(
|
|||
}
|
||||
|
||||
const IDO_PREINIT_ANNOUNCEMENT_SIGNATURE: &[u8; 15] = &[
|
||||
0x6a, 0x4c, 0xba,
|
||||
0x43, 0x61, 0x75, 0x6c, 0x64, 0x72, 0x6f, 0x6e, 0x49, 0x64, 0x6f, 0x30,
|
||||
0x6a, 0x4c, 0xbb, // OP_RETURN OP_PUSHDATA1 (187)
|
||||
0x43, 0x61, 0x75, 0x6c, 0x64, 0x72, 0x6f, 0x6e, 0x49, 0x64, 0x6f, 0x30, // CauldronIdo0
|
||||
];
|
||||
|
||||
fn is_preinit_broadcast(
|
||||
|
|
@ -963,7 +1017,7 @@ struct IdoPreinitParseParamsResult {
|
|||
is_valid_ido: bool,
|
||||
}
|
||||
|
||||
fn parse_ido_preinit_tx_params(tx: &Transaction, platform_fee_nfth: &[u8], errors: &mut Vec<Error>, invalid_ido_reasons: &mut Vec<Error>) -> Option<IdoPreinitParseParamsResult> {
|
||||
fn parse_ido_preinit_tx_params(tx: &Transaction, delphi_token_id: &[u8], platform_fee_nfth: &[u8], errors: &mut Vec<Error>, invalid_ido_reasons: &mut Vec<Error>) -> Option<IdoPreinitParseParamsResult> {
|
||||
// preinit announcement
|
||||
let annOut = tx.output.get(0); // preinit params
|
||||
if annOut.is_some() {
|
||||
|
|
@ -986,13 +1040,13 @@ fn parse_ido_preinit_tx_params(tx: &Transaction, platform_fee_nfth: &[u8], error
|
|||
// params main
|
||||
match &instructions[1] {
|
||||
Ok(Instruction::PushBytes(data)) => {
|
||||
if data.len() < 185 {
|
||||
if data.len() < 187 {
|
||||
errors.push(anyhow::anyhow!("Incorrect announcement.mainData size"));
|
||||
return None;
|
||||
}
|
||||
let mut is_valid_ido = true;
|
||||
// preinit_parameters.offeredTokenTotalSupply < BigInt::from(0)
|
||||
let offered_token_is_in_supply = vm_number_to_bigint(&data[168..176]) < BigInt::from(0);
|
||||
let offered_token_is_in_supply = vm_number_to_bigint(&data[170..178]) < BigInt::from(0);
|
||||
|
||||
let offeringBcmrStorageOut = tx.output.get(8);
|
||||
if offeringBcmrStorageOut.is_none() {
|
||||
|
|
@ -1030,31 +1084,31 @@ fn parse_ido_preinit_tx_params(tx: &Transaction, platform_fee_nfth: &[u8], error
|
|||
},
|
||||
authguardLockingBytecode: authguardLockingBytecode,
|
||||
offering: IdoParametersOffering {
|
||||
platformFeeNFTH: data[10..42].to_vec(),
|
||||
platformFeeNumerator: vm_number_to_bigint(&data[42..46]),
|
||||
delphiCategory: data[46..78].to_vec(),
|
||||
platformFeeNFTH: data[12..44].to_vec(),
|
||||
platformFeeNumerator: vm_number_to_bigint(&data[44..48]),
|
||||
delphiCategory: data[48..80].to_vec(),
|
||||
launchConditions: IdoParametersOfferingLaunchConditions {
|
||||
expiresAt: vm_number_to_bigint(&data[78..84]),
|
||||
deployThreshold: vm_number_to_bigint(&data[84..92]),
|
||||
immediateDeployThreshold: vm_number_to_bigint(&data[92..100]),
|
||||
expiresAt: vm_number_to_bigint(&data[80..86]),
|
||||
deployThreshold: vm_number_to_bigint(&data[86..94]),
|
||||
immediateDeployThreshold: vm_number_to_bigint(&data[94..102]),
|
||||
},
|
||||
offer: IdoParametersOfferingOffer {
|
||||
maxDiscountRateNumerator: vm_number_to_bigint(&data[100..104]),
|
||||
discountAnnualRateNumerator: vm_number_to_bigint(&data[104..108]),
|
||||
priceNumerator: vm_number_to_bigint(&data[108..124]),
|
||||
minOffer: vm_number_to_bigint(&data[124..128]),
|
||||
xTokenCategory: if vm_number_to_bigint(&data[128..160]) == BigInt::from(0) {
|
||||
maxDiscountRateNumerator: vm_number_to_bigint(&data[102..106]),
|
||||
discountAnnualRateNumerator: vm_number_to_bigint(&data[106..110]),
|
||||
priceNumerator: vm_number_to_bigint(&data[110..126]),
|
||||
minOffer: vm_number_to_bigint(&data[126..130]),
|
||||
xTokenCategory: if vm_number_to_bigint(&data[130..162]) == BigInt::from(0) {
|
||||
None
|
||||
} else {
|
||||
Some(data[128..160].to_vec())
|
||||
Some(data[130..162].to_vec())
|
||||
},
|
||||
},
|
||||
executionFee: vm_number_to_bigint(&data[160..164]),
|
||||
executionFee: vm_number_to_bigint(&data[162..166]),
|
||||
},
|
||||
permanentLiquidityShareNumerator: vm_number_to_bigint(&data[164..168]),
|
||||
offeredTokenTotalSupply: vm_number_to_bigint(&data[168..176]),
|
||||
offeredTokenAmount: vm_number_to_bigint(&data[176..184]),
|
||||
authguardNftOutputIndex: vm_number_to_bigint(&data[184..185]),
|
||||
permanentLiquidityShareNumerator: vm_number_to_bigint(&data[166..170]),
|
||||
offeredTokenTotalSupply: vm_number_to_bigint(&data[170..178]),
|
||||
offeredTokenAmount: vm_number_to_bigint(&data[178..186]),
|
||||
authguardNftOutputIndex: vm_number_to_bigint(&data[186..187]),
|
||||
};
|
||||
|
||||
// enforce limitation (xToken == NATIVE_BCH)
|
||||
|
|
@ -1101,7 +1155,7 @@ fn parse_ido_preinit_tx_params(tx: &Transaction, platform_fee_nfth: &[u8], error
|
|||
invalid_ido_reasons.push(anyhow::anyhow!("preinit_parameters.offeredTokenAmount <= BigInt::from(0)"));
|
||||
is_valid_ido = false;
|
||||
}
|
||||
if preinit_parameters.offering.delphiCategory != DELPHI_TOKEN_ID {
|
||||
if preinit_parameters.offering.delphiCategory != delphi_token_id {
|
||||
invalid_ido_reasons.push(anyhow::anyhow!("preinit_parameters.offering.delphiCategory != DELPHI_TOKEN_ID"));
|
||||
is_valid_ido = false;
|
||||
}
|
||||
|
|
@ -1148,11 +1202,16 @@ fn parse_ido_preinit_tx(network: Option<Network>, tx: &Transaction, errors: &mut
|
|||
Some(Network::Bitcoin) => MAINNET_PLATFORM_FEE_NFTH.clone(),
|
||||
_ => MAINNET_PLATFORM_FEE_NFTH.clone(),
|
||||
};
|
||||
let delphi_token_id = match network {
|
||||
Some(Network::Chipnet) => CHIPNET_DELPHI_TOKEN_ID.clone(),
|
||||
Some(Network::Bitcoin) => MAINNET_DELPHI_TOKEN_ID.clone(),
|
||||
_ => MAINNET_DELPHI_TOKEN_ID.clone(),
|
||||
};
|
||||
let offered_token_is_in_supply: bool;
|
||||
let mut is_valid_ido: bool;
|
||||
let nullable_preinit_parameters: Option<IdoPreInitParameters>;
|
||||
// preinit announcement
|
||||
match parse_ido_preinit_tx_params(tx, &platform_fee_nfth, errors, invalid_ido_reasons) {
|
||||
match parse_ido_preinit_tx_params(tx, &delphi_token_id, &platform_fee_nfth, errors, invalid_ido_reasons) {
|
||||
Some(output) => {
|
||||
offered_token_is_in_supply = output.offered_token_is_in_supply;
|
||||
is_valid_ido = output.is_valid_ido;
|
||||
|
|
@ -1169,14 +1228,16 @@ fn parse_ido_preinit_tx(network: Option<Network>, tx: &Transaction, errors: &mut
|
|||
|
||||
// find authguardCategory
|
||||
if let Some(params) = nullable_preinit_parameters {
|
||||
match params.authguardNftOutputIndex.to_usize() {
|
||||
Some(index) => {
|
||||
authguardNftOut = tx.output.get(index);
|
||||
if authguardNftOut.is_none() {
|
||||
errors.push(anyhow::anyhow!("authguardNftOutputIndex out of range"));
|
||||
}
|
||||
},
|
||||
_ => errors.push(anyhow::anyhow!("authguardNftOutputIndex out of range")),
|
||||
if params.authguardNftOutputIndex >= BigInt::from(0) {
|
||||
match params.authguardNftOutputIndex.to_usize() {
|
||||
Some(index) => {
|
||||
authguardNftOut = tx.output.get(index);
|
||||
if authguardNftOut.is_none() {
|
||||
errors.push(anyhow::anyhow!("authguardNftOutputIndex out of range"));
|
||||
}
|
||||
},
|
||||
_ => errors.push(anyhow::anyhow!("authguardNftOutputIndex out of range")),
|
||||
}
|
||||
}
|
||||
|
||||
let state = IdoPreInitState {
|
||||
|
|
@ -1303,7 +1364,7 @@ fn parse_ido_preinit_tx(network: Option<Network>, tx: &Transaction, errors: &mut
|
|||
¶ms.permanentLiquidityShareNumerator,
|
||||
¶ms.offering.offer.priceNumerator,
|
||||
),
|
||||
&BigInt::from(7i64), // permanentPoolOTokenReserveOutpointIndex
|
||||
&BigInt::from(8i64), // permanentPoolOTokenReserveOutpointIndex
|
||||
&BigInt::from(0i64), // offeringInitiatorOutpointIndex
|
||||
),
|
||||
).to_bytes();
|
||||
|
|
@ -2157,29 +2218,29 @@ pub async fn index_block(
|
|||
for input_index in [ 0, 1, 3 ] {
|
||||
let input = tx.input.get(input_index);
|
||||
if input.is_some() {
|
||||
if let Some(txchain_item) =
|
||||
txchain_lookup_next(
|
||||
pool,
|
||||
&input.unwrap().previous_output.txid,
|
||||
input.unwrap().previous_output.vout
|
||||
)
|
||||
.await?
|
||||
{
|
||||
match ido_lookup(pool, txchain_item.ido_id)
|
||||
if let Some(txchain_item) =
|
||||
txchain_lookup_next(
|
||||
pool,
|
||||
&input.unwrap().previous_output.txid,
|
||||
input.unwrap().previous_output.vout
|
||||
)
|
||||
.await?
|
||||
{
|
||||
match ido_lookup(pool, txchain_item.ido_id)
|
||||
.await {
|
||||
Ok(Some(ido)) => {
|
||||
match on_add_ido_tx(network, pool, &ido, &txchain_item, tx, block_height)
|
||||
.await {
|
||||
Err(err) => info!("add tx to an ido failed, txid: {}, {}", hex::encode(tx.txid().to_blob()), err),
|
||||
_ => (),
|
||||
}
|
||||
},
|
||||
Err(err) => warn!("ido record not found!!, {}", err),
|
||||
_ => warn!("ido record not found!!"),
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
Ok(Some(ido)) => {
|
||||
match on_add_ido_tx(network, pool, &ido, &txchain_item, tx, block_height)
|
||||
.await {
|
||||
Err(err) => info!("add tx to an ido failed, txid: {}, {}", hex::encode(tx.txid().to_blob()), err),
|
||||
_ => (),
|
||||
}
|
||||
},
|
||||
Err(err) => warn!("ido record not found!!, {}", err),
|
||||
_ => warn!("ido record not found!!"),
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2254,6 +2315,49 @@ impl IdoDBRecord {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use bitcoincash::blockdata::transaction::Transaction;
|
||||
use std::sync::LazyLock;
|
||||
|
||||
static PREINIT_TEST_TX01: LazyLock<Vec<u8>> = LazyLock::new(|| hex::decode("0200000001e6b6c7e14eb71e53285f252a3ec38a4822befbe5ed15c18303c53c593af14b5900000000644167d23b1ba69109557b9d2efd7c20bc96e794fba690e33cee5b89e3db536045bd0fa04ff78b7e9b1c48b308b88355e2ffc1d92207c5da4c0d72a48765c4bdf88c612103e88d9ab230288089c7363b77431504661a943266c08235cb1ac3998349b75e67000000000c0000000000000000d86a4cbb4361756c64726f6e49646f30072d5fbecfa1bc37a13f58b188f50a5bc1dfb9ab8ae0bf5d3d9a63f6f81efc0b809698001b948240c9cfaa8224383db16e4735efa09c9426d1713d265e849a8e91f2669afefc0a6a000070170000000000007017000000000000002d310180969800041a130d8401000000000000000000007017000000000000000000000000000000000000000000000000000000000000000000001027000080c3c90100e40b540200000000ca9a3b00000000811976a91430da60e54a4d87ecdcb6adf91a98736668b55e9e88ace80300000000000023aa20d82b9eb9f86f02acd8787d6959d24e2a81e8e8ffcf9fae67d94e3b13ab74f6fe87e80300000000000023aa20b0be53828f2700b0fd254708e0b54b100163be607c1c82138ba793a2d667e55f87e80300000000000023aa20542b74123c493fc2f1f74d99586f87355b07c5a450b64111085759cf9cc96d8287e80300000000000023aa20f69ff67df71b9ecd4b6b39af393551468bb2a46fb261e2e5a61cfb27dbcbb25087e80300000000000023aa20e5b1d9865bf78f7cfc02e60ba0bcf327e0d3949f455a37dd8870979c3fc0f42d87e80300000000000023aa20bcf0c9aabff1ff311bccd16c598ac0bc7860253b2c8535cef71dbb2c0a1a782c87e80300000000000023aa207d3e837c0a706c368bacce2c03d1777a33e0a32a26bbf807c1a9b79446b3769787b0040000000000000f0201008178c99dc8c0c88702000075b0040000000000000f0201008178c99dc8c0c88702000075307500000000000023aa2060935eaee5df8476303b86855a14c093d02aaf816409533ad31ef87e79705b7f872bbdcc1d000000001976a914b093805bb56927c08724b92bfdfd77cf07c2cdc288ac00000000").unwrap());
|
||||
|
||||
#[test]
|
||||
fn preinit_detect() {
|
||||
let tx: Transaction = bitcoincash::consensus::deserialize(&PREINIT_TEST_TX01).expect("should be valid");
|
||||
assert!(is_preinit_broadcast(&tx));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_ido_preinit_from_valid_ido() {
|
||||
let tx: Transaction = bitcoincash::consensus::deserialize(&PREINIT_TEST_TX01).expect("should be valid");
|
||||
let mut errors: Vec<Error> = Vec::new();
|
||||
let mut invalid_ido_reasons: Vec<Error> = Vec::new();
|
||||
let network = Some(Network::Chipnet);
|
||||
let result = parse_ido_preinit_tx(network, &tx, &mut errors, &mut invalid_ido_reasons);
|
||||
let params = result.parameters.expect("parameters should be defined!");
|
||||
let state = result.state.expect("state should be defined!");
|
||||
if errors.len() > 0 {
|
||||
println!("Parse ido preinit failed, txid: {}\nError(s):", hex::encode(tx.txid().to_blob()));
|
||||
for error in &errors {
|
||||
println!(" - {}", error);
|
||||
}
|
||||
}
|
||||
if invalid_ido_reasons.len() > 0 {
|
||||
println!("Invalid ido found, preinit_txid: {}\nReason(s):", hex::encode(tx.txid().to_blob()));
|
||||
for reason in &invalid_ido_reasons {
|
||||
println!(" - {}", reason);
|
||||
}
|
||||
}
|
||||
println!("params: {}", String::from_utf8(serde_json::to_vec_pretty(¶ms).unwrap()).unwrap());
|
||||
println!("state: {}", String::from_utf8(serde_json::to_vec_pretty(&state).unwrap()).unwrap());
|
||||
assert!(errors.len() == 0 && invalid_ido_reasons.len() == 0);
|
||||
assert!(result.is_valid_ido);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ─── Public RPC query functions ──────────────────────────────────────────────
|
||||
|
||||
pub async fn list_idos(
|
||||
|
|
@ -2266,7 +2370,8 @@ pub async fn list_idos(
|
|||
) -> Result<Vec<IdoRpcRecord>> {
|
||||
let mut qb: sqlx::QueryBuilder<sqlx::Sqlite> = sqlx::QueryBuilder::new(
|
||||
"SELECT id, preinit_txid, init_txid, launch_txid, offering_token_id, offered_token_id, \
|
||||
status, parameters, state, txchain_entrypoint, txchain_head, is_valid FROM ido WHERE 1=1",
|
||||
status, parameters, state, txchain_entrypoint, txchain_head, is_valid, is_token_created_at_preinit
|
||||
FROM ido WHERE 1=1",
|
||||
);
|
||||
if let Some(v) = is_valid {
|
||||
qb.push(" AND is_valid = ");
|
||||
|
|
@ -2299,7 +2404,7 @@ pub async fn get_ido_by_offering_token_id(
|
|||
) -> Result<Option<IdoRpcRecord>> {
|
||||
let row = sqlx::query(
|
||||
"SELECT id, preinit_txid, init_txid, launch_txid, offering_token_id, offered_token_id, \
|
||||
status, parameters, state, txchain_entrypoint, txchain_head, is_valid \
|
||||
status, parameters, state, txchain_entrypoint, txchain_head, is_valid, is_token_created_at_preinit \
|
||||
FROM ido WHERE offering_token_id = ?",
|
||||
)
|
||||
.bind(offering_token_id_blob)
|
||||
|
|
@ -2460,7 +2565,7 @@ pub async fn list_txchain_tracker_map(
|
|||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
mod querytests {
|
||||
use super::*;
|
||||
use num_bigint::BigInt;
|
||||
use sqlx::SqlitePool;
|
||||
|
|
@ -2746,6 +2851,7 @@ mod tests {
|
|||
.bind(distributed as i64)
|
||||
.execute(pool)
|
||||
.await
|
||||
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -445,7 +445,7 @@ pub async fn index_blocks(
|
|||
.await?;
|
||||
|
||||
db::ido::index_block(
|
||||
network,
|
||||
network,
|
||||
&db.ido_w,
|
||||
&sorted_txs,
|
||||
&blockhash,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue