From db299cfbf660fcb7731016c1b9ed2d2d37da75f7 Mon Sep 17 00:00:00 2001 From: Andy Date: Sat, 31 Jan 2026 23:37:25 +0000 Subject: [PATCH] Add IssuanceHookset hooks, docs, and samples Introduce the IssuanceHookset module with IDO, Rewards and Router hook implementations, documentation, metadata, and sample C hooks. --- IssuanceHookset/Docs/IDOMulti.md | 158 ++++ IssuanceHookset/Docs/MetaTemplate/Meta.json | 163 ++++ IssuanceHookset/Docs/Rewards.md | 144 ++++ IssuanceHookset/Docs/Router.md | 113 +++ IssuanceHookset/Docs/Samples/LedgerIssue.c | 347 ++++++++ IssuanceHookset/Docs/Samples/LedgerMultiple.c | 205 +++++ IssuanceHookset/Docs/Samples/LedgerPhase.c | 186 +++++ IssuanceHookset/Docs/Samples/LedgerSeq.c | 145 ++++ .../Docs/Transactions/Hookset.json | 339 ++++++++ IssuanceHookset/Fin/IDOMulti.c | 529 ++++++++++++ IssuanceHookset/Fin/README.md | 13 + IssuanceHookset/Fin/Rewards.c | 252 ++++++ IssuanceHookset/Fin/Router.c | 150 ++++ IssuanceHookset/Hooks/IDOMaster.c | 771 ++++++++++++++++++ IssuanceHookset/Hooks/RewardsMaster.c | 389 +++++++++ IssuanceHookset/Hooks/RouterMaster.c | 238 ++++++ IssuanceHookset/IssuanceHookset.md | 83 ++ IssuanceHookset/README.md | 419 ++++++++++ README.md | 189 ----- .../GithubUser_MyProjectName.md | 12 - 20 files changed, 4644 insertions(+), 201 deletions(-) create mode 100644 IssuanceHookset/Docs/IDOMulti.md create mode 100644 IssuanceHookset/Docs/MetaTemplate/Meta.json create mode 100644 IssuanceHookset/Docs/Rewards.md create mode 100644 IssuanceHookset/Docs/Router.md create mode 100644 IssuanceHookset/Docs/Samples/LedgerIssue.c create mode 100644 IssuanceHookset/Docs/Samples/LedgerMultiple.c create mode 100644 IssuanceHookset/Docs/Samples/LedgerPhase.c create mode 100644 IssuanceHookset/Docs/Samples/LedgerSeq.c create mode 100644 IssuanceHookset/Docs/Transactions/Hookset.json create mode 100644 IssuanceHookset/Fin/IDOMulti.c create mode 100644 IssuanceHookset/Fin/README.md create mode 100644 IssuanceHookset/Fin/Rewards.c create mode 100644 IssuanceHookset/Fin/Router.c create mode 100644 IssuanceHookset/Hooks/IDOMaster.c create mode 100644 IssuanceHookset/Hooks/RewardsMaster.c create mode 100644 IssuanceHookset/Hooks/RouterMaster.c create mode 100644 IssuanceHookset/IssuanceHookset.md create mode 100644 IssuanceHookset/README.md delete mode 100644 README.md delete mode 100644 submissions/GithubUser_MyProjectName/GithubUser_MyProjectName.md diff --git a/IssuanceHookset/Docs/IDOMulti.md b/IssuanceHookset/Docs/IDOMulti.md new file mode 100644 index 0000000..8ee493f --- /dev/null +++ b/IssuanceHookset/Docs/IDOMulti.md @@ -0,0 +1,158 @@ +# IDO Master Hook (IDOM) + +## Overview + +The IDO Master Hook (IDOM) is a sophisticated smart contract for Xahau that enables Initial DEX Offerings (IDOs). It facilitates token sales with multiple phases, dynamic multipliers, soft cap evaluation, and refund mechanisms. Users deposit XAH during active phases to receive IOU tokens at varying rates, with options for unwinding positions during eligible periods. + +## Purpose + +IDOs allow issuers to launch token sales with structured phases that incentivize early participation through higher multipliers. The hook manages the entire lifecycle: setup, deposits, issuance, soft cap evaluation, and refunds. It integrates with whitepaper validation to ensure user acknowledgment of terms and includes balance protection to prevent premature fund withdrawal. + +## Hook Parameters + +The hook requires several parameters set at installation time: + +- **ADMIN** (20 bytes): Account ID of the administrator authorized to configure the IDO. +- **CURRENCY** (20 bytes): Currency code for the IOU tokens to be issued. +- **INTERVAL** (4 bytes): Ledger interval per phase (big-endian uint32). +- **SOFT_CAP** (8 bytes): Soft cap in XAH (big-endian uint64). +- **WP_LNK** (variable): Whitepaper/documentation link for validation. + +## Admin Configuration + +### Invoke Parameters +- **START** (4 bytes): Ledger offset to begin the IDO window (big-endian uint32). +- **WP_LNK** (variable): Whitepaper link stored in state for validation. + +## Phases and Multipliers + +The IDO operates in 5 phases with decreasing multipliers: + +- **Phase 1**: 100x multiplier +- **Phase 2**: 75x multiplier +- **Phase 3**: 50x multiplier +- **Phase 4**: 25x multiplier +- **Phase 5**: Cooldown/unwind period (no new deposits) + +Phases are determined by elapsed ledgers since the start, divided by the interval offset. + +## User Actions + +### Deposits +- Send XAH payments during active phases (1-4). +- Include 'WP_LNK' parameter matching the stored whitepaper link. +- Receive IOU tokens at the current phase's multiplier rate. + +### Unwinding +- Send exact IOU amount back during eligible periods for proportional XAH refund. +- Available during Phase 5 (refund mode) or before window end (successful sales). + +## Transaction Handling + +### Invoke Transactions +- **Authorized Admin**: Can set START and WP_LNK to initialize the IDO window. +- **Unauthorized**: Rejected. + +### Payment Transactions + +#### Outgoing Payments +- **IOU Payments**: Always accepted (token issuance). +- **XAH Payments**: Checked against unlocked balance (locked during active IDO). +- **Other**: Accepted. + +#### Incoming Payments + +##### XAH Deposits (Active Phases) +- Validates WP_LNK parameter match. +- Checks window active and phase valid. +- Issues IOU tokens via Remit transaction. +- Updates global and user participation counters. + +##### IOU Unwinds +- Validates issuer and amount. +- Checks refund mode or exact amount match. +- Emits XAH refund payment. +- Updates counters and removes user data. + +## State Management + +The hook maintains several state keys: + +- **START**: Window start ledger. +- **END**: Window end ledger. +- **WP_LNK**: Stored whitepaper link. +- **SOFT_CAP**: Soft cap threshold. +- **XAH**: Total XAH raised. +- **IOU**: Total IOU issued. +- **EXEC**: Total execution count. +- **PHASE[1-5]**: Phase-specific execution counts. +- **REFUND**: Refund mode flag (0=success, 1=refund). +- **TOTAL_RAISED**: Preserved total for successful sales. +- **IDO_DATA** (foreign): User participation data (XAH deposited, IOU received). + +## Soft Cap Evaluation + +After Phase 4 ends: +- Compares total XAH raised against soft cap. +- If met: Sale successful, funds unlock after cooldown. +- If not met: Refund mode activated, users can unwind. + +## Balance Protection + +- Funds are locked during active IDO to prevent withdrawal. +- Locked amount = total XAH raised × 1,000,000 (drops). +- Unlocks after successful sale and cooldown period. + +## Accepted Transactions + +- Admin invokes with START/WP_LNK parameters. +- Outgoing IOU and other payments. +- Outgoing XAH with sufficient unlocked balance. +- Incoming XAH during active phases with valid WP_LNK. +- Incoming IOU for unwinding during eligible periods. + +## Rejected Transactions + +- Unauthorized invokes. +- XAH deposits without WP_LNK or during invalid phases. +- IOU unwinds with wrong issuer or invalid amounts. +- Payments outside active window (unless refund mode). +- Outgoing XAH exceeding unlocked balance. + +## Error Messages + +The hook provides detailed error messages for debugging: +- "IDO :: Error :: [specific issue]" for configuration/setup problems. +- "IDO :: Rejected :: [reason]" for invalid transactions. +- "IDO :: Unwind :: [issue]" for unwind-specific errors. +- "IDO :: Accepted :: [description]" for successful transactions. + +## Security Considerations + +- Admin authorization prevents unauthorized configuration. +- WP_LNK validation ensures user acknowledgment. +- Exact amount matching for unwinds prevents manipulation. +- Balance protection secures raised funds. +- State validation prevents race conditions. + +## Integration + +Designed to work with: +- Router Hook for transaction routing. +- Rewards Hook for post-IDO incentives. +- Compatible with Xahau's Remit transaction type for IOU issuance. + +## Usage Example + +1. **Setup**: Install hook with parameters, admin invokes with START. +2. **Deposit Phase**: Users send XAH with WP_LNK during phases 1-4. +3. **Evaluation**: After Phase 4, soft cap checked automatically. +4. **Unwind/Claim**: Users unwind IOU for refunds or hold for rewards. + +## Author + +@Handy_4ndy + +## License + +Part of the Xahau HandyHook Collection. See repository license for details. \ No newline at end of file diff --git a/IssuanceHookset/Docs/MetaTemplate/Meta.json b/IssuanceHookset/Docs/MetaTemplate/Meta.json new file mode 100644 index 0000000..a368290 --- /dev/null +++ b/IssuanceHookset/Docs/MetaTemplate/Meta.json @@ -0,0 +1,163 @@ +{ + "t": "[TOKEN_TICKER]", + "n": "[TOKEN_DISPLAY_NAME]", + "d": "Utility token issued via an open-source phased IDO Hook on Xahau Network. Features time-decaying multipliers, soft-cap protection, automatic unwind/refund, and on-chain transparency for fair fundraising.", + "i": "[ICON_URI e.g. ipfs://... or https://...]", + "ac": "defi", + "as": "fundraising", + "in": "[ISSUER_OR_PROJECT_NAME]", + "us": [ + { + "u": "[PROJECT_WEBSITE_URL]", + "c": "website", + "t": "Official Website" + }, + { + "u": "[DOCUMENTATION_URL]", + "c": "docs", + "t": "Documentation & Usage Guide" + }, + { + "u": "[WHITEPAPER_OR_DISCLOSURES_IPFS_OR_URL]", + "c": "docs", + "t": "Whitepaper, Risk Disclosures & Legal Terms" + }, + { + "u": "[SOCIAL_MEDIA_URL e.g. x.com/...]", + "c": "social", + "t": "Project Updates" + }, + { + "u": "explorer.xahau.network", + "c": "other", + "t": "Xahau Explorer (View On-Chain Activity)" + } + ], + "ai": { + "platform": { + "network": "Xahau", + "programmability": "Account-attached Hooks (WebAssembly) for on-ledger automation and transaction logic", + "token_type": "Issued IOU (fungible token created via payments/Remits after TrustSet)", + "key_features": [ + "4-phase fundraising window with configurable multipliers (e.g. 100x → 75x → 50x → 25x)", + "Soft cap threshold with automatic post-window refund/unwind if unmet", + "On-chain global counters: executions, total raised, total issued, per-phase stats", + "Per-user participation tracking via hierarchical state namespaces", + "WP_LNK parameter during install → used as access token to imply acknowledgment of disclosures" + ] + }, + "ido_mechanics": { + "phases": [ + { + "number": 1, + "status": "First Phase", + "multiplier": "[PHASE1_MULTIPLIER e.g. 100x]", + "duration": "configurable (e.g. [EXAMPLE_LEDGERS] ledgers ≈ [DAYS] days)" + }, + { + "number": 2, + "status": "Second Phase", + "multiplier": "[PHASE2_MULTIPLIER e.g. 75x]", + "duration": "same as phase 1" + }, + { + "number": 3, + "status": "Mid Phase", + "multiplier": "[PHASE3_MULTIPLIER e.g. 50x]", + "duration": "same as phase 1" + }, + { + "number": 4, + "status": "Final Phase", + "multiplier": "[PHASE4_MULTIPLIER e.g. 25x]", + "duration": "same as phase 1" + }, + { + "number": 5, + "status": "Cooldown", + "multiplier": "0 (IDO closed, unwind only)", + "duration": "same as phase 1" + } + ], + "soft_cap": "configurable (e.g. [AMOUNT] XAH in drops)", + "unwind_mechanism": "If soft cap unmet after window: participants return exact IOU balance → Hook emits proportional XAH refund via Remit", + "participation_flow": "XAH Payment to issuer during active window → Hook emits Remit with multiplied IOU; rejects invalid/out-of-window attempts" + }, + "tokenomics": { + "total_supply": "[CONFIGURABLE_TOTAL_SUPPLY e.g. 1,000,000,000]", + "initial_distribution": "Primarily via phased IDO; remainder configurable (e.g. vested team, liquidity pools, ecosystem incentives, reserves)", + "utility": [ + "Governance rights", + "Potential staking/yield mechanisms", + "Fee discounts or access perks", + "Ecosystem feature unlocks (project-specific)" + ] + }, + "compliance": { + "regulatory_classifications": { + "us_sec": "Self-assessed as utility token: Value from decentralized participation/utility, not centralized profit expectation (Howey Test review recommended).", + "eu_mica": "Crypto-asset (utility type); disclosures provided via IPFS-linked documentation; follow CASP rules if public offer exceeds thresholds.", + "uk_fca": "Cryptoasset; prominent risk warnings; no unauthorized high-risk promotions to retail users.", + "global": "On-chain transparency supports FATF Travel Rule principles; users advised to apply local AML/KYC standards." + }, + "risk_disclosures": { + "general": [ + "High risk of total loss due to volatility, illiquidity, or project failure.", + "No guaranteed value, returns, secondary market, or adoption.", + "Hook/smart-logic risks: potential bugs despite best practices." + ], + "ido_specific": [ + "Soft cap not met → unwind/refund mode may involve delays.", + "Early-phase higher multipliers reflect higher risk/reward timing.", + "Possible regulatory reclassification in certain jurisdictions." + ], + "disclaimer": "This is not investment, financial, or legal advice. All participants bear full responsibility. Consult qualified professionals and review local laws." + }, + "kyc_aml_policy": { + "approach": "Self-certification by participants; issuers may implement additional checks per jurisdiction.", + "privacy": "On-chain data is public and immutable by design; minimize off-chain personal data collection.", + "standards": "No facilitation of sanctioned entities; issuers should monitor for compliance." + }, + "terms_of_service": { + "acceptance": "Sending XAH to the issuer account and/or providing WP_LNK during setup constitutes acknowledgment of all linked terms, risks, and disclosures.", + "eligibility": "Must be 18+ and not in restricted/sanctioned jurisdictions. Participants self-certify compliance.", + "limitations": "Issuer may pause, modify, or terminate fundraising for security, compliance, or technical reasons.", + "liability": "Services and Hook logic provided 'AS IS'; no liability accepted for market losses, technical issues, or third-party actions.", + "governing_law": "International blockchain norms; disputes recommended via arbitration in a neutral jurisdiction.", + "amendments": "Terms subject to update; continued participation implies acceptance." + }, + "audit_and_security": { + "hook_audit": { + "status": "Pending / Planned / Completed (issuer to specify)", + "recommended_auditors": "Independent firms such as PeckShield, Certik, SlowMist, or equivalent", + "target_or_completion_date": "[YYYY-MM or 'Before real funds accepted']", + "report_uri": "[AUDIT_REPORT_IPFS_OR_URL] (placeholder – replace with actual link)" + }, + "additional_audits": { + "status": "Pending / Planned / Completed (if separate token or tooling audited)", + "report_uri": "[ADDITIONAL_AUDIT_URI] (placeholder)" + }, + "security_features": [ + "Guard macros to prevent common errors (overflows, reentrancy, etc.)", + "Restricted invoke access (only issuer/admin)", + "Atomic emit-based token issuance", + "State integrity and counter validation" + ], + "recommendation": "All deployers/issuers MUST obtain independent security audits before accepting real-value transactions. Audits materially reduce risk and build user confidence." + }, + "tax_reporting": { + "user_responsibility": "Participants solely responsible for their own tax and reporting obligations.", + "platform_support": "On-chain transaction history available via explorers for user reference." + }, + "sustainability": { + "note": "Xahau uses efficient consensus; issuers may allocate portions of raised funds to environmental or social impact initiatives." + } + }, + "contact_and_support": { + "website": "[ISSUER_WEBSITE_URL]", + "email": "[SUPPORT_EMAIL e.g. support@[DOMAIN]]", + "social": "[SOCIAL_HANDLE_OR_URL]", + "legal": "[LEGAL_CONTACT e.g. legal@[DOMAIN]]" + } + } +} \ No newline at end of file diff --git a/IssuanceHookset/Docs/Rewards.md b/IssuanceHookset/Docs/Rewards.md new file mode 100644 index 0000000..5031059 --- /dev/null +++ b/IssuanceHookset/Docs/Rewards.md @@ -0,0 +1,144 @@ +# Issuance Rewards Hook (IRH) + +## Overview + +The Issuance Rewards Hook (IRH) enables IOU token holders to claim periodic rewards on their holdings after the completion of an Initial DEX Offering (IDO). It provides configurable interest rates, claim intervals, and lifetime limits, with integration for IDO participants to receive bonus rewards. + +## Purpose + +After an IDO concludes successfully, token holders can earn ongoing rewards on their IOU balances. The hook enforces timing constraints, trustline requirements, and configurable limits to ensure fair and controlled reward distribution. It integrates with the IDO hook to provide bonus rates for original participants. + +## Hook Parameters + +The hook requires several parameters set at installation time: + +- **CURRENCY** (20 bytes): Currency code for the IOU tokens being rewarded. +- **ADMIN** (20 bytes): Account ID of the administrator authorized to configure rewards. +- **INT_RATE** (4 bytes): Initial daily interest rate (big-endian uint32, e.g., 1000 = 10%). +- **SET_INTERVAL** (4 bytes): Initial claim interval in ledgers (big-endian uint32). +- **SET_MAX_CLAIMS** (4 bytes): Initial lifetime claim limit per user (big-endian uint32). (Optional) + +## Admin Configuration + +### Invoke Parameters (Install-time or Runtime) +- **INT_RATE** (4 bytes): Set daily interest rate (big-endian uint32, e.g., 1000 = 10%). +- **SET_INTERVAL** (4 bytes): Set claim interval in ledgers (big-endian uint32). +- **SET_MAX_CLAIMS** (4 bytes): Set lifetime claim limit per user (big-endian uint32). + +## User Actions + +### Claiming Rewards +- Send invoke transaction with 'R_CLAIM' parameter containing the claimant's account ID. +- Hook validates trustline, timing, and limits. +- Calculates rewards based on current IOU balance and configured rate. +- IDO participants receive +5% bonus on their base rate. +- Emits Remit transaction to deliver reward tokens. + +## Reward Calculation + +- **Base Rate**: IOU Balance × Interest Rate / 10000 +- **Bonus Rate**: For IDO participants, base rate + 5% +- Rewards are calculated in real-time based on current balance +- Uses XFL floating-point arithmetic for precision + +## State Management + +The hook maintains several state keys: + +- **INT_RATE**: Configured interest rate. +- **CLAIM_INT**: Claim interval in ledgers. +- **MAX_CLM**: Maximum lifetime claims per user. + +User-specific state is stored in hierarchical namespaces: +- **CLAIM_DATA**: Per-user claim tracking (last claim ledger, total claims). +- Uses account-derived namespaces for unlimited scalability. + +## Integration with IDO Hook + +- Queries foreign state from IDO hook to detect participation. +- Participants receive bonus rewards (+5% interest). +- Ensures rewards are only available after IDO completion. + +## Constraints and Validation + +### Timing +- Claims must wait for configured interval since last claim. +- Enforced per user with ledger-based timestamps. + +### Trustlines +- Users must have established trustline for the reward currency. +- Balance must be positive (IOU holdings). + +### Limits +- Optional lifetime claim limit per user. +- Configurable by admin, default unlimited. + +## Transaction Handling + +### Invoke Transactions + +#### Admin Configuration +- From authorized admin account only. +- Can set interest rate, interval, and max claims. +- Parameters can be set at install or updated via invoke. + +#### User Claims +- From any account with valid trustline. +- Requires 'R_CLAIM' parameter with claimant account ID. +- Validates all constraints before processing. + +#### Other Invokes +- Outgoing invokes from hook account: Passed through. +- Invalid invokes: Rejected with detailed messages. + +## Accepted Transactions + +- Admin invokes with configuration parameters. +- Outgoing invokes. +- User invokes with valid 'R_CLAIM' parameter and all constraints met. + +## Rejected Transactions + +- Non-invoke transactions. +- Unauthorized admin configuration attempts. +- Invalid 'R_CLAIM' parameters. +- Missing trustlines. +- Timing violations (too soon since last claim). +- Lifetime claim limit exceeded. +- Missing configuration (interest rate/interval not set). + +## Error Messages + +The hook provides detailed error messages for debugging: +- "IRH :: Error :: [specific issue]" for configuration/setup problems. +- "IRH :: Success :: [description]" for successful operations. + +## Security Considerations + +- Admin authorization prevents unauthorized configuration changes. +- Trustline validation ensures only legitimate holders can claim. +- Timing and limit enforcement prevents abuse. +- Hierarchical namespaces prevent state collisions. +- Real-time balance checks prevent stale claims. + +## Usage Example + +1. **Setup**: Install hook with parameters, admin configures rates. +2. **Post-IDO**: After IDO completion, users can start claiming. +3. **Claim**: User sends invoke with 'R_CLAIM' parameter. +4. **Validation**: Hook checks all constraints and calculates rewards. +5. **Distribution**: Reward tokens emitted to claimant. + +## Performance Notes + +- Uses foreign state queries for IDO integration. +- Hierarchical namespaces ensure scalability. +- Efficient validation order minimizes processing overhead. + +## Author + +@Handy_4ndy + +## License + +Part of the Xahau HandyHook Collection. See repository license for details. \ No newline at end of file diff --git a/IssuanceHookset/Docs/Router.md b/IssuanceHookset/Docs/Router.md new file mode 100644 index 0000000..b2da246 --- /dev/null +++ b/IssuanceHookset/Docs/Router.md @@ -0,0 +1,113 @@ +# IDO Router Hook + +## Overview + +The IDO Router Hook is a critical component of the Xahau HandyHook Collection, designed to manage the execution flow in a hook chain that includes both IDO (Initial Dex Offering) and Rewards hooks. It acts as a smart router, determining whether to execute the IDO hook, the Rewards hook, or skip them based on transaction type, parameters, and current state. + +## Purpose + +In a hook chain setup, multiple hooks can be installed on an account. The Router Hook ensures that only the appropriate hook logic runs for each transaction, preventing conflicts and optimizing performance. It uses hardcoded hashes to identify and control the execution of the IDO and Rewards hooks. + +## Hardcoded Configuration + +The Router Hook uses predefined byte arrays for hook hashes and namespace to ensure compatibility and security: + +- **IDO_HOOK_HASH**: The SHA-256 hash of the IDO hook binary. Used to skip or allow execution of the IDO hook. +- **REWARDS_HOOK_HASH**: The SHA-256 hash of the Rewards hook binary. Used to skip or allow execution of the Rewards hook. +- **IDO_NAMESPACE**: A 32-byte namespace used for storing and retrieving IDO-related state data from foreign accounts. + +These values are hardcoded to prevent runtime configuration errors and ensure deterministic behavior. + +## Functionality + +### Transaction Routing Logic + +The Router Hook analyzes incoming transactions and routes them as follows: + +#### Outgoing Transactions +- **Invoke (ttINVOKE)**: Skips the IDO hook, allowing the Rewards hook to process admin configurations or claims. +- **Payment (ttPAYMENT)**: + - XAH payments: Skips the Rewards hook, allowing IDO logic to handle outgoing XAH (e.g., refunds). + - Non-XAH payments: Skips the IDO hook, allowing Rewards hook to process. + +#### Incoming Transactions + +##### Invoke Transactions +- **START Parameter**: Runs IDO hook (for initialization), skips Rewards hook. +- **Rewards Admin Parameters** (INT_RATE, SET_INTERVAL, SET_MAX_CLAIMS): Skips IDO hook, runs Rewards hook. +- **R_CLAIM Parameter**: Skips IDO hook, runs Rewards hook for user claims. +- **Invalid Invoke**: Rejected if no recognized parameters. + +##### Payment Transactions + +The Router checks the IDO window status and refund mode: + +- **Refund Mode Active**: Only accepts incoming IOU payments (for unwinding), rejects invokes and outgoing payments. +- **IDO Ended**: Skips IDO hook for all transactions. +- **Window Not Active**: Skips IDO hook unless refund mode. + +For active windows or refund mode: + +- **XAH Payments**: + - Must include WP_LNK parameter (whitepaper acknowledgment) or have existing raised funds. + - Runs IDO hook, skips Rewards hook. +- **IOU Payments**: + - Must have participation data in user state. + - Runs IDO hook, skips Rewards hook. + +## Accepted Transactions + +- Outgoing invokes and payments. +- Incoming invokes with START, rewards admin params, or R_CLAIM. +- Incoming XAH payments with WP_LNK or during active IDO with raised funds. +- Incoming IOU payments from participants during active IDO or refund mode. + +## Rejected Transactions + +- Incoming payments outside active window (unless refund mode). +- XAH deposits without WP_LNK acknowledgment and no raised funds. +- IOU deposits without participation data. +- Invalid invokes without required parameters. +- Transactions during refund mode that aren't incoming IOU payments. + +## Installation and Setup + +1. **Hook Chain Order**: Install the Router Hook as the first hook in the chain, followed by the IDO hook and Rewards hook. +2. **Parameters**: No runtime parameters required; all configuration is hardcoded. +3. **Dependencies**: Requires the IDO and Rewards hooks to be installed with matching hashes. + +## State Dependencies + +The Router queries the following state keys from the IDO namespace: +- START: IDO window start ledger. +- END: IDO window end ledger. +- REFUND: Refund mode flag. +- XAH: Total raised XAH (for permissive XAH deposits). +- IDO_DATA: User participation data (per account namespace). + +## Error Handling + +The Router Hook provides detailed error messages for debugging: +- "Router: Skip failed" - Hook skip operation failed. +- "Router: Cannot read sender account" - Unable to read transaction sender. +- Various routing-specific messages for invalid transactions. + +## Security Considerations + +- Hardcoded hashes prevent tampering with hook execution. +- Strict parameter validation ensures only intended transactions are processed. +- State queries use foreign namespaces to access IDO data securely. + +## Compatibility + +- Designed for Xahau network. +- Compatible with IDO and Rewards hooks from the HandyHook Collection. +- Uses standard Hook API functions for maximum compatibility. + +## Author + +@Handy_4ndy + +## License + +Part of the Xahau HandyHook Collection. See repository license for details. \ No newline at end of file diff --git a/IssuanceHookset/Docs/Samples/LedgerIssue.c b/IssuanceHookset/Docs/Samples/LedgerIssue.c new file mode 100644 index 0000000..fc46bdd --- /dev/null +++ b/IssuanceHookset/Docs/Samples/LedgerIssue.c @@ -0,0 +1,347 @@ +//************************************************************** +// Xahau Hook 101 Example ~ LedgerSeq Phase Hook with Hardcoded End +// Author: @Handy_4ndy +// +// Description: +// This hook accepts incoming payments during the active phase of a 4-phase window. +// The END offset is hardcoded on install. The window is set via invoke with START offset. +// Total window: START to START + 4*END. +// Phases: 1 (START to START+END), 2 (START+END to START+2*END), etc. +// Multipliers: Phase 1 (100x), Phase 2 (75x), Phase 3 (50x), Phase 4 (25x). +// Issues IOU tokens via Remit to the sender based on received XAH * multiplier. +// Installed on the issuer account, so hook account is the issuer. +// Only the hook account or designated admin can set the START parameter. +// +// Parameters (Install):- +// 'END' (4 byte uint32_t): Duration of each phase. +// 'ADMIN' (20 bytes): Admin account ID that can trigger invokes. +// 'CURRENCY' (20 bytes): IOU currency code. +// +// Parameters (Invoke):- +// 'START' (4 byte uint32_t): Offset from current ledger for start. +// +// Usage:- +// - Install with END, ADMIN, CURRENCY parameters on the issuer account. +// - Invoke with START to set the window (total end = current + START + 4*END). +// - Incoming XAH payments accepted during any active phase, issuing IOU tokens via Remit. +// - Amount received is multiplied by phase multiplier (100x, 75x, 50x, 25x) and remitted as IOU. +// - Outgoing payments always accepted. +// +// Accepts:- +// - Invoke transactions setting the window from authorized accounts. +// - Outgoing payments. +// - Incoming XAH payments during phases 1-4, issuing IOU tokens via Remit. +// +// Rejects:- +// - Incoming payments outside the window. +// - Invoke without START parameter. +// - Install without END, ADMIN, or CURRENCY parameter. +// - Unauthorized invokes. +// +//************************************************************** + +#include "hookapi.h" + +// Field codes for Remit transaction Amounts array +#define sfAmountEntry ((14U << 16U) + 91U) // 0xE0 0x5B +#define sfAmounts ((15U << 16U) + 92U) // 0xF0 0x5C + +// Utility macros +#define DONE(x) accept(SBUF(x), __LINE__) +#define NOPE(x) rollback(SBUF(x), __LINE__) +#define GUARD(maxiter) _g(__LINE__, (maxiter) + 1) + +// Convert 8-byte buffer to uint64 (big-endian) +#define UINT64_FROM_BUF(buf) \ + (((uint64_t)(buf)[0] << 56) + ((uint64_t)(buf)[1] << 48) + \ + ((uint64_t)(buf)[2] << 40) + ((uint64_t)(buf)[3] << 32) + \ + ((uint64_t)(buf)[4] << 24) + ((uint64_t)(buf)[5] << 16) + \ + ((uint64_t)(buf)[6] << 8) + (uint64_t)(buf)[7]) + +// Base Remit transaction template (229 bytes) +// clang-format off +uint8_t txn[350] = +{ +/* size,upto */ +/* 3, 0 */ 0x12U, 0x00U, 0x5FU, /* ttREMIT */ +/* 5, 3 */ 0x22U, 0x80U, 0x00U, 0x00U, 0x00U, /* Flags */ +/* 5, 8 */ 0x24U, 0x00U, 0x00U, 0x00U, 0x00U, /* Sequence */ +/* 6, 13 */ 0x20U, 0x1AU, 0x00U, 0x00U, 0x00U, 0x00U, /* FirstLedgerSequence */ +/* 6, 19 */ 0x20U, 0x1BU, 0x00U, 0x00U, 0x00U, 0x00U, /* LastLedgerSequence */ +/* 9, 25 */ 0x68U, 0x40U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, /* Fee */ +/* 35, 34 */ 0x73U, 0x21U, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* SigningPubKey */ +/* 22, 69 */ 0x81U, 0x14U, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* Account */ +/* 22, 91 */ 0x83U, 0x14U, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* Destination */ +/* 116, 113 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* EmitDetails */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +/* 0, 229 */ /* Amounts array appended here */ +}; +// clang-format on + +#define BASE_SIZE 229U +#define FLS_OUT (txn + 15U) +#define LLS_OUT (txn + 21U) +#define FEE_OUT (txn + 26U) +#define HOOK_ACC (txn + 71U) +#define DEST_ACC (txn + 93U) +#define EMIT_OUT (txn + 113U) +#define AMOUNTS_OUT (txn + 229U) + +int64_t hook(uint32_t reserved) { + + TRACESTR("LSW :: LedgerSeq Window Hook :: Called"); + + // Get hook account + uint8_t hook_acc[20]; + if (hook_account(SBUF(hook_acc)) != 20) + rollback(SBUF("LSW :: Error :: Failed to get hook account."), __LINE__); + + // Get admin account from hook param + uint8_t admin_acc[20]; + if (hook_param(SBUF(admin_acc), "ADMIN", 5) != 20) + rollback(SBUF("LSW :: Error :: ADMIN parameter not set."), __LINE__); + + // Get currency from hook param + uint8_t currency[20]; + if (hook_param(SBUF(currency), "CURRENCY", 8) != 20) + rollback(SBUF("LSW :: Error :: CURRENCY parameter not set."), __LINE__); + + // Get current ledger sequence + int64_t current_ledger = ledger_seq(); + + // Get transaction type + int64_t tt = otxn_type(); + + // Keys for state + uint8_t start_key[5] = {'S', 'T', 'A', 'R', 'T'}; + uint8_t end_key[3] = {'E', 'N', 'D'}; + + if (tt == ttINVOKE) { + // Set the window + + // Get originating account + uint8_t otxn_acc[20]; + if (otxn_field(SBUF(otxn_acc), sfAccount) != 20) + rollback(SBUF("LSW :: Error :: Failed to get origin account."), __LINE__); + + // Check authorization + if (!BUFFER_EQUAL_20(otxn_acc, hook_acc) && !BUFFER_EQUAL_20(otxn_acc, admin_acc)) + rollback(SBUF("LSW :: Error :: Unauthorized invoke."), __LINE__); + + // Get END from install parameters + uint8_t end_buf[4]; + if (hook_param(SBUF(end_buf), SBUF(end_key)) != 4) { + rollback(SBUF("LSW :: Error :: END not set on install."), __LINE__); + } + uint32_t end_offset = UINT32_FROM_BUF(end_buf); + + // Get START from invoke parameters + uint8_t start_buf[4]; + int64_t start_len = otxn_param(SBUF(start_buf), SBUF(start_key)); + if (start_len != 4) { + rollback(SBUF("LSW :: Error :: Invalid START parameter."), __LINE__); + } + uint32_t start_offset = UINT32_FROM_BUF(start_buf); + + uint32_t current_ledger_u = (uint32_t)current_ledger; + trace_num(SBUF("Current ledger at invoke = "), (uint64_t)current_ledger_u); + + uint32_t start_ledger = (uint32_t)current_ledger + start_offset; + uint32_t end_ledger = start_ledger + 4 * end_offset; + + TRACESTR("LSW :: Setting window"); + trace_num(SBUF("START offset = "), (uint64_t)start_offset); + trace_num(SBUF("END offset (per phase) = "), (uint64_t)end_offset); + uint8_t start_state[4]; + UINT32_TO_BUF(start_state, start_ledger); + uint8_t end_state[4]; + UINT32_TO_BUF(end_state, end_ledger); + trace_num(SBUF("Calculated start ledger = "), (uint64_t)start_ledger); + trace_num(SBUF("Calculated end ledger = "), (uint64_t)end_ledger); + + // Store in state + if (state_set(start_state, 4, start_key, 5) < 0 || + state_set(end_state, 4, end_key, 3) < 0) { + rollback(SBUF("LSW :: Error :: Failed to set state."), __LINE__); + } + + accept(SBUF("LSW :: Success :: Window set."), __LINE__); + + } else if (tt == ttPAYMENT) { + // Check payment + + TRACESTR("LSW :: Checking payment"); + uint32_t current_ledger_u = (uint32_t)current_ledger; + uint8_t ledger_buf[4]; + UINT32_TO_BUF(ledger_buf, current_ledger_u); + trace_num(SBUF("Current ledger = "), (uint64_t)current_ledger_u); + + // Get origin account + uint8_t otxn_acc[20]; + if (otxn_field(SBUF(otxn_acc), sfAccount) != 20) { + rollback(SBUF("LSW :: Error :: Failed to get origin account."), __LINE__); + } + + // If outgoing, accept + if (BUFFER_EQUAL_20(hook_acc, otxn_acc)) { + accept(SBUF("LSW :: Accepted :: Outgoing payment."), __LINE__); + } + + // Incoming payment, check window + uint8_t start_buf[4]; + uint8_t end_buf[4]; + + if (state(SBUF(start_buf), SBUF(start_key)) != 4 || + state(SBUF(end_buf), SBUF(end_key)) != 4) { + rollback(SBUF("LSW :: Error :: Window not set."), __LINE__); + } + + // Get END offset for phase calculation + uint8_t end_param_buf[4]; + if (hook_param(SBUF(end_param_buf), SBUF(end_key)) != 4) { + rollback(SBUF("LSW :: Error :: END not set."), __LINE__); + } + uint32_t end_offset = UINT32_FROM_BUF(end_param_buf); + + trace_num(SBUF("Stored start ledger = "), (uint64_t)UINT32_FROM_BUF(start_buf)); + trace_num(SBUF("Stored end ledger = "), (uint64_t)UINT32_FROM_BUF(end_buf)); + + // Get received amount from transaction + uint8_t amount_buffer[8]; + int64_t amount_len = otxn_field(SBUF(amount_buffer), sfAmount); + int64_t received_drops = AMOUNT_TO_DROPS(amount_buffer); + int64_t amount_xfl = float_set(-6, received_drops); + int64_t amount_int = float_int(amount_xfl, 0, 1); + + TRACEVAR(received_drops); + + int64_t received_xah = received_drops / 1000000; + TRACEVAR(received_xah); + + uint32_t start_ledger = UINT32_FROM_BUF(start_buf); + uint32_t end_ledger = UINT32_FROM_BUF(end_buf); + + if ((uint32_t)current_ledger >= start_ledger && (uint32_t)current_ledger < end_ledger) { + uint32_t elapsed = (uint32_t)current_ledger - start_ledger; + uint32_t phase = (elapsed / end_offset) + 1; + int64_t multiplier = 0; + if (phase == 1) { + multiplier = 100; + TRACESTR("LSW :: Phase 1 active."); + } else if (phase == 2) { + multiplier = 75; + TRACESTR("LSW :: Phase 2 active."); + } else if (phase == 3) { + multiplier = 50; + TRACESTR("LSW :: Phase 3 active."); + } else if (phase == 4) { + multiplier = 25; + TRACESTR("LSW :: Phase 4 active."); + } else { + rollback(SBUF("LSW :: Rejected :: Invalid phase."), __LINE__); + } + + TRACEVAR(phase); + + int64_t issued_amount = received_xah * multiplier; + if (issued_amount == 0) NOPE("LSW :: Issued amount is zero."); + TRACEVAR(issued_amount); + + // Build Amounts array + uint8_t* amounts_ptr = AMOUNTS_OUT; + + *amounts_ptr++ = 0xF0U; // sfAmounts array start + *amounts_ptr++ = 0x5CU; + + *amounts_ptr++ = 0xE0U; // sfAmountEntry object start + *amounts_ptr++ = 0x5BU; + + int64_t amount_xfl = float_set(0, issued_amount); + int32_t amount_len = float_sto( + amounts_ptr, 49, + currency, 20, + hook_acc, 20, + amount_xfl, + sfAmount + ); + + if (amount_len < 0) + NOPE("LSW :: Failed to serialize amount."); + + amounts_ptr += amount_len; + + *amounts_ptr++ = 0xE1U; // End AmountEntry + *amounts_ptr++ = 0xF1U; // End Amounts array + + int32_t amounts_len = amounts_ptr - AMOUNTS_OUT; + + // Fill transaction fields + hook_account(HOOK_ACC, 20); + + for (int i = 0; GUARD(20), i < 20; ++i) + DEST_ACC[i] = otxn_acc[i]; + + // Prepare for emission + etxn_reserve(1); + + int32_t total_size = BASE_SIZE + amounts_len; + + etxn_details(EMIT_OUT, 116U); + + // Encode ledger sequences + int64_t seq = ledger_seq() + 1; + txn[15] = (seq >> 24U) & 0xFFU; + txn[16] = (seq >> 16U) & 0xFFU; + txn[17] = (seq >> 8U) & 0xFFU; + txn[18] = seq & 0xFFU; + + seq += 4; + txn[21] = (seq >> 24U) & 0xFFU; + txn[22] = (seq >> 16U) & 0xFFU; + txn[23] = (seq >> 8U) & 0xFFU; + txn[24] = seq & 0xFFU; + + // Calculate and encode fee + int64_t fee = etxn_fee_base(txn, total_size); + + if (fee < 0) + NOPE("LSW :: Fee calculation failed."); + + uint64_t fee_tmp = fee; + uint8_t* fee_ptr = (uint8_t*)&fee; + *fee_ptr++ = 0b01000000 + ((fee_tmp >> 56) & 0b00111111); + *fee_ptr++ = (fee_tmp >> 48) & 0xFFU; + *fee_ptr++ = (fee_tmp >> 40) & 0xFFU; + *fee_ptr++ = (fee_tmp >> 32) & 0xFFU; + *fee_ptr++ = (fee_tmp >> 24) & 0xFFU; + *fee_ptr++ = (fee_tmp >> 16) & 0xFFU; + *fee_ptr++ = (fee_tmp >> 8) & 0xFFU; + *fee_ptr++ = (fee_tmp >> 0) & 0xFFU; + + *((uint64_t*)(txn + 26)) = fee; + + // Emit transaction + uint8_t emithash[32]; + int64_t emit_result = emit(SBUF(emithash), txn, total_size); + + if (emit_result < 0) + NOPE("LSW :: Emit failed."); + + accept(SBUF("LSW :: Accepted :: Incoming payment during active phase."), __LINE__); + } else { + if ((uint32_t)current_ledger < start_ledger) { + rollback(SBUF("LSW :: Rejected :: Window has not started."), __LINE__); + } else { + rollback(SBUF("LSW :: Rejected :: Window has ended."), __LINE__); + } + } + + } else { + // Other transactions, accept + accept(SBUF("LSW :: Accepted :: Other transaction."), __LINE__); + } + + _g(1,1); // Guard + return 0; +} diff --git a/IssuanceHookset/Docs/Samples/LedgerMultiple.c b/IssuanceHookset/Docs/Samples/LedgerMultiple.c new file mode 100644 index 0000000..b25a57a --- /dev/null +++ b/IssuanceHookset/Docs/Samples/LedgerMultiple.c @@ -0,0 +1,205 @@ +//************************************************************** +// Xahau Hook 101 Example ~ LedgerSeq Phase Hook with Hardcoded End +// Author: @Handy_4ndy +// +// Description: +// This hook accepts incoming payments during the active phase of a 4-phase window. +// The END offset is hardcoded on install. The window is set via invoke with START offset. +// Total window: START to START + 4*END. +// Phases: 1 (START to START+END), 2 (START+END to START+2*END), etc. +// Multipliers: Phase 1 (100x), Phase 2 (75x), Phase 3 (50x), Phase 4 (25x). +// Logs received amount and issued amount (received * multiplier). +// Only the hook account or designated admin can set the START parameter. +// +// Parameters (Install):- +// 'END' (4 byte uint32_t): Duration of each phase. +// 'ADMIN' (20 bytes): Admin account ID that can trigger invokes. +// +// Parameters (Invoke):- +// 'START' (4 byte uint32_t): Offset from current ledger for start. +// +// Usage:- +// - Install with END and ADMIN parameters. +// - Invoke with START to set the window (total end = current + START + 4*END). +// - Incoming payments accepted during any active phase with phase-specific message.// - Amount received is multiplied by phase multiplier (100x, 75x, 50x, 25x) and logged.// - Outgoing payments always accepted. +// +// Accepts:- +// - Invoke transactions setting the window from authorized accounts. +// - Outgoing payments. +// - Incoming payments during phases 1-4. +// +// Rejects:- +// - Incoming payments outside the window. +// - Invoke without START parameter. +// - Install without END or ADMIN parameter. +// - Unauthorized invokes. +// +//************************************************************** + +#include "hookapi.h" + +int64_t hook(uint32_t reserved) { + + TRACESTR("LSW :: LedgerSeq Window Hook :: Called"); + + // Get hook account + uint8_t hook_acc[20]; + if (hook_account(SBUF(hook_acc)) != 20) + rollback(SBUF("LSW :: Error :: Failed to get hook account."), __LINE__); + + // Get admin account from hook param + uint8_t admin_acc[20]; + if (hook_param(SBUF(admin_acc), "ADMIN", 5) != 20) + rollback(SBUF("LSW :: Error :: ADMIN parameter not set."), __LINE__); + + // Get current ledger sequence + int64_t current_ledger = ledger_seq(); + + // Get transaction type + int64_t tt = otxn_type(); + + // Keys for state + uint8_t start_key[5] = {'S', 'T', 'A', 'R', 'T'}; + uint8_t end_key[3] = {'E', 'N', 'D'}; + uint8_t amt_key[3] = {'A', 'M', 'T'}; + + if (tt == ttINVOKE) { + // Set the window + + // Get originating account + uint8_t otxn_acc[20]; + if (otxn_field(SBUF(otxn_acc), sfAccount) != 20) + rollback(SBUF("LSW :: Error :: Failed to get origin account."), __LINE__); + + // Check authorization + if (!BUFFER_EQUAL_20(otxn_acc, hook_acc) && !BUFFER_EQUAL_20(otxn_acc, admin_acc)) + rollback(SBUF("LSW :: Error :: Unauthorized invoke."), __LINE__); + + // Get END from install parameters + uint8_t end_buf[4]; + if (hook_param(SBUF(end_buf), SBUF(end_key)) != 4) { + rollback(SBUF("LSW :: Error :: END not set on install."), __LINE__); + } + uint32_t end_offset = UINT32_FROM_BUF(end_buf); + + // Get START from invoke parameters + uint8_t start_buf[4]; + int64_t start_len = otxn_param(SBUF(start_buf), SBUF(start_key)); + if (start_len != 4) { + rollback(SBUF("LSW :: Error :: Invalid START parameter."), __LINE__); + } + uint32_t start_offset = UINT32_FROM_BUF(start_buf); + + uint32_t current_ledger_u = (uint32_t)current_ledger; + trace_num(SBUF("Current ledger at invoke = "), (uint64_t)current_ledger_u); + + uint32_t start_ledger = (uint32_t)current_ledger + start_offset; + uint32_t end_ledger = start_ledger + 4 * end_offset; + + TRACESTR("LSW :: Setting window"); + trace_num(SBUF("START offset = "), (uint64_t)start_offset); + trace_num(SBUF("END offset (per phase) = "), (uint64_t)end_offset); + uint8_t start_state[4]; + UINT32_TO_BUF(start_state, start_ledger); + uint8_t end_state[4]; + UINT32_TO_BUF(end_state, end_ledger); + trace_num(SBUF("Calculated start ledger = "), (uint64_t)start_ledger); + trace_num(SBUF("Calculated end ledger = "), (uint64_t)end_ledger); + + // Store in state + if (state_set(start_state, 4, start_key, 5) < 0 || + state_set(end_state, 4, end_key, 3) < 0) { + rollback(SBUF("LSW :: Error :: Failed to set state."), __LINE__); + } + + accept(SBUF("LSW :: Success :: Window set."), __LINE__); + + } else if (tt == ttPAYMENT) { + // Check payment + + TRACESTR("LSW :: Checking payment"); + uint32_t current_ledger_u = (uint32_t)current_ledger; + uint8_t ledger_buf[4]; + UINT32_TO_BUF(ledger_buf, current_ledger_u); + trace_num(SBUF("Current ledger = "), (uint64_t)current_ledger_u); + + // Get origin account + uint8_t otxn_acc[20]; + if (otxn_field(SBUF(otxn_acc), sfAccount) != 20) { + rollback(SBUF("LSW :: Error :: Failed to get origin account."), __LINE__); + } + + // If outgoing, accept + if (BUFFER_EQUAL_20(hook_acc, otxn_acc)) { + accept(SBUF("LSW :: Accepted :: Outgoing payment."), __LINE__); + } + + // Incoming payment, check window + uint8_t start_buf[4]; + uint8_t end_buf[4]; + + if (state(SBUF(start_buf), SBUF(start_key)) != 4 || + state(SBUF(end_buf), SBUF(end_key)) != 4) { + rollback(SBUF("LSW :: Error :: Window not set."), __LINE__); + } + + // Get END offset for phase calculation + uint8_t end_param_buf[4]; + if (hook_param(SBUF(end_param_buf), SBUF(end_key)) != 4) { + rollback(SBUF("LSW :: Error :: END not set."), __LINE__); + } + uint32_t end_offset = UINT32_FROM_BUF(end_param_buf); + + trace_num(SBUF("Stored start ledger = "), (uint64_t)UINT32_FROM_BUF(start_buf)); + trace_num(SBUF("Stored end ledger = "), (uint64_t)UINT32_FROM_BUF(end_buf)); + + // Get received amount from transaction + uint8_t amount_buffer[8]; + int64_t amount_len = otxn_field(SBUF(amount_buffer), sfAmount); + int64_t received_drops = AMOUNT_TO_DROPS(amount_buffer); + int64_t amount_xfl = float_set(-6, received_drops); + int64_t amount_int = float_int(amount_xfl, 0, 1); + + TRACEVAR(received_drops); + + uint32_t start_ledger = UINT32_FROM_BUF(start_buf); + uint32_t end_ledger = UINT32_FROM_BUF(end_buf); + + if ((uint32_t)current_ledger >= start_ledger && (uint32_t)current_ledger < end_ledger) { + uint32_t elapsed = (uint32_t)current_ledger - start_ledger; + uint32_t phase = (elapsed / end_offset) + 1; + if (phase == 1) { + int64_t issued_drops = received_drops * 100; + TRACEVAR(issued_drops); + accept(SBUF("LSW :: Accepted :: Incoming payment during phase 1."), __LINE__); + } else if (phase == 2) { + int64_t issued_drops = received_drops * 75; + TRACEVAR(issued_drops); + accept(SBUF("LSW :: Accepted :: Incoming payment during phase 2."), __LINE__); + } else if (phase == 3) { + int64_t issued_drops = received_drops * 50; + TRACEVAR(issued_drops); + accept(SBUF("LSW :: Accepted :: Incoming payment during phase 3."), __LINE__); + } else if (phase == 4) { + int64_t issued_drops = received_drops * 25; + TRACEVAR(issued_drops); + accept(SBUF("LSW :: Accepted :: Incoming payment during phase 4."), __LINE__); + } else { + rollback(SBUF("LSW :: Rejected :: Invalid phase."), __LINE__); + } + } else { + if ((uint32_t)current_ledger < start_ledger) { + rollback(SBUF("LSW :: Rejected :: Window has not started."), __LINE__); + } else { + rollback(SBUF("LSW :: Rejected :: Window has ended."), __LINE__); + } + } + + } else { + // Other transactions, accept + accept(SBUF("LSW :: Accepted :: Other transaction."), __LINE__); + } + + _g(1,1); // Guard + return 0; +} diff --git a/IssuanceHookset/Docs/Samples/LedgerPhase.c b/IssuanceHookset/Docs/Samples/LedgerPhase.c new file mode 100644 index 0000000..68f1071 --- /dev/null +++ b/IssuanceHookset/Docs/Samples/LedgerPhase.c @@ -0,0 +1,186 @@ +//************************************************************** +// Xahau Hook 101 Example ~ LedgerSeq Phase Hook with Hardcoded End +// Author: @Handy_4ndy +// +// Description: +// This hook accepts incoming payments during the active phase of a 4-phase window. +// The END offset is hardcoded on install. The window is set via invoke with START offset. +// Total window: START to START + 4*END. +// Phases: 1 (START to START+END), 2 (START+END to START+2*END), etc. +// Only the hook account or designated admin can set the START parameter. +// +// Parameters (Install):- +// 'END' (4 byte uint32_t): Duration of each phase. +// 'ADMIN' (20 bytes): Admin account ID that can trigger invokes. +// +// Parameters (Invoke):- +// 'START' (4 byte uint32_t): Offset from current ledger for start. +// +// Usage:- +// - Install with END and ADMIN parameters. +// - Invoke with START to set the window (total end = current + START + 4*END). +// - Incoming payments accepted during any active phase with phase-specific message. +// - Outgoing payments always accepted. +// +// Accepts:- +// - Invoke transactions setting the window from authorized accounts. +// - Outgoing payments. +// - Incoming payments during phases 1-4. +// +// Rejects:- +// - Incoming payments outside the window. +// - Invoke without START parameter. +// - Install without END or ADMIN parameter. +// - Unauthorized invokes. +// +//************************************************************** + +#include "hookapi.h" + +int64_t hook(uint32_t reserved) { + + TRACESTR("LSW :: LedgerSeq Window Hook :: Called"); + + // Get hook account + uint8_t hook_acc[20]; + if (hook_account(SBUF(hook_acc)) != 20) + rollback(SBUF("LSW :: Error :: Failed to get hook account."), __LINE__); + + // Get admin account from hook param + uint8_t admin_acc[20]; + if (hook_param(SBUF(admin_acc), "ADMIN", 5) != 20) + rollback(SBUF("LSW :: Error :: ADMIN parameter not set."), __LINE__); + + // Get current ledger sequence + int64_t current_ledger = ledger_seq(); + + // Get transaction type + int64_t tt = otxn_type(); + + // Keys for state + uint8_t start_key[5] = {'S', 'T', 'A', 'R', 'T'}; + uint8_t end_key[3] = {'E', 'N', 'D'}; + + if (tt == ttINVOKE) { + // Set the window + + // Get originating account + uint8_t otxn_acc[20]; + if (otxn_field(SBUF(otxn_acc), sfAccount) != 20) + rollback(SBUF("LSW :: Error :: Failed to get origin account."), __LINE__); + + // Check authorization + if (!BUFFER_EQUAL_20(otxn_acc, hook_acc) && !BUFFER_EQUAL_20(otxn_acc, admin_acc)) + rollback(SBUF("LSW :: Error :: Unauthorized invoke."), __LINE__); + + // Get END from install parameters + uint8_t end_buf[4]; + if (hook_param(SBUF(end_buf), SBUF(end_key)) != 4) { + rollback(SBUF("LSW :: Error :: END not set on install."), __LINE__); + } + uint32_t end_offset = UINT32_FROM_BUF(end_buf); + + // Get START from invoke parameters + uint8_t start_buf[4]; + int64_t start_len = otxn_param(SBUF(start_buf), SBUF(start_key)); + if (start_len != 4) { + rollback(SBUF("LSW :: Error :: Invalid START parameter."), __LINE__); + } + uint32_t start_offset = UINT32_FROM_BUF(start_buf); + + uint32_t current_ledger_u = (uint32_t)current_ledger; + trace_num(SBUF("Current ledger at invoke = "), (uint64_t)current_ledger_u); + + uint32_t start_ledger = (uint32_t)current_ledger + start_offset; + uint32_t end_ledger = start_ledger + 4 * end_offset; + + TRACESTR("LSW :: Setting window"); + trace_num(SBUF("START offset = "), (uint64_t)start_offset); + trace_num(SBUF("END offset (per phase) = "), (uint64_t)end_offset); + uint8_t start_state[4]; + UINT32_TO_BUF(start_state, start_ledger); + uint8_t end_state[4]; + UINT32_TO_BUF(end_state, end_ledger); + trace_num(SBUF("Calculated start ledger = "), (uint64_t)start_ledger); + trace_num(SBUF("Calculated end ledger = "), (uint64_t)end_ledger); + + // Store in state + if (state_set(start_state, 4, start_key, 5) < 0 || + state_set(end_state, 4, end_key, 3) < 0) { + rollback(SBUF("LSW :: Error :: Failed to set state."), __LINE__); + } + + accept(SBUF("LSW :: Success :: Window set."), __LINE__); + + } else if (tt == ttPAYMENT) { + // Check payment + + TRACESTR("LSW :: Checking payment"); + uint32_t current_ledger_u = (uint32_t)current_ledger; + uint8_t ledger_buf[4]; + UINT32_TO_BUF(ledger_buf, current_ledger_u); + trace_num(SBUF("Current ledger = "), (uint64_t)current_ledger_u); + + // Get origin account + uint8_t otxn_acc[20]; + if (otxn_field(SBUF(otxn_acc), sfAccount) != 20) { + rollback(SBUF("LSW :: Error :: Failed to get origin account."), __LINE__); + } + + // If outgoing, accept + if (BUFFER_EQUAL_20(hook_acc, otxn_acc)) { + accept(SBUF("LSW :: Accepted :: Outgoing payment."), __LINE__); + } + + // Incoming payment, check window + uint8_t start_buf[4]; + uint8_t end_buf[4]; + + if (state(SBUF(start_buf), SBUF(start_key)) != 4 || + state(SBUF(end_buf), SBUF(end_key)) != 4) { + rollback(SBUF("LSW :: Error :: Window not set."), __LINE__); + } + + // Get END offset for phase calculation + uint8_t end_param_buf[4]; + if (hook_param(SBUF(end_param_buf), SBUF(end_key)) != 4) { + rollback(SBUF("LSW :: Error :: END not set."), __LINE__); + } + uint32_t end_offset = UINT32_FROM_BUF(end_param_buf); + + trace_num(SBUF("Stored start ledger = "), (uint64_t)UINT32_FROM_BUF(start_buf)); + trace_num(SBUF("Stored end ledger = "), (uint64_t)UINT32_FROM_BUF(end_buf)); + + uint32_t start_ledger = UINT32_FROM_BUF(start_buf); + uint32_t end_ledger = UINT32_FROM_BUF(end_buf); + + if ((uint32_t)current_ledger >= start_ledger && (uint32_t)current_ledger < end_ledger) { + uint32_t elapsed = (uint32_t)current_ledger - start_ledger; + uint32_t phase = (elapsed / end_offset) + 1; + if (phase == 1) { + accept(SBUF("LSW :: Accepted :: Incoming payment during phase 1."), __LINE__); + } else if (phase == 2) { + accept(SBUF("LSW :: Accepted :: Incoming payment during phase 2."), __LINE__); + } else if (phase == 3) { + accept(SBUF("LSW :: Accepted :: Incoming payment during phase 3."), __LINE__); + } else if (phase == 4) { + accept(SBUF("LSW :: Accepted :: Incoming payment during phase 4."), __LINE__); + } else { + rollback(SBUF("LSW :: Rejected :: Invalid phase."), __LINE__); + } + } else { + if ((uint32_t)current_ledger < start_ledger) { + rollback(SBUF("LSW :: Rejected :: Window has not started."), __LINE__); + } else { + rollback(SBUF("LSW :: Rejected :: Window has ended."), __LINE__); + } + } + + } else { + // Other transactions, accept + accept(SBUF("LSW :: Accepted :: Other transaction."), __LINE__); + } + + _g(1,1); // Guard + return 0; +} diff --git a/IssuanceHookset/Docs/Samples/LedgerSeq.c b/IssuanceHookset/Docs/Samples/LedgerSeq.c new file mode 100644 index 0000000..64d5c56 --- /dev/null +++ b/IssuanceHookset/Docs/Samples/LedgerSeq.c @@ -0,0 +1,145 @@ +//************************************************************** +// Xahau Hook 101 Example ~ LedgerSeq Window Hook +// Author: @Handy_4ndy +// +// Description: +// This hook accepts incoming payments only within a ledger sequence window. +// The window is set via invoke with START and END offsets. +// +// Parameters (Invoke):- +// 'START' (4 byte uint32_t): Offset from current ledger for start. +// 'END' (4 byte uint32_t): Duration of the window. +// +// Usage:- +// - Invoke with START and END to set the window. +// - Incoming payments accepted only if current ledger is within [start, end]. +// - Outgoing payments always accepted. +// +// Accepts:- +// - Invoke transactions setting the window. +// - Outgoing payments. +// - Incoming payments within the window. +// +// Rejects:- +// - Incoming payments outside the window. +// - Invoke without proper parameters. +// +//************************************************************** + +#include "hookapi.h" + +int64_t hook(uint32_t reserved) { + + TRACESTR("LSW :: LedgerSeq Window Hook :: Called"); + + // Get current ledger sequence + int64_t current_ledger = ledger_seq(); + + // Get transaction type + int64_t tt = otxn_type(); + + // Keys for state + uint8_t start_key[5] = {'S', 'T', 'A', 'R', 'T'}; + uint8_t end_key[3] = {'E', 'N', 'D'}; + + if (tt == ttINVOKE) { + // Set the window + + uint8_t start_buf[4]; + uint8_t end_buf[4]; + + int64_t start_len = otxn_param(SBUF(start_buf), SBUF(start_key)); + int64_t end_len = otxn_param(SBUF(end_buf), SBUF(end_key)); + + if (start_len != 4 || end_len != 4) { + rollback(SBUF("LSW :: Error :: Invalid START or END parameters."), __LINE__); + } + + uint32_t start_offset = UINT32_FROM_BUF(start_buf); + uint32_t end_offset = UINT32_FROM_BUF(end_buf); + + uint32_t current_ledger_u = (uint32_t)current_ledger; + uint8_t current_buf[4]; + UINT32_TO_BUF(current_buf, current_ledger_u); + trace_num(SBUF("Current ledger at invoke = "), (uint64_t)current_ledger_u); + + uint32_t start_ledger = (uint32_t)current_ledger + start_offset; + uint32_t end_ledger = (uint32_t)current_ledger + start_offset + end_offset; + + TRACESTR("LSW :: Setting window"); + trace_num(SBUF("START offset = "), (uint64_t)start_offset); + trace_num(SBUF("END offset = "), (uint64_t)end_offset); + uint8_t start_state[4]; + UINT32_TO_BUF(start_state, start_ledger); + uint8_t end_state[4]; + UINT32_TO_BUF(end_state, end_ledger); + trace_num(SBUF("Calculated start ledger = "), (uint64_t)start_ledger); + trace_num(SBUF("Calculated end ledger = "), (uint64_t)end_ledger); + + // Store in state + if (state_set(start_state, 4, start_key, 5) < 0 || + state_set(end_state, 4, end_key, 3) < 0) { + rollback(SBUF("LSW :: Error :: Failed to set state."), __LINE__); + } + + accept(SBUF("LSW :: Success :: Window set."), __LINE__); + + } else if (tt == ttPAYMENT) { + // Check payment + + TRACESTR("LSW :: Checking payment"); + uint32_t current_ledger_u = (uint32_t)current_ledger; + uint8_t ledger_buf[4]; + UINT32_TO_BUF(ledger_buf, current_ledger_u); + trace_num(SBUF("Current ledger = "), (uint64_t)current_ledger_u); + + // Get hook account + uint8_t hook_acc[20]; + if (hook_account(SBUF(hook_acc)) != 20) { + rollback(SBUF("LSW :: Error :: Failed to get hook account."), __LINE__); + } + + // Get origin account + uint8_t otxn_acc[20]; + if (otxn_field(SBUF(otxn_acc), sfAccount) != 20) { + rollback(SBUF("LSW :: Error :: Failed to get origin account."), __LINE__); + } + + // If outgoing, accept + if (BUFFER_EQUAL_20(hook_acc, otxn_acc)) { + accept(SBUF("LSW :: Accepted :: Outgoing payment."), __LINE__); + } + + // Incoming payment, check window + uint8_t start_buf[4]; + uint8_t end_buf[4]; + + if (state(SBUF(start_buf), SBUF(start_key)) != 4 || + state(SBUF(end_buf), SBUF(end_key)) != 4) { + rollback(SBUF("LSW :: Error :: Window not set."), __LINE__); + } + + trace_num(SBUF("Stored start ledger = "), (uint64_t)UINT32_FROM_BUF(start_buf)); + trace_num(SBUF("Stored end ledger = "), (uint64_t)UINT32_FROM_BUF(end_buf)); + + uint32_t start_ledger = UINT32_FROM_BUF(start_buf); + uint32_t end_ledger = UINT32_FROM_BUF(end_buf); + + if ((uint32_t)current_ledger >= start_ledger && (uint32_t)current_ledger <= end_ledger) { + accept(SBUF("LSW :: Accepted :: Incoming payment within window."), __LINE__); + } else { + if ((uint32_t)current_ledger < start_ledger) { + rollback(SBUF("LSW :: Rejected :: Window has not started."), __LINE__); + } else { + rollback(SBUF("LSW :: Rejected :: Window has ended."), __LINE__); + } + } + + } else { + // Other transactions, accept + accept(SBUF("LSW :: Accepted :: Other transaction."), __LINE__); + } + + _g(1,1); // Guard + return 0; +} diff --git a/IssuanceHookset/Docs/Transactions/Hookset.json b/IssuanceHookset/Docs/Transactions/Hookset.json new file mode 100644 index 0000000..5adaf67 --- /dev/null +++ b/IssuanceHookset/Docs/Transactions/Hookset.json @@ -0,0 +1,339 @@ +{ + "Account": "raXdWCS1Ro8gVER2zRQMPn3pm4kLdD7okD", + "Fee": "1000", + "Flags": 0, + "Hooks": [ + { + "Hook": { + "Flags": 1, + "HookHash": "B952D1A5B03230EE3DA880571FB1438E67B29A0F4101FC76B784F1B7495F3BC1", + "HookNamespace": "065D8E6C0BF74A69A6D312C3D5B5CC627434CECE07B2787C1A538FCFD9F9C8DE", + "HookOn": "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFFFFFFFFFBFFFFE", + "HookParameters": [] + } + }, + { + "Hook": { + "Flags": 1, + "HookHash": "330961A6811A03131B590D0C69211447E78DF7208898A44F8CC1E13C629F2D2D", + "HookNamespace": "516BA79215002276EF4C381B901955C53A04575589607E7DBA20468DD343DD72", + "HookOn": "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFFFFFFFFFBFFFFE", + "HookParameters": [ + { + "HookParameter": { + "HookParameterName": "494E54455256414C", + "HookParameterValue": "0000001E" + } + }, + { + "HookParameter": { + "HookParameterName": "41444D494E", + "HookParameterValue": "ABA521D9DCB3602C15AE7CDA813AA9CA790E8B3D" + } + }, + { + "HookParameter": { + "HookParameterName": "43555252454E4359", + "HookParameterValue": "5453540000000000000000000000000000000000" + } + }, + { + "HookParameter": { + "HookParameterName": "57505F4C4E4B", + "HookParameterValue": "68747470733A2F2F787370656E63652E636F2E756B" + } + }, + { + "HookParameter": { + "HookParameterName": "534F46545F434150", + "HookParameterValue": "000000000000000A" + } + } + ] + } + }, + { + "Hook": { + "Flags": 1, + "HookHash": "8CFC9AA6AA4A858DEF04D3049D4E7D22A37F968D050634244EC5DACECCE6160D", + "HookNamespace": "59AFE47D9D3772675632EE5EBBFFEEB325D9A094387C87E3818357F4BD46FCC7", + "HookOn": "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFFFFFFFFFBFFFFF", + "HookParameters": [ + { + "HookParameter": { + "HookParameterName": "43555252454E4359", + "HookParameterValue": "5453540000000000000000000000000000000000" + } + }, + { + "HookParameter": { + "HookParameterName": "41444D494E", + "HookParameterValue": "ABA521D9DCB3602C15AE7CDA813AA9CA790E8B3D" + } + }, + { + "HookParameter": { + "HookParameterName": "494E545F52415445", + "HookParameterValue": "000000C8" + } + }, + { + "HookParameter": { + "HookParameterName": "5345545F494E54455256414C", + "HookParameterValue": "0000001E" + } + } + ] + } + } + ], + "LastLedgerSequence": 20392296, + "NetworkID": 21337, + "Sequence": 800025817, + "SigningPubKey": "02D90D375BB5746A0772F59F510A396F10C6EF68C82F9DA4B0456129A4F60D08A5", + "TransactionType": "SetHook", + "TxnSignature": "3045022100CA45E2BBF846FC2CF30C5099DEF4D50DA587A4434D02B5F2A6E39E0EB97923F4022078221F2318FBDBEB67F54D89A341FA2200134CD6FC64175C9EC17B57748E62EE", + "ctid": "C137295600015359", + "date": 823215141, + "hash": "7189E633C9DA44F6DC30F8633F2E1D34DF7C6730BE412C1DA3BD4FA932365036", + "inLedger": 20392278, + "ledger_index": 20392278, + "meta": { + "AffectedNodes": [ + { + "ModifiedNode": { + "FinalFields": { + "CreateCode": "0061736D0100000001720F60057F7F7F7F7F017E6000017E60037F7F7E017E60027F7F017E60037F7F7F017E60047F7F7F7F017E60097F7F7F7F7F7F7F7F7F017E60017F017E60027F7E017E60037E7E7F017E60017E017E60027E7E017E60027F7F017F60087F7F7F7F7F7F7F7F017E60087F7F7F7F7F7F7E7F017E02DB031C03656E76057472616365000003656E76096F74786E5F74797065000103656E7606616363657074000203656E760C686F6F6B5F6163636F756E74000303656E7608726F6C6C6261636B000203656E760A6F74786E5F6669656C64000403656E760A686F6F6B5F706172616D000503656E760973746174655F736574000503656E760A6F74786E5F706172616D000503656E76057374617465000503656E760B7574696C5F6B65796C6574000603656E7608736C6F745F736574000403656E760D736C6F745F7375626669656C64000403656E760A736C6F745F666C6F6174000703656E7609666C6F61745F736574000803656E760D666C6F61745F636F6D70617265000903656E760C666C6F61745F6E6567617465000A03656E760C666C6F61745F646976696465000B03656E760E666C6F61745F6D756C7469706C79000B03656E76025F67000C03656E760D73746174655F666F726569676E000D03656E760A6C65646765725F736571000103656E7609666C6F61745F73746F000E03656E760C6574786E5F72657365727665000703656E760C6574786E5F64657461696C73000303656E760D6574786E5F6665655F62617365000303656E7604656D6974000503656E761173746174655F666F726569676E5F736574000D0302010705030100020631087F0141F099040B7F004190170B7F004180080B7F0041EE190B7F004180080B7F0041F099040B7F0041000B7F0041010B07080104686F6F6B001C0AF9910001F5910002057F037E23004190036B2200240041BD16412741A1154126410010001A100142E30052044041A5124139423010021A0B200041F0026A411410034214520440419F0C412C423310041A0B200041D0026A4114418180201005421452044041F10B412E423610041A0B20002903F00220002903D002510440024020002903F80220002903D802520D0020002802800320002802E002470D0041E711413E423810021A0B0B200041B0026A411441800841081006421452044041E70D41C300423B10041A0B20004190026A411441980841051006421452044041AA0E41C000423E10041A0B200042C99CD1FAA5AA90AAC50037038802200042C39885CAD4E9D7A4CE0037038002200042CD82E1FAB588D3263703F801200041F4016A410441B3084108100642045104400240200041F4016A410420004188026A410810074204510D0041F213413A42C50010041A0B0B200041F0016A410441A608410C10064204510440200041F0016A410420004180026A41081007420452044041E610413B42CA0010041A0B0B200041EC016A4104418908410E10064204510440200041EC016A4104200041F8016A41081007420452044041B00D413742CF0010041A0B0B024020002903D002200029039002510440024020002903D802200029039802520D0020002802E00220002802A002470D00200041A0016A410441B308410810084204510440200041A0016A410420004188026A41081007420452044041C513412D42D50010041A0B41B209413942D60010021A0B20004180016A410441A608410C1008420451044020004180016A410420004180026A41081007420452044041B810412E42DB0010041A0B41F808413A42DC0010021A0B200041406B4104418908410E10084204510440200041406B4104200041F8016A41081007420452044041CB0C413042E10010041A0B41BC08413C42E20010021A0B41F81541C50042E40010021A0C020B0B200041D0016A4114419E0841071008421452044041A11141C60042F70110021A0C010B200041CC016A410420004188026A41081009420452044041ED0A41D20042EA0010041A0B20002800CC0122014118742001410874418080FC07717220014108764180FE037120014118767272220445044041DE12413A42EE0010041A0B200041C8016A410420004180026A410810094204520440419A0A41D30042F10010041A0B20002800C8012101200041C4016A4104200041F8016A41081009420451044020002800C40122024118742002410874418080FC07717220024108764180FE03712002411876727221030B200041A0016A41224109200041F0026A4114200041D0026A4114200041B0026A4114100A422252044041FB0C413542FD0010041A0B200041A0016A41224101100B420152044041AC1441C30042FF0010041A0B4101418280184101100C420152044041EF14413242810110041A0B4101100D220641004200100E4102100F42015104402006101021060B41002004AD100E41004290CE00100E220710112208420053044041CE0F412A42890110041A0B20062008101222084200530440419C0F4132428C0110041A0B20014108764180FE03712001411876722001410874418080FC0771200141187472722105410021010340418E01411510131A200141144645044020004180016A20016A200041D0026A20016A2D00003A0000200141016A21010C010B0B411421010340419001412110131A200141204645044020004180016A20016A41003A0000200141016A21010C010B0B200042C988BDFAC5A890AAC10037037820004200370368200042003703600240200041E0006A4110200041F8006A410820004180016A4120200041F0026A4114101442105104404200200031006F7D2000310069423086200031006842388684200031006A42288684200031006B42208684200031006C42188684200031006D42108684200031006E42088684510D014100200441F4036AAD100E2007101122074200530D0120062007101221080B0B200041D8006A418817290300370300200041D0006A418017290300370300200041F816290300370348200041F016290300370340410A2101034041A101412110131A2001412046450440200041406B20016A41003A0000200141016A21010C010B0B20004200370338200041386A4108200041406B412020004180016A4120200041F0026A41141014410021021015210742085104400240200028023C22014118742001410874418080FC07717220014108764180FE0371200141187672722102200028023822014118742001410874418080FC07717220014108764180FE0371200141187672722201450D002007A720016B20054F0D0041F80F41C00042B20110041A0B0B20030440200220034F044041C715413142B60110041A0B0B41D717411410031A41002101034041B801411510131A2001411446450440200141ED176A200041D0026A20016A2D00003A0000200141016A21010C010B0B41F51841F0B981DF0536000041F9184131200041B0026A411441D71741142008418180181016A72201410048044041BF0B413242C70110041A0B200141F9186A41E1E3033B0000410110171A41A817200742017C220642FFFFFFFF0F8342047C22083C000041A21720063C000041A11720064208883C000041A01720064210883C0000419F1720064218883C000041A71720084208883C000041A61720084210883C000041A51720084218883C000041811841F40010181A41B117419017200141EB016A2201101922063C000041B01720064208883C000041AF1720064210883C000041AE1720064218883C000041AD1720064220883C000041AC1720064228883C000041AB1720064230883C000041AA172006423888A7413F7141C000723A0000200041106A41204190172001101A420053044041EA0E413242E70110041A0B200020073C000B200020074208883C000A200020074210883C0009200020074218883C00082000200241016A22013A000F200020014108763A000E200020014110763A000D200020014118763A000C200041086A4108200041406B412020004180016A4120200041F0026A4114101B4208520440419813412D42F40110041A0B41EB09412F42F50110021A0B4101410110131A20004190036A240042000B0BB60F05004180080BE40E43555252454E4359005345545F4D41585F434C41494D530041444D494E00525F434C41494D005345545F494E54455256414C00494E545F5241544500495248203A3A2053756363657373203A3A204D617820636C61696D73206C696D697420636F6E66696775726564207375636365737366756C6C792E00495248203A3A2053756363657373203A3A20436C61696D20696E74657276616C20636F6E66696775726564207375636365737366756C6C792E00495248203A3A2053756363657373203A3A20496E746572657374207261746520636F6E66696775726564207375636365737366756C6C792E00495248203A3A2053756363657373203A3A20546F6B656E7320636C61696D6564207375636365737366756C6C792E00495248203A3A204572726F72203A3A205345545F494E54455256414C206E6F7420636F6E66696775726564202D2061646D696E206D7573742073657420636C61696D20696E74657276616C2066697273742E00495248203A3A204572726F72203A3A20494E545F52415445206E6F7420636F6E66696775726564202D2061646D696E206D75737420757365205345545F494E5445524553545F524154452066697273742E00495248203A3A204572726F72203A3A204661696C656420746F2073657269616C697A6520636C61696D20616D6F756E742E00495248203A3A204572726F72203A3A204661696C656420746F20676574206F726967696E206163636F756E742E00495248203A3A204572726F72203A3A204661696C656420746F2067657420686F6F6B206163636F756E742E00495248203A3A204572726F72203A3A204661696C656420746F20736574206D617820636C61696D73206C696D69742E00495248203A3A204572726F72203A3A20436F756C64206E6F742067656E65726174652074727573746C696E65206B65796C65742E00495248203A3A204572726F72203A3A204661696C656420746F2073657420696E7374616C6C2D74696D65206D617820636C61696D732E00495248203A3A204572726F72203A3A204D6973636F6E666967757265642E2043555252454E4359206E6F742073657420617320486F6F6B20506172616D657465722E00495248203A3A204572726F72203A3A204D6973636F6E666967757265642E2041444D494E206E6F742073657420617320486F6F6B20506172616D657465722E00495248203A3A204572726F72203A3A204661696C656420746F20656D697420636C61696D207472616E73616374696F6E2E00495248203A3A204572726F72203A3A20496E76616C696420636C61696D20616D6F756E742063616C63756C6174696F6E2E00495248203A3A204572726F72203A3A20496E76616C696420726174652063616C63756C6174696F6E2E00495248203A3A204572726F72203A3A20546F6F20736F6F6E202D2077616974206D6F7265206C656467657273206265666F7265206E65787420636C61696D2E00495248203A3A204572726F72203A3A204661696C656420746F2073657420636C61696D20696E74657276616C2E00495248203A3A204572726F72203A3A204661696C656420746F2073657420696E7374616C6C2D74696D6520636C61696D20696E74657276616C2E00495248203A3A2053756363657373203A3A20496E766F6B652066726F6D206E6F6E2D77686974656C6973746564206163636F756E7420706173736564207468726F7567682E00495248203A3A2053756363657373203A3A204F7574676F696E6720696E766F6B65207472616E73616374696F6E20706173736564207468726F7567682E00495248203A3A2053756363657373203A3A204E6F6E2D494E564F4B45207472616E73616374696F6E20706173736564207468726F7567682E00495248203A3A204572726F72203A3A20496E76616C696420696E7465726573742072617465202D206D75737420626520706F7369746976652E00495248203A3A204572726F72203A3A204661696C656420746F2075706461746520757365722073746174652E00495248203A3A204572726F72203A3A204661696C656420746F2073657420696E74657265737420726174652E00495248203A3A204572726F72203A3A204661696C656420746F2073657420696E7374616C6C2D74696D6520696E74657265737420726174652E00495248203A3A204572726F72203A3A20436C61696D616E74206163636F756E7420646F6573206E6F7420686176652072657175697265642074727573746C696E652E00495248203A3A204572726F72203A3A20436F756C64206E6F74206C6F61642074727573746C696E652062616C616E63652E00495248203A3A20497373756564205265776172647320486F6F6B203A3A2043616C6C65642E00495248203A3A204572726F72203A3A204D6178696D756D206C69666574696D6520636C61696D7320726561636865642E00495248203A3A2053756363657373203A3A2041646D696E20636F6E66696775726174696F6E3A204E6F2076616C696420706172616D65746572732070726F76696465642E0022495248203A3A20497373756564205265776172647320486F6F6B203A3A2043616C6C65642E220041F0160B0A434C41494D5F44415441004190170B2412005F22800000002400000000201A00000000201B0000000068400000000000000073210041D5170B0281140041EB170B028314", + "Fee": "3359", + "Flags": 0, + "HookApiVersion": 0, + "HookHash": "8CFC9AA6AA4A858DEF04D3049D4E7D22A37F968D050634244EC5DACECCE6160D", + "HookNamespace": "59AFE47D9D3772675632EE5EBBFFEEB325D9A094387C87E3818357F4BD46FCC7", + "HookOn": "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFFFFFFFFFBFFFFF", + "HookParameters": [ + { + "HookParameter": { + "HookParameterName": "43555252454E4359", + "HookParameterValue": "0000000000000000000000005453540000000000" + } + }, + { + "HookParameter": { + "HookParameterName": "41444D494E", + "HookParameterValue": "ABA521D9DCB3602C15AE7CDA813AA9CA790E8B3D" + } + }, + { + "HookParameter": { + "HookParameterName": "494E545F52415445", + "HookParameterValue": "000003E8" + } + }, + { + "HookParameter": { + "HookParameterName": "5345545F494E54455256414C", + "HookParameterValue": "0000000A" + } + } + ], + "HookSetTxnID": "A0705D8E2105769C0E090CB01750A40C994662C0804782F3DAF41831CCC7FC10", + "ReferenceCount": "3" + }, + "LedgerEntryType": "HookDefinition", + "LedgerIndex": "008331CDA25CE3A11AEBDBA97C3D10821C175FFA8CF4FB025F67D57571E5EB55", + "PreviousFields": { + "ReferenceCount": "2" + } + } + }, + { + "ModifiedNode": { + "FinalFields": { + "CreateCode": "0061736D0100000001380860027F7F017E60037F7F7F017E60037F7F7E017E60027F7F017F6000017E60047F7F7F7F017E60087F7F7F7F7F7F7F7F017E60017F017E02AC010B03656E760C686F6F6B5F6163636F756E74000003656E760A6F74786E5F6669656C64000103656E7608726F6C6C6261636B000203656E76025F67000303656E76096F74786E5F74797065000403656E7609686F6F6B5F736B6970000103656E7606616363657074000203656E760A6F74786E5F706172616D000503656E760A6C65646765725F736571000403656E760D73746174655F666F726569676E000603656E760573746174650005030201070503010002063D0A7F01418090040B7F0041A00F0B7F0041C00F0B7F0041E00F0B7F004180080B7F004180100B7F004180080B7F00418090040B7F0041000B7F0041010B07080104686F6F6B000B0A948C0001908C0002057F027E230041B0036B2200240020004190036A411410001A200041F0026A411441818020100142145204404180084123421A10021A0B027F027F0240024002400340411E411510031A20014114460D0120004190036A20016A2104200041F0026A20016A200141016A21012D000020042D0000460D000B10042106200141016B41144921010C010B100422065045044041002101200642E300520D0141A00F412041001005420053044041870B4114422710021A0B41FD0B4125422810061A0C020B200041206A4130418180181001420851044041C00F412041001005420053044041EB0A411C422D10021A0B41BD0E4121422E10061A0541A00F412041001005420053044041870B4114423010021A0B41F70C4126423110061A0B4200210641000C020B200121034100200642E300520D011A0B200041206A4114419B0B41051007420451044041C00F412041001005420053044041EB0A411C423810021A0B41A308412E423910061A0B0240200041206A411441FA0E410810074208520440200041206A411441E60E410C10074204520440200041206A411441A10B410E10074204520D020B0B41A00F412041001005420053044041870B4114423E10021A0B41B00B412A423F10061A0B200041206A411441DE0E41071007421451044041A00F412041001005420053044041870B411442C20010021A0B41DA0B412342C30010061A0B41A00F412041001005420053044041870B411442C50010021A0B41D108413B42C60010021A42E300210641010B210410082107200041EC026A41870F2D00003A0000200041830F2800003602E802200041E6026A418A0F2D00003A0000200041880F2F00003B01E402200041E0026A4104200041E8026A410541E00F412020004190036A220141141009420451200041DC026A4104200041E4026A410341E00F4120200141141009420451712205047F410020002800E00222024118742002410874418080FC07717220024108764180FE0371200241187672722007A722024B0D011A200220002800DC0222014118742001410874418080FC07717220014108764180FE037120014118767272490541000B0B2101200041D8026A418F0F2F00003B01002000418B0F2800003602D402200041003A00D302200041D3026A4101200041D4026A410641E00F412020004190036A4114100942015120002D00D302410146712202044002402004044041E509412942DF0010021A0C010B20064200520D00200345044041BA09412B42E20010021A0B200041206A4130418180181001423052044041C10A412A42E70010021A0B41C00F412041001005420053044041EB0A411C42E90010021A0B41ED0D412F42EA0010061A0B0B200504402007A720002800DC0222034118742003410874418080FC07717220034108764180FE0371200341187672724B044041A00F412041001005420053044041870B411442EE0010021A0B41D80C411F42EF0010061A0B0B200220014100477245044041A00F412041001005420053044041870B411442F20010021A0B41A20C413642F30010061A0B200041A0026A41304181801810014208510440200041206A41800241F30E41061007420059044041C00F412041001005420053044041EB0A411C42FC0010021A0B419C0E412142FD0010061A0B2000411A6A41930F2D00003A0000200041910F2F00003B011820004108200041186A4103100A420851044041C00F412041001005420053044041EB0A411C42820110021A0B419D0D412842830110061A0B41A00F412041001005420053044041870B411442850110021A0B418E0A413342860110021A0B200041386A4200370300200041306A42003703002000420037032820004200370320410021010340418901411510031A2001411446450440200041206A20016A200041F0026A20016A2D00003A0000200141016A21010C010B0B200042C988BDFAC5A890AAC10037031820004110200041186A4108200041206A412020004190036A41141009421051044041C00F412041001005420053044041EB0A411C42900110021A0B41C50D412842910110061A0B41A00F412041001005420053044041870B411442930110021A0B418C09412E42940110021A200041B0036A240042000B0B820802004180080B9407526F757465723A2043616E6E6F7420726561642073656E646572206163636F756E7400526F757465723A20535441525420706172616D20E286922072756E2049444F2C20736B6970207265776172647300526F757465723A20496E766F6B6520776974686F7574205354415254206F72207265776172647320706172616D7320E2869220696E76616C696400526F757465723A20494F5520776974686F75742070617274696369706174696F6E20E2869220696E76616C696400526F757465723A20526566756E64206D6F6465202B206F7574676F696E6720E2869220696E76616C696400526F757465723A20526566756E64206D6F6465202B20696E766F6B6520E2869220696E76616C696400526F757465723A2058414820776974686F75742057505F4C4E4B202F206E6F2072616973656420E2869220696E76616C696400526F757465723A20526566756E64206D6F6465202B206E6F7420494F5520E2869220696E76616C696400526F757465723A20536B69702072657761726473206661696C656400526F757465723A20536B6970206661696C6564005354415254005345545F4D41585F434C41494D5300526F757465723A20526577617264732061646D696E20706172616D7320E2869220736B69702049444F00526F757465723A20525F434C41494D20706172616D20E2869220736B69702049444F00526F757465723A204F7574676F696E6720696E766F6B6520E2869220736B69702049444F00526F757465723A2057696E646F77206E6F742061637469766520616E64206E6F7420726566756E6420E2869220736B69702049444F00526F757465723A2049444F20656E64656420E2869220736B69702049444F00526F757465723A204F7574676F696E67206E6F6E2D58414820E2869220736B69702049444F00526F757465723A20584148202B207261697365642065786973747320E286922072756E2049444F00526F757465723A20494F55202B2070617274696369706174696F6E20E286922072756E2049444F00526F757465723A20526566756E64206D6F6465202B20696E636F6D696E6720494F5520E286922072756E2049444F00526F757465723A20584148202B2057505F4C4E4B20E286922072756E2049444F00526F757465723A204F7574676F696E672058414820E286922072756E2049444F00525F434C41494D005345545F494E54455256414C0057505F4C4E4B00494E545F52415445005354415254454E44524546554E445841480041A00F0B60330961A6811A03131B590D0C69211447E78DF7208898A44F8CC1E13C629F2D2D8CFC9AA6AA4A858DEF04D3049D4E7D22A37F968D050634244EC5DACECCE6160D516BA79215002276EF4C381B901955C53A04575589607E7DBA20468DD343DD72", + "Fee": "1799", + "Flags": 0, + "HookApiVersion": 0, + "HookHash": "B952D1A5B03230EE3DA880571FB1438E67B29A0F4101FC76B784F1B7495F3BC1", + "HookNamespace": "065D8E6C0BF74A69A6D312C3D5B5CC627434CECE07B2787C1A538FCFD9F9C8DE", + "HookOn": "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFFFFFFFFFBFFFFE", + "HookParameters": [], + "HookSetTxnID": "8EC31D80B3DF82977A3C6B8C521A8C1AC8D335C1E0B0F6834334B30418D0688C", + "ReferenceCount": "2" + }, + "LedgerEntryType": "HookDefinition", + "LedgerIndex": "5815034B1B984E512A8089AA6704B9F8A27A01CDBA1E9AD348761A966F0DDA3D", + "PreviousFields": { + "ReferenceCount": "1" + } + } + }, + { + "ModifiedNode": { + "FinalFields": { + "CreateCode": "0061736D0100000001670D60057F7F7F7F7F017E60027F7F017E60037F7F7E017E6000017E60037F7F7F017E60047F7F7F7F017E60097F7F7F7F7F7F7F7F7F017E60017F017E60037E7F7F017E60027F7F017F60087F7F7F7F7F7F7F7F017E60027F7E017E60087F7F7F7F7F7F7E7F017E02AC031A03656E76057472616365000003656E760C686F6F6B5F6163636F756E74000103656E7608726F6C6C6261636B000203656E76096F74786E5F74797065000303656E760A6F74786E5F6669656C64000403656E760A686F6F6B5F706172616D000503656E76057374617465000503656E760A6C65646765725F736571000303656E760A6F74786E5F706172616D000503656E760974726163655F6E756D000203656E760973746174655F736574000503656E7606616363657074000203656E760B7574696C5F6B65796C6574000603656E7608736C6F745F736574000403656E760D736C6F745F7375626669656C64000403656E760A736C6F745F666C6F6174000703656E7609666C6F61745F696E74000803656E76025F67000903656E760D73746174655F666F726569676E000A03656E760C6574786E5F72657365727665000703656E760C6574786E5F64657461696C73000103656E760D6574786E5F6665655F62617365000103656E7604656D6974000503656E761173746174655F666F726569676E5F736574000A03656E7609666C6F61745F736574000B03656E7609666C6F61745F73746F000C0302010705030100020631087F0141A0A6040B7F0041C0230B7F004180080B7F00419E260B7F004180080B7F0041A0A6040B7F0041000B7F0041010B07080104686F6F6B001A0A8BC2000187C20002047F0C7E230041E0066B2200240041F81D412841AE094127410010001A200041C0066A41141001421452044041840B412D423010021A0B100342E300510440200041A0016A4114418180201004421452044041D50A412F423510021A0B024020002903A00120002903C00651044020002903A80120002903C80651044020002802B00120002802D006460D020B0B200041C0046A411441E70941051005421452044041E60D412A423910021A0B20002903A00120002903C00451044020002903A80120002903C80451044020002802B00120002802D004460D020B0B4191184126423B10021A0B200041246A419B232D00003A00002000419723280000360220200041406B4104200041206A4105100642045104400240200028004022014118742001410874418080FC07717220014108764180FE0371200141187672721007A74B0D0041F409413D42C30010021A0B0B200041C0046A41800241ED09410610052206420057044041900E412B42C80010021A0B200042C99CD1AAA4CAD5A0CC003703F003200041E8036A4104200041F0036A41081005420452044041F813412E42CC0010021A0B20002800E80322014118742001410874418080FC07717220014108764180FE0371200141187672722102200041B8036A4104200041206A41051008420452044041A712412A42D10010021A0B20002800B80321011007210541DF1D41184180084117410010001A41A6084110200542FFFFFFFF0F8310091A41D008410C2001410874418080FC077120014118747220014108764180FE0371200141187672722201AD10091A41DD08410F2002AD10091A41ED08410C20012005A76A2201AD10091A41FA08410A2001200241056C6A2202AD10091A200041A4046A4195232F00003B010020004191232800003602A004200041C0046A2006A7200041A0046A4106100A4200530440419516413242DF0010021A0B20002001410874418080FC077120014118747220014108764180FE0371200141187672723600B00320002002410874418080FC077120024118747220024108764180FE037120024118767272360070200041E2006A419E232D00003A00002000419C232F00003B01600240200041B0036A4104200041206A4105100A42005904400240200041E8036A4104200041F0036A4108100A4200530D00200041F0006A4104200041E0006A4103100A4200590D020B0B41BB15412642E80010021A0B200041C0036A410841DE0941081005420852044041B90D412D42EB0010021A0B200042D39E99A2F5EBD0A0D000370300200041C0036A410820004108100A420053044041E115413442EE0010021A0B41CC0C411F42EF00100B1A0B200041A0046A4114418180201004421452044041D50A412F42F30010021A0B200041F0036A413041818018100421050240024020002903C00620002903A004510440024020002903C80620002903A804520D0020002802D00620002802B004470D00200542085204402005423052044041B10B413142C801100B1A0C020541E20B413542F800100B1A0C040B000B200041C0046A220141224103200041C0066A41144100410041004100100C1A200141224101100D420152044041DE0E413042FD0010021A0B4101418280184101100E420152044041EA18412B42FF0010021A0B4101100F410641001010210720002C00F0032201410048047E427E0520003100F70320003100F1034230862001AD4211834238868420003100F2034228868420003100F3034220868420003100F4034218868420003100F5034210868420003100F603420886847C0B200041E2006A41B3232D00003A0000200041B1232F00003B016042002106200041C0036A4108200041E0006A41031006420851044020003100C70320003100C10342308620003100C0034238868420003100C2034228868420003100C3034220868420003100C4034218868420003100C5034210868420003100C603420886847C21060B200041BC036A419B232D00003A000020004197232800003602B803200042C99CD1AAA4CAD5A0CC00370300200041B0036A4104200041B8036A4105100642045104400240200041F0006A41042000410810064204520D0020002800B00322014118742001410874418080FC07717220014108764180FE037120014118767272200028007022014118742001410874418080FC07717220014108764180FE0371200141187672724102746A1007A74B0D00200041EC036A41AF232F00003B0100200041AB232800003602E803200041D8006A4101200041E8036A410610064200590D00200041206A410841DE09410810054208520D00200031002720003100214230862000310020423886842000310022422886842000310023422086842000310024421886842000310025421086842000310026420886847C2109200041406B4108200041E0006A41031006420851047E200031004720003100414230862000310040423886842000310042422886842000310043422086842000310044421886842000310045421086842000310046420886847C0542000B20095A0440200041003A00A803200041A8036A4101200041E8036A4106100A1A200041A8016A41A7232800003602002000419F232900003703A001200041406B4108200041A0016A410C100A1A05200041013A00A001200041A0016A4101200041E8036A4106100A1A0B0B0B200041246A41AF232F00003B0100200041AB23280000360220200041D8006A4101200041206A410610062109200041EA036A419E232D00003A00002000419C232F00003B01E803200642C0FB427E2108200041406B4104200041E8036A4103100642045104400240200028004022014118742001410874418080FC07717220014108764180FE0371200141187672721007A74B0D0020094201520D0020002D00580D00420021082006500D00200042003703A001200041A0016A4108200041E0006A4103100A1A0B0B200720087C58047E41970C413542C301100B0541B718413342C50110020B1A0C030B0B20054230520D010B0240200029038C0420002903C00651044020002903940420002903C806510440200028029C0420002802D006460D020B0B41A711412042CD0110021A0B4100210141B708410A20003100F70320002D00F003220241FF0071AD42388620003100F1034230868420003100F2034228868420003100F3034220868420003100F4034218868420003100F5034210868420003100F603420886847C2205420020057D2002418001711B410041011010220510091A034041D201411510111A2001411446450440200041A0016A20016A200041A0046A20016A2D00003A0000200141016A21010C010B0B41142101034041D401412110111A2001412046450440200041A0016A20016A41003A0000200141016A21010C010B0B200042C988BDFAC5A890AAC10037032020004110200041206A4108200041A0016A4120200041C0066A411410121A200031000F2106200031000E2107200031000D2109200031000C210A200031000B210B200031000A210C2000310009210D2000310008210E419209410E200031000720003100014230862000310000423886842000310002422886842000310003422086842000310004421886842000310005421086842000310006420886847C220810091A419708410E2006200D423086200E42388684200C42288684200B42208684200A421886842009421086842007420886847C220710091A200041E4006A419B232D00003A00002000419723280000360260200042C99CD1AAA4CAD5A0CC00370340200041D8006A4104200041E0006A4105100642045104400240200041A8036A4104200041406B410810064204520D00200028005822014118742001410874418080FC07717220014108764180FE03712001411876727220002800A80322014118742001410874418080FC07717220014108764180FE0371200141187672724102746A1007A74B0D00200041BC036A41AF232F00003B0100200041AB232800003602B803200041F0006A4101200041B8036A410610064200590D00200041C0036A410841DE09410810054208520D0020003100C703210920003100C603210A20003100C503210B20003100C403210C20003100C303210D20003100C203210E20003100C103210F20003100C0032110200041B2036A41B3232D00003A0000200041B1232F00003B01B00342002106200041E8036A4108200041B0036A41031006420851044020003100EF0320003100E90342308620003100E8034238868420003100EA034228868420003100EB034220868420003100EC034218868420003100ED034210868420003100EE03420886847C21060B4197094109200610091A418509410C2009200F423086201042388684200E42288684200D42208684200C42188684200B42108684200A420886847C220910091A20062009540440200041013A00C004200041C0046A4101200041B8036A4106100A1A41FD20413941D4194138410010001A05200041003A0068200041E8006A4101200041B8036A4106100A1A41C122412841EA224127410010001A200041C8046A41A7232800003602002000419F232900003703C004200041E8036A4108200041C0046A410C100A1A41BC2041C000419519413F410010001A0B0B0B200041F4006A41AF232F00003B0100200041AB2328000036027002402000418C016A4101200041F0006A410610064201510440024020002D008C014101470D0041B72141D60041DF1A41D500410010001A0C020B0B2005200752044041AE1D413142900210021A0B200041C2036A419E232D00003A00002000419C232F00003B01C003200041C0046A4104200041C0036A410310064204520D0020002800C00422014118742001410874418080FC07717220014108764180FE0371200141187672721007A74B0D0041AF1741E20042980210021A0B410110131A10072106200041C0036A2202411410011A200041E880013B01EC04200041E1003A00E304200041A0363B00DD04200041A0343B00D704200041003600D3042000412E3A00D204200041003601CE04200041243A00CD04200041003600C904200041233A00C8042000429280809082103703C0042000200842C0843D7E22053C00EB04200020054208883C00EA04200020054210883C00E904200020054218883C00E804200020054220883C00E704200020054228883C00E604200020054230883C00E50420002006A7220341056A22013A00E204200020014108763A00E104200020014110763A00E004200020014118763A00DF042000200341016A22013A00DC04200020014108763A00DB04200020014110763A00DA04200020014118763A00D90420002005423888A7413F7141C000723A00E404200041F1046A22014100360000200041FF046A420037030020004187056A42003703002000418E056A4200370000200041003601EE04200041F3C2003B00F504200042003703F70420004181293B01980520004183293B01AE05200020002903C00337039A05200020002903C8033703A205200020002802D0033602AA05200020002903A0043703B005200020002903A8043703B805200020002802B0043602C005200041C4056A41F80110141A2001200041C0046A220141F801101522054218883C0000200020053C00F404200041E8003A00EC04200020054208883C00F304200020054210883C00F204200020054220883C00F004200020054228883C00EF04200020054230883C00EE0420002005423888A7413F7141C000723A00ED0420024120200141F8011016420053044041DF1B411F42A20210021A0B200041C5B0959A0436026820004196016A41B3232D00003A0000200041B1232F00003B0194012000419E016A41B6232D00003A0000200041B4232F00003B019C01200041E8036A4108200041E8006A410410064208510440200020003100EF0320003100E90342308620003100E8034238868420003100EA034228868420003100EB034220868420003100EC034218868420003100ED034210868420003100EE03420886847C42017D2205423886200542288642808080808080C0FF0083842005421886428080808080E03F8320054208864280808080F01F838484200542088842808080F80F832005421888428080FC07838420054228884280FE038320054238888484843700E803200041E8036A4108200041E8006A4104100A1A0B200041B8036A410820004194016A410310064208510440200020003100BF0320087D20003100B90342308620003100B8034238868420003100BA034228868420003100BB034220868420003100BC034218868420003100BD034210868420003100BE03420886847C2205423886200542288642808080808080C0FF0083842005421886428080808080E03F8320054208864280808080F01F838484200542088842808080F80F832005421888428080FC07838420054228884280FE038320054238888484843700B803200041B8036A410820004194016A4103100A1A0B200041B0036A41082000419C016A410310064208510440200020003100B70320077D20003100B10342308620003100B0034238868420003100B2034228868420003100B3034220868420003100B4034218868420003100B5034210868420003100B603420886847C2205423886200542288642808080808080C0FF0083842005421886428080808080E03F8320054208864280808080F01F838484200542088842808080F80F832005421888428080FC07838420054228884280FE038320054238888484843700B003200041B0036A41082000419C016A4103100A1A0B41004100200041206A4108200041A0016A4120200041C0066A411410171A41B41B412B42B902100B1A0B200041C0046A41800241ED09410610082105200041AC036A4195232F00003B010020004191232800003602A803200041A0016A418002200041A8036A410610062206420057044041F01241CC0042C10210021A0B2005200652044041EE1441CD0042C30210021A0B2005420020054200551B210641002101034041C40241810210111A02402006500D00200041C0046A20016A2D0000200041A0016A20016A2D000047044041EE1441CD0042C60210021A0B200141016A2101200642017D21060C010B0B41FE1F413D41BC13413C410010001A200042C99CD1AAA4CAD5A0CC003703E8032000419C016A4104200041E8036A41081005420452044041BB0E412342CC0210021A0B200028009C01210120004198016A419B232D00003A000020004197232800003602940120004192016A419E232D00003A00002000419C232F00003B0190012001410874418080FC077120014118747220014108764180FE037120014118767272210102402000418C016A410420004194016A41051006420451044020004188016A410420004190016A410310064204510D010B41EB0C412142D40210021A0B20002800880122024118742002410874418080FC07717220024108764180FE0371200241187672722103200028008C0122024118742002410874418080FC07717220024108764180FE037120024118767272220420014102746A1007A722024D04400240200041C4006A41AF232F00003B0100200041AB23280000360240200041B0036A4101200041406B410610064200590D002000410841DE0941081005420852044041B90D412D42E10210021A0B200031000721052000310006210820003100052107200031000421092000310003210A2000310002210B2000310001210C2000310000210D200041BA036A41B3232D00003A0000200041B1232F00003B01B80342002106200041206A4108200041B8036A410310064208510440200031002720003100214230862000310020423886842000310022422886842000310023422086842000310024421886842000310025421086842000310026420886847C21060B4197094109200610091A418509410C2005200C423086200D42388684200B42288684200A422086842009421886842007421086842008420886847C220510091A20052006580440200041003A0070200041F0006A4101200041406B4106100A1A41C122412841EA224127410010001A200041C8036A41A7232800003602002000419F232900003703C003200041206A4108200041C0036A410C100A1A05200041013A00C003200041C0036A4101200041406B4106100A1A41FD20413941D4194138410010001A0B0B0B200220034F0440200041C4036A41AF232F00003B0100200041AB232800003602C00320004101200041C0036A410610064201510440024020002D00004101470D00418C1A41D30042FD0210021A0B0B41E41C412642FE0210021A0B027E41A109410C20002C00F0032203410048047E427E0520003100F70320003100F1034230862003AD4211834238868420003100F2034228868420003100F3034220868420003100F4034218868420003100F5034210868420003100F603420886847C0B42C0843D7F220710091A200220046B220320016E2102200120034B047E41C61F413741AD104136410010001A42E40005024002400240024002400240200241016B0E0403020100040B418E22413241B31C4131410010001A41E31041C40042940310021A0C040B41D81E413641C30F4135410010001A42190C050B418F1F413641F80F4135410010001A42320C040B41A11E4136418E0F4135410010001A42CB000C030B418C17412342960310021A0B42000B0B20077E220850044041D112411F429A0310021A0B41C208410D200810091A200041C5B0959A043602840120004182016A41B3232D00003A0000200041B1232F00003B018001200041FE006A41B6232D00003A0000200041B4232F00003B017C200042003703B80342012106200041B8036A410820004184016A41041006420851044020003100BF0320003100B90342308620003100B8034238868420003100BA034228868420003100BB034220868420003100BC034218868420003100BD034210868420003100BE03420886847C42017C21060B2000200642288642808080808080C0FF00832006423886842006421886428080808080E03F8320064208864280808080F01F838484200642088842808080F80F832006421888428080FC07838420064228884280FE038320064238888484843703B803200041B8036A410820004184016A4104100A420053044041C711412D42A60310021A0B200042003703B0032000200041B0036A410820004180016A41031006420851047E20003100B70320003100B10342308620003100B0034238868420003100B2034228868420003100B3034220868420003100B4034218868420003100B5034210868420003100B603420886847C0542000B20077C2205423886200542288642808080808080C0FF0083842005421886428080808080E03F8320054208864280808080F01F838484200542088842808080F80F832005421888428080FC07838420054228884280FE038320054238888484843703B003200041B0036A410820004180016A4103100A420053044041CA14412442AE0310021A0B200042003703702000200041F0006A4108200041FC006A41031006420851047E200031007720003100714230862000310070423886842000310072422886842000310073422086842000310074421886842000310075421086842000310076420886847C0542000B20087C2205423886200542288642808080808080C0FF0083842005421886428080808080E03F8320054208864280808080F01F838484200542088842808080F80F832005421888428080FC07838420054228884280FE03832005423888848484370370200041F0006A4108200041FC006A4103100A420053044041A614412442B60310021A0B200041C5003A006C200041D090859A053600682000200241316A3A006D2000420037036042012106200041E0006A4108200041E8006A410610064208510440200031006720003100614230862000310060423886842000310062422886842000310063422086842000310064421886842000310065421086842000310066420886847C42017C21060B2000200642288642808080808080C0FF00832006423886842006421886428080808080E03F8320064208864280808080F01F838484200642088842808080F80F832006421888428080FC07838420064228884280FE03832006423888848484370360200041E0006A4108200041E8006A4106100A420053044041F411413342C50310021A0B41002101034041C703411510111A2001411446450440200041C0036A20016A200041A0046A20016A2D00003A0000200141016A21010C010B0B41142101034041C903412110111A2001412046450440200041C0036A20016A41003A0000200141016A21010C010B0B200042C988BDFAC5A890AAC1003703582000420037034820004200370340200041406B22014110200041D8006A22024108200041C0036A22034120200041C0066A2204411410121A20002008200031004F7C2000310049423086200031004842388684200031004A42288684200031004B42208684200031004C42188684200031004D42108684200031004E420886847C22053C004F200020054208883C004E200020054210883C004D200020054218883C004C200020054220883C004B200020054228883C004A200020054230883C0049200020054238883C00482000200720003100477C20003100414230862000310040423886842000310042422886842000310043422086842000310044421886842000310045421086842000310046420886847C22053C0047200020054208883C0046200020054210883C0045200020054218883C0044200020054220883C0043200020054228883C0042200020054230883C0041200020054238883C00402001411020024108200341202004411410174200530440418A1D412442D50310021A0B41A52541F0B981DF05360000200041206A411441D509410810054214520440418C0D412D42DD0310021A0B41A9254131200041206A4114200041C0066A4114410020081018418180181019A72201410048044041B10A412442E70310021A0B200141A9256A41E1E3033B0000418724411410011A200141AB256A210241002101034041ED03411510111A20014114464504402001419D246A200041A0046A20016A2D00003A0000200141016A21010C010B0B410110131A41B12441F40010141A41D8231007220642057C22053C000041D223200642017C22063C000041D72320054208883C000041D62320054210883C000041D52320054218883C000041D12320064208883C000041D02320064210883C000041CF2320064218883C000041C023200241C0236B220110152205420053044041931C412042FE0310021A0B41DA23200542FFFFFFFFFFFFFFFF3F83428080808080808080C000842205423886200542288642808080808080C0FF0083842005421886428080808080E03F8320054208864280808080F01F838484200542088842808080F80F832005421888428080FC07838420054228884280FE038320054238888484843703002000412041C02320011016420053044041FE1B4115428D0410021A0B41C71641C500428E04100B1A4101410010111A200041E0066A240042000B0BF91B04004180080BB71B49444F4D203A3A2053657474696E672077696E646F7700757365725F746F74616C5F696F750063757272656E745F6C65646765725F7500696F755F616D6F756E74006973737565645F616D6F756E740073746172745F6F666673657400696E74657276616C5F6F66667365740073746172745F6C656467657200656E645F6C656467657200736F66745F6361705F78616800757365725F746F74616C5F7861680072656365697665645F7861680049444F4D203A3A20496E697469616C20446578204F66666572696E67203A3A2043616C6C65640043555252454E435900534F46545F4341500041444D494E0057505F4C4E4B0049444F4D203A3A204572726F72203A3A2057696E646F772068617320616C726561647920737461727465642C2063616E6E6F7420726573746172742E0049444F4D203A3A204661696C656420746F2073657269616C697A6520616D6F756E742E0049444F4D203A3A204572726F72203A3A204661696C656420746F20676574206F726967696E206163636F756E742E0049444F4D203A3A204572726F72203A3A204661696C656420746F2067657420686F6F6B206163636F756E742E0049444F4D203A3A2053756363657373203A3A204163636570746564203A3A204F7574676F696E67207061796D656E742E0049444F4D203A3A2053756363657373203A3A204163636570746564203A3A204F7574676F696E6720494F55207061796D656E742E0049444F4D203A3A2053756363657373203A3A204163636570746564203A3A204F7574676F696E6720584148207061796D656E742E0049444F4D203A3A2053756363657373203A3A2057696E646F77207365742E0049444F4D203A3A204572726F72203A3A2057696E646F77206E6F74207365742E0049444F4D203A3A204572726F72203A3A2043555252454E435920706172616D65746572206E6F74207365742E0049444F4D203A3A204572726F72203A3A20534F46545F43415020706172616D65746572206E6F74207365742E0049444F4D203A3A204572726F72203A3A2041444D494E20706172616D65746572206E6F74207365742E0049444F4D203A3A204572726F72203A3A2057505F4C4E4B20706172616D65746572206E6F74207365742E0049444F4D203A3A204572726F72203A3A20494E54455256414C206E6F74207365742E0049444F4D203A3A204572726F72203A3A20436F756C64206E6F74206C6F6164206163636F756E74206B65796C65742E0049444F4D203A3A2050686173652032206163746976652C20373578206D756C7469706C79657220697320696E206566666563742E0049444F4D203A3A2050686173652034206163746976652C20323578206D756C7469706C79657220697320696E206566666563742E0049444F4D203A3A2050686173652033206163746976652C20353078206D756C7469706C79657220697320696E206566666563742E0049444F4D203A3A2050686173652031206163746976652C2031303078206D756C7469706C79657220697320696E206566666563742E0049444F4D203A3A2052656A6563746564203A3A205068617365203520697320666F7220756E77696E64696E67206F6E6C792C206E6F206E6577206465706F736974732E0049444F4D203A3A20556E77696E64203A3A2057726F6E67206973737565722E0049444F4D203A3A204661696C656420746F2075706461746520657865637574696F6E7320636F756E7465722E0049444F4D203A3A204661696C656420746F2075706461746520706861736520657865637574696F6E7320636F756E7465722E0049444F4D203A3A204572726F72203A3A20496E76616C696420535441525420706172616D657465722E0049444F4D203A3A2049737375656420616D6F756E74206973207A65726F2E0049444F4D203A3A204572726F72203A3A2057505F4C4E4B206E6F7420666F756E6420696E2073746174652C206177616974696E672069737375657220696E697469616C697A6174696F6E2E0049444F4D203A3A2057505F4C4E4B2076616C696461746564202D20757365722061636B6E6F776C656467656420646F63756D656E746174696F6E2E0049444F4D203A3A204572726F72203A3A20494E54455256414C206E6F7420736574206F6E20696E7374616C6C2E0049444F4D203A3A204661696C656420746F2075706461746520494F5520746F74616C2E0049444F4D203A3A204661696C656420746F207570646174652058414820746F74616C2E0049444F4D203A3A2052656A6563746564203A3A2057505F4C4E4B20706172616D6574657220646F6573206E6F74206D617463682E205665726966792077686974657061706572206C696E6B2E0049444F4D203A3A204572726F72203A3A204661696C656420746F207365742073746174652E0049444F4D203A3A204572726F72203A3A204661696C656420746F2073746F726520534F46545F43415020696E2073746174652E0049444F4D203A3A204572726F72203A3A204661696C656420746F2073746F72652057505F4C4E4B20696E2073746174652E0049444F4D203A3A2053756363657373203A3A204163636570746564203A3A20496E636F6D696E67207061796D656E7420647572696E67206163746976652070686173652E0049444F4D203A3A2052656A6563746564203A3A20496E76616C69642070686173652E0049444F4D203A3A20556E77696E64203A3A2053616C65207375636365737366756C20616E6420636F6F6C646F776E20706572696F642068617320656E6465642C20756E77696E64277320617265206E6F206C6F6E67657220706F737369626C652E0049444F4D203A3A204572726F72203A3A20556E617574686F72697A656420696E766F6B652E0049444F4D203A3A2052656A6563746564203A3A20496E73756666696369656E7420756E6C6F636B65642062616C616E63652E0049444F4D203A3A204572726F72203A3A20436F756C64206E6F74206C6F616420736642616C616E63652E0049444F4D203A3A20536F667420636170206D65742E2046756E64732077696C6C20756E6C6F636B20616674657220636F6F6C646F776E20706572696F642E0049444F4D203A3A20536F667420636170204E4F54206D65742E2050686173652035206973206E6F7720524546554E4420706572696F642E0049444F4D203A3A2052656A6563746564203A3A2057696E646F7720656E6465642E20536F667420636170206E6F74206D65742E2053656E6420494F5520746F20756E77696E6420666F7220726566756E642E0049444F4D203A3A20526566756E64206D6F6465202D20616363657074696E672074686520657861637420494F5520616D6F756E742069737375656420666F722070726F706F7274696F6E616C20726566756E642E0049444F4D203A3A2053756363657373203A3A20556E77696E64203A3A205841482072657475726E65642E0049444F4D203A3A20556E77696E64203A3A20456D6974206661696C65642E0049444F4D203A3A20456D6974206661696C65642E0049444F4D203A3A204665652063616C63756C6174696F6E206661696C65642E0049444F4D203A3A2050686173652035206163746976652C20436F6F6C646F776E20706572696F6420656E61626C65642E0049444F4D203A3A2052656A6563746564203A3A2057696E646F772068617320656E6465642E0049444F4D203A3A204661696C656420746F20757064617465207573657220646174612E0049444F4D203A3A20556E77696E64203A3A20416D6F756E74206E6F7420657861637420746F20746F74616C20494F552E002249444F4D203A3A2053657474696E672077696E646F7722002249444F4D203A3A20496E697469616C20446578204F66666572696E67203A3A2043616C6C656422002249444F4D203A3A2050686173652032206163746976652C20373578206D756C7469706C79657220697320696E206566666563742E22002249444F4D203A3A2050686173652034206163746976652C20323578206D756C7469706C79657220697320696E206566666563742E22002249444F4D203A3A2050686173652033206163746976652C20353078206D756C7469706C79657220697320696E206566666563742E22002249444F4D203A3A2050686173652031206163746976652C2031303078206D756C7469706C79657220697320696E206566666563742E22002249444F4D203A3A2057505F4C4E4B2076616C696461746564202D20757365722061636B6E6F776C656467656420646F63756D656E746174696F6E2E22002249444F4D203A3A20536F667420636170206D65742E2046756E64732077696C6C20756E6C6F636B20616674657220636F6F6C646F776E20706572696F642E22002249444F4D203A3A20536F667420636170204E4F54206D65742E2050686173652035206973206E6F7720524546554E4420706572696F642E22002249444F4D203A3A20526566756E64206D6F6465202D20616363657074696E672074686520657861637420494F5520616D6F756E742069737375656420666F722070726F706F7274696F6E616C20726566756E642E22002249444F4D203A3A2050686173652035206163746976652C20436F6F6C646F776E20706572696F6420656E61626C65642E22002249444F4D203A3A20536F667420636170204D45542E2053616C65207375636365737366756C21220049444F4D203A3A20536F667420636170204D45542E2053616C65207375636365737366756C210057505F4C4E4B5354415254454E44544F54414C5F524149534544524546554E44584148494F550041C0230B2412005F22800000002400000000201A00000000201B000000006840000000000000007321004185240B02811400419B240B028314", + "Fee": "16032", + "Flags": 0, + "HookApiVersion": 0, + "HookHash": "330961A6811A03131B590D0C69211447E78DF7208898A44F8CC1E13C629F2D2D", + "HookNamespace": "516BA79215002276EF4C381B901955C53A04575589607E7DBA20468DD343DD72", + "HookOn": "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFFFFFFFFFBFFFFE", + "HookParameters": [ + { + "HookParameter": { + "HookParameterName": "41444D494E", + "HookParameterValue": "ABA521D9DCB3602C15AE7CDA813AA9CA790E8B3D" + } + }, + { + "HookParameter": { + "HookParameterName": "43555252454E4359", + "HookParameterValue": "0000000000000000000000005453540000000000" + } + }, + { + "HookParameter": { + "HookParameterName": "494E54455256414C", + "HookParameterValue": "0000000A" + } + }, + { + "HookParameter": { + "HookParameterName": "57505F4C4E4B", + "HookParameterValue": "68747470733A2F2F697066732E696F2F697066732F6261666B726569666A6C656436746A616B686C73646E3732657074776D366776616365727A6436786D6F3668736A726E6F73326E376F3362673471" + } + }, + { + "HookParameter": { + "HookParameterName": "534F46545F434150", + "HookParameterValue": "000000000000000A" + } + } + ], + "HookSetTxnID": "2B449A8FC3B9DC55E6AA536C2E02002EFA082ED4F3DA7578A1EFC9E8BC7BF55F", + "ReferenceCount": "3" + }, + "LedgerEntryType": "HookDefinition", + "LedgerIndex": "AF2D781F9C9862EEF3CC69DA50A3E17E0EC98B8F3C9F275D59E7EFCA230AEFF2", + "PreviousFields": { + "ReferenceCount": "2" + } + } + }, + { + "CreatedNode": { + "LedgerEntryType": "Hook", + "LedgerIndex": "B66AD6B70F7F2132DF37C1EB34CC567BE10AF7A6456B416AA69753C5BF59B814", + "NewFields": { + "Account": "raXdWCS1Ro8gVER2zRQMPn3pm4kLdD7okD", + "Hooks": [ + { + "Hook": { + "Flags": 0, + "HookHash": "B952D1A5B03230EE3DA880571FB1438E67B29A0F4101FC76B784F1B7495F3BC1" + } + }, + { + "Hook": { + "Flags": 0, + "HookHash": "330961A6811A03131B590D0C69211447E78DF7208898A44F8CC1E13C629F2D2D", + "HookParameters": [ + { + "HookParameter": { + "HookParameterName": "43555252454E4359", + "HookParameterValue": "5453540000000000000000000000000000000000" + } + }, + { + "HookParameter": { + "HookParameterName": "494E54455256414C", + "HookParameterValue": "0000001E" + } + }, + { + "HookParameter": { + "HookParameterName": "57505F4C4E4B", + "HookParameterValue": "68747470733A2F2F787370656E63652E636F2E756B" + } + } + ] + } + }, + { + "Hook": { + "Flags": 0, + "HookHash": "8CFC9AA6AA4A858DEF04D3049D4E7D22A37F968D050634244EC5DACECCE6160D", + "HookParameters": [ + { + "HookParameter": { + "HookParameterName": "43555252454E4359", + "HookParameterValue": "5453540000000000000000000000000000000000" + } + }, + { + "HookParameter": { + "HookParameterName": "494E545F52415445", + "HookParameterValue": "000000C8" + } + }, + { + "HookParameter": { + "HookParameterName": "5345545F494E54455256414C", + "HookParameterValue": "0000001E" + } + } + ] + } + } + ] + } + } + }, + { + "ModifiedNode": { + "FinalFields": { + "Account": "raXdWCS1Ro8gVER2zRQMPn3pm4kLdD7okD", + "AccountIndex": "1e54d", + "Balance": "70523111", + "Domain": "787370656E63652E636F2E756B", + "Flags": 1082130432, + "HookNamespaces": [ + "01EAF09326B4911554384121FF56FA8FECC215FDDE2EC35D9E59F2C53EC665A0", + "0000000000000000000000000000000000000000000000000000000000000000", + "516BA79215002276EF4C381B901955C53A04575589607E7DBA20468DD343DD72" + ], + "HookStateCount": 36, + "OwnerCount": 48, + "Sequence": 800025818, + "TouchCount": "35" + }, + "LedgerEntryType": "AccountRoot", + "LedgerIndex": "BCB3155190783659101826B54C969777C0967BFAE0A6947618936E266A5BB508", + "PreviousFields": { + "Balance": "70524111", + "OwnerCount": 39, + "Sequence": 800025817, + "TouchCount": "34" + }, + "PreviousTxnID": "C5DF07F22FB35F6DB717433BD47E8437829E43A626599D3BA486B7B4A248021F", + "PreviousTxnLgrSeq": 20391867 + } + }, + { + "ModifiedNode": { + "FinalFields": { + "Flags": 0, + "Owner": "raXdWCS1Ro8gVER2zRQMPn3pm4kLdD7okD", + "RootIndex": "BEDCA3FD29F86F5D98E0ABBD5D1C09F2FFC519B0BE2CFAF894C5D518BD7430C0" + }, + "LedgerEntryType": "DirectoryNode", + "LedgerIndex": "BEDCA3FD29F86F5D98E0ABBD5D1C09F2FFC519B0BE2CFAF894C5D518BD7430C0" + } + } + ], + "TransactionIndex": 1, + "TransactionResult": "tesSUCCESS" + }, + "status": "success", + "validated": true + +} \ No newline at end of file diff --git a/IssuanceHookset/Fin/IDOMulti.c b/IssuanceHookset/Fin/IDOMulti.c new file mode 100644 index 0000000..885185a --- /dev/null +++ b/IssuanceHookset/Fin/IDOMulti.c @@ -0,0 +1,529 @@ +#include "hookapi.h" + +#ifndef NULL +#define NULL 0 +#endif +#define sfAmountEntry ((14U << 16U) + 91U) +#define sfAmounts ((15U << 16U) + 92U) +#define DONE(x) accept(SBUF("IDOM :: Success :: " x), __LINE__) +#define NOPE(x) rollback(SBUF("IDOM :: Error :: " x), __LINE__) +#define REJECT(x) rollback(SBUF("IDOM :: Rejected :: " x), __LINE__) +#define UNWIND(x) rollback(SBUF("IDOM :: Unwind :: " x), __LINE__) +#define FAIL(x) rollback(SBUF("IDOM :: " x), __LINE__) +#define GUARD(maxiter) _g(__LINE__, (maxiter) + 1) +#define UINT64_FROM_BUF(buf) \ + (((uint64_t)(buf)[0] << 56) + ((uint64_t)(buf)[1] << 48) + \ + ((uint64_t)(buf)[2] << 40) + ((uint64_t)(buf)[3] << 32) + \ + ((uint64_t)(buf)[4] << 24) + ((uint64_t)(buf)[5] << 16) + \ + ((uint64_t)(buf)[6] << 8) + (uint64_t)(buf)[7]) +uint8_t txn[350] = +{ +/* size,upto */ +/* 3, 0 */ 0x12U, 0x00U, 0x5FU, /* ttREMIT */ +/* 5, 3 */ 0x22U, 0x80U, 0x00U, 0x00U, 0x00U, /* Flags */ +/* 5, 8 */ 0x24U, 0x00U, 0x00U, 0x00U, 0x00U, /* Sequence */ +/* 6, 13 */ 0x20U, 0x1AU, 0x00U, 0x00U, 0x00U, 0x00U, /* FirstLedgerSequence */ +/* 6, 19 */ 0x20U, 0x1BU, 0x00U, 0x00U, 0x00U, 0x00U, /* LastLedgerSequence */ +/* 9, 25 */ 0x68U, 0x40U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, /* Fee */ +/* 35, 34 */ 0x73U, 0x21U, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* SigningPubKey */ +/* 22, 69 */ 0x81U, 0x14U, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* Account */ +/* 22, 91 */ 0x83U, 0x14U, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* Destination */ +/* 116, 113 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* EmitDetails */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +/* 0, 229 */ /* Amounts array appended here */ +}; +#define BASE_SIZE 229U +#define FLS_OUT (txn + 15U) +#define LLS_OUT (txn + 21U) +#define FEE_OUT (txn + 26U) +#define HOOK_ACC (txn + 71U) +#define DEST_ACC (txn + 93U) +#define EMIT_OUT (txn + 113U) +#define AMOUNTS_OUT (txn + 229U) +int64_t hook(uint32_t reserved) { + TRACESTR("IDOM :: Initial Dex Offering :: Called"); + uint8_t hook_acc[20]; + if (hook_account(SBUF(hook_acc)) != 20) + NOPE("Failed to get hook account."); + int64_t tt = otxn_type(); + if (tt == ttINVOKE) { + uint8_t otxn_acc[20]; + if (otxn_field(SBUF(otxn_acc), sfAccount) != 20) + NOPE("Failed to get origin account."); + if (!BUFFER_EQUAL_20(otxn_acc, hook_acc)) { + uint8_t admin_acc[20]; + if (hook_param(SBUF(admin_acc), "ADMIN", 5) != 20) + NOPE("ADMIN parameter not set."); + if (!BUFFER_EQUAL_20(otxn_acc, admin_acc)) + NOPE("Unauthorized invoke."); + } + uint8_t start_key[5] = {'S', 'T', 'A', 'R', 'T'}; + uint8_t existing_start_buf[4]; + if (state(SBUF(existing_start_buf), SBUF(start_key)) == 4) { + uint32_t existing_start = UINT32_FROM_BUF(existing_start_buf); + int64_t current_ledger = ledger_seq(); + if ((uint32_t)current_ledger >= existing_start) + NOPE("Window has already started, cannot restart."); + } + uint8_t wp_buf[256]; + int64_t wp_len = hook_param(SBUF(wp_buf), "WP_LNK", 6); + if (wp_len < 1) + NOPE("WP_LNK parameter not set."); + uint8_t interval_key[8] = {'I','N','T','E','R','V','A','L'}; + uint8_t interval_buf[4]; + if (hook_param(SBUF(interval_buf), SBUF(interval_key)) != 4) + NOPE("INTERVAL not set on install."); + uint32_t interval_offset = UINT32_FROM_BUF(interval_buf); + uint8_t start_buf[4]; + int64_t start_len = otxn_param(SBUF(start_buf), SBUF(start_key)); + if (start_len != 4) + NOPE("Invalid START parameter."); + uint32_t start_offset = UINT32_FROM_BUF(start_buf); + int64_t current_ledger = ledger_seq(); + uint32_t current_ledger_u = (uint32_t)current_ledger; + uint32_t start_ledger = current_ledger_u + start_offset; + uint32_t end_ledger = start_ledger + 5 * interval_offset; + TRACESTR("IDOM :: Setting window"); + TRACEVAR(current_ledger_u); + TRACEVAR(start_offset); + TRACEVAR(interval_offset); + TRACEVAR(start_ledger); + TRACEVAR(end_ledger); + uint8_t wp_lnk_key[6] = {'W', 'P', '_', 'L', 'N', 'K'}; + if (state_set(wp_buf, wp_len, wp_lnk_key, 6) < 0) + NOPE("Failed to store WP_LNK in state."); + uint8_t start_state[4]; + UINT32_TO_BUF(start_state, start_ledger); + uint8_t end_state[4]; + UINT32_TO_BUF(end_state, end_ledger); + uint8_t end_key[3] = {'E', 'N', 'D'}; + if (state_set(start_state, 4, start_key, 5) < 0 || + state_set(interval_buf, 4, interval_key, 8) < 0 || + state_set(end_state, 4, end_key, 3) < 0) + NOPE("Failed to set state."); + uint8_t soft_cap_buf[8]; + if (hook_param(SBUF(soft_cap_buf), "SOFT_CAP", 8) != 8) + NOPE("SOFT_CAP parameter not set."); + uint8_t soft_cap_key[8] = {'S', 'O', 'F', 'T', '_', 'C', 'A', 'P'}; + if (state_set(SBUF(soft_cap_buf), soft_cap_key, 8) < 0) + NOPE("Failed to store SOFT_CAP in state."); + DONE("Window set."); + } + uint8_t otxn_acc[20]; + if (otxn_field(SBUF(otxn_acc), sfAccount) != 20) + NOPE("Failed to get origin account."); + uint8_t amount_buffer[48]; + int64_t amount_len = otxn_field(SBUF(amount_buffer), sfAmount); + if (BUFFER_EQUAL_20(hook_acc, otxn_acc)) { + if (amount_len == 48) { + DONE("Accepted :: Outgoing IOU payment."); + } else if (amount_len == 8) { + uint8_t acct_kl[34]; + util_keylet(SBUF(acct_kl), KEYLET_ACCOUNT, SBUF(hook_acc), 0, 0, 0, 0); + if (slot_set(SBUF(acct_kl), 1) != 1) + NOPE("Could not load account keylet."); + if (slot_subfield(1, sfBalance, 1) != 1) + NOPE("Could not load sfBalance."); + int64_t balance_xfl = slot_float(1); + int64_t balance_drops = float_int(balance_xfl, 6, 0); + int64_t outgoing_drops = AMOUNT_TO_DROPS(amount_buffer); + uint8_t xah_key[3] = {'X', 'A', 'H'}; + uint8_t xah_buf[8]; + uint64_t total_xah = 0; + if (state(SBUF(xah_buf), SBUF(xah_key)) == 8) + total_xah = UINT64_FROM_BUF(xah_buf); + uint8_t start_key[5] = {'S', 'T', 'A', 'R', 'T'}; + uint8_t interval_key[8] = {'I','N','T','E','R','V','A','L'}; + uint8_t start_buf[4]; + uint8_t interval_buf[4]; + if (state(SBUF(start_buf), SBUF(start_key)) == 4 && + state(SBUF(interval_buf), SBUF(interval_key)) == 4) { + uint32_t start_ledger = UINT32_FROM_BUF(start_buf); + uint32_t interval_offset = UINT32_FROM_BUF(interval_buf); + uint32_t phase4_end = start_ledger + (4 * interval_offset); + int64_t current_ledger = ledger_seq(); + uint32_t current_ledger_u = (uint32_t)current_ledger; + if (current_ledger_u >= phase4_end) { + uint8_t refund_key[6] = {'R', 'E', 'F', 'U', 'N', 'D'}; + uint8_t refund_flag[1]; + int64_t refund_check = state(SBUF(refund_flag), SBUF(refund_key)); + if (refund_check < 0) { + // Evaluate soft cap + uint8_t soft_cap_buf[8]; + if (hook_param(SBUF(soft_cap_buf), "SOFT_CAP", 8) == 8) { + uint64_t soft_cap_xah = UINT64_FROM_BUF(soft_cap_buf); + uint8_t total_xah_buf[8]; + uint64_t total_xah_eval = 0; + if (state(SBUF(total_xah_buf), SBUF(xah_key)) == 8) + total_xah_eval = UINT64_FROM_BUF(total_xah_buf); + if (total_xah_eval >= soft_cap_xah) { + uint8_t refund_inactive[1] = {0}; + state_set(SBUF(refund_inactive), SBUF(refund_key)); + uint8_t total_raised_key[12] = {'T', 'O', 'T', 'A', 'L', '_', 'R', 'A', 'I', 'S', 'E', 'D'}; + state_set(SBUF(total_xah_buf), SBUF(total_raised_key)); + } else { + uint8_t refund_active[1] = {1}; + state_set(SBUF(refund_active), SBUF(refund_key)); + } + } + } + } + } + uint64_t locked_drops = total_xah * 1000000ULL; + uint8_t refund_key[6] = {'R', 'E', 'F', 'U', 'N', 'D'}; + uint8_t refund_flag[1]; + int64_t refund_mode = state(SBUF(refund_flag), SBUF(refund_key)); + uint8_t end_key[3] = {'E', 'N', 'D'}; + uint8_t end_buf[4]; + int sale_over = 0; + if (state(SBUF(end_buf), SBUF(end_key)) == 4) { + uint32_t end_ledger = UINT32_FROM_BUF(end_buf); + int64_t current_ledger = ledger_seq(); + uint32_t current_ledger_u = (uint32_t)current_ledger; + if (current_ledger_u >= end_ledger) + sale_over = 1; + } + if (sale_over && refund_mode == 1 && refund_flag[0] == 0) { + locked_drops = 0; + if (total_xah != 0) { + uint8_t zero_buf[8] = {0}; + state_set(SBUF(zero_buf), SBUF(xah_key)); + } + } + if (balance_drops - locked_drops >= outgoing_drops) { + DONE("Accepted :: Outgoing XAH payment."); + } else { + REJECT("Insufficient unlocked balance."); + } + } else { + DONE("Accepted :: Outgoing payment."); + } + } + if (amount_len == 48) { + if (!BUFFER_EQUAL_20(amount_buffer + 28, hook_acc)) + UNWIND("Wrong issuer."); + int64_t iou_xfl = -INT64_FROM_BUF(amount_buffer); + int64_t iou_amount = float_int(iou_xfl, 0, 1); + TRACEVAR(iou_amount); + uint8_t user_namespace[32]; + for (int i = 0; GUARD(20), i < 20; ++i) + user_namespace[i] = otxn_acc[i]; + for (int i = 20; GUARD(32), i < 32; ++i) + user_namespace[i] = 0; + uint8_t ido_data_key[8] = {'I', 'D', 'O', '_', 'D', 'A', 'T', 'A'}; + uint8_t user_data[16]; + state_foreign(SBUF(user_data), ido_data_key, 8, user_namespace, 32, hook_acc, 20); + uint64_t user_total_xah = UINT64_FROM_BUF(user_data); + uint64_t user_total_iou = UINT64_FROM_BUF(user_data + 8); + TRACEVAR(user_total_xah); + TRACEVAR(user_total_iou); + uint8_t start_key[5] = {'S', 'T', 'A', 'R', 'T'}; + uint8_t interval_key[8] = {'I','N','T','E','R','V','A','L'}; + uint8_t start_buf[4]; + uint8_t interval_buf[4]; + if (state(SBUF(start_buf), SBUF(start_key)) == 4 && + state(SBUF(interval_buf), SBUF(interval_key)) == 4) { + uint32_t start_ledger = UINT32_FROM_BUF(start_buf); + uint32_t interval_offset = UINT32_FROM_BUF(interval_buf); + uint32_t phase4_end = start_ledger + (4 * interval_offset); + int64_t current_ledger = ledger_seq(); + uint32_t current_ledger_u = (uint32_t)current_ledger; + if (current_ledger_u >= phase4_end) { + uint8_t refund_key[6] = {'R', 'E', 'F', 'U', 'N', 'D'}; + uint8_t refund_flag[1]; + int64_t refund_check = state(SBUF(refund_flag), SBUF(refund_key)); + if (refund_check < 0) { + uint8_t soft_cap_buf[8]; + if (hook_param(SBUF(soft_cap_buf), "SOFT_CAP", 8) == 8) { + uint64_t soft_cap_xah = UINT64_FROM_BUF(soft_cap_buf); + uint8_t xah_key[3] = {'X', 'A', 'H'}; + uint8_t total_xah_buf[8]; + uint64_t total_xah = 0; + if (state(SBUF(total_xah_buf), SBUF(xah_key)) == 8) + total_xah = UINT64_FROM_BUF(total_xah_buf); + TRACEVAR(total_xah); + TRACEVAR(soft_cap_xah); + if (total_xah < soft_cap_xah) { + uint8_t refund_active[1] = {1}; + state_set(SBUF(refund_active), SBUF(refund_key)); + TRACESTR("IDOM :: Soft cap NOT met. Phase 5 is now REFUND period."); + } else { + uint8_t refund_inactive[1] = {0}; + state_set(SBUF(refund_inactive), SBUF(refund_key)); + TRACESTR("IDOM :: Soft cap MET. Sale successful!"); + uint8_t total_raised_key[12] = {'T', 'O', 'T', 'A', 'L', '_', 'R', 'A', 'I', 'S', 'E', 'D'}; + state_set(SBUF(total_xah_buf), SBUF(total_raised_key)); + TRACESTR("IDOM :: Soft cap met. Funds will unlock after cooldown period."); + } + } + } + } + } + uint8_t refund_key[6] = {'R', 'E', 'F', 'U', 'N', 'D'}; + uint8_t refund_flag[1]; + int64_t refund_mode = state(SBUF(refund_flag), SBUF(refund_key)); + int is_refund_active = (refund_mode == 1 && refund_flag[0] == 1); + + if (is_refund_active) { + TRACESTR("IDOM :: Refund mode - accepting the exact IOU amount issued for proportional refund."); + } else { + if (iou_amount != user_total_iou) + UNWIND("Amount not exact to total IOU."); + uint8_t end_key[3] = {'E', 'N', 'D'}; + uint8_t end_buf[4]; + if (state(SBUF(end_buf), SBUF(end_key)) == 4) { + uint32_t end_ledger = UINT32_FROM_BUF(end_buf); + int64_t current_ledger = ledger_seq(); + uint32_t current_ledger_u = (uint32_t)current_ledger; + if (current_ledger_u >= end_ledger) { + UNWIND("Sale successful and cooldown period has ended, unwind's are no longer possible."); + } + } + } + etxn_reserve(1); + uint8_t pay_txn[PREPARE_PAYMENT_SIMPLE_SIZE]; + uint64_t xah_drops = user_total_xah * 1000000; + PREPARE_PAYMENT_SIMPLE(pay_txn, xah_drops, otxn_acc, 0, 0); + uint8_t emithash[32]; + if (emit(SBUF(emithash), SBUF(pay_txn)) < 0) + UNWIND("Emit failed."); + uint8_t exec_key[4] = {'E', 'X', 'E', 'C'}; + uint8_t xah_key[3] = {'X', 'A', 'H'}; + uint8_t iou_key[3] = {'I', 'O', 'U'}; + uint8_t exec_buf[8]; + if (state(SBUF(exec_buf), SBUF(exec_key)) == 8) { + uint64_t executions = UINT64_FROM_BUF(exec_buf) - 1; + UINT64_TO_BUF(exec_buf, executions); + state_set(SBUF(exec_buf), SBUF(exec_key)); + } + uint8_t xah_buf[8]; + if (state(SBUF(xah_buf), SBUF(xah_key)) == 8) { + uint64_t total_xah = UINT64_FROM_BUF(xah_buf) - user_total_xah; + UINT64_TO_BUF(xah_buf, total_xah); + state_set(SBUF(xah_buf), SBUF(xah_key)); + } + uint8_t iou_buf[8]; + if (state(SBUF(iou_buf), SBUF(iou_key)) == 8) { + uint64_t total_iou = UINT64_FROM_BUF(iou_buf) - user_total_iou; + UINT64_TO_BUF(iou_buf, total_iou); + state_set(SBUF(iou_buf), SBUF(iou_key)); + } + state_foreign_set(0, 0, ido_data_key, 8, user_namespace, 32, hook_acc, 20); + DONE("Unwind :: XAH returned."); + } + uint8_t otxn_wp_buf[256]; + int64_t otxn_wp_len = otxn_param(SBUF(otxn_wp_buf), "WP_LNK", 6); + uint8_t wp_lnk_key[6] = {'W', 'P', '_', 'L', 'N', 'K'}; + uint8_t stored_wp_buf[256]; + int64_t stored_wp_len = state(SBUF(stored_wp_buf), SBUF(wp_lnk_key)); + if (stored_wp_len < 1) + NOPE("WP_LNK not found in state, awaiting issuer initialization."); + if (otxn_wp_len != stored_wp_len) + REJECT("WP_LNK parameter does not match. Verify whitepaper link."); + for (int i = 0; GUARD(256), i < otxn_wp_len; i++) { + if (otxn_wp_buf[i] != stored_wp_buf[i]) + REJECT("WP_LNK parameter does not match. Verify whitepaper link."); + } + TRACESTR("IDOM :: WP_LNK validated - user acknowledged documentation."); + uint8_t interval_key[8] = {'I','N','T','E','R','V','A','L'}; + uint8_t interval_param_buf[4]; + if (hook_param(SBUF(interval_param_buf), SBUF(interval_key)) != 4) + NOPE("INTERVAL not set."); + uint32_t interval_offset = UINT32_FROM_BUF(interval_param_buf); + uint8_t start_key[5] = {'S', 'T', 'A', 'R', 'T'}; + uint8_t end_key[3] = {'E', 'N', 'D'}; + uint8_t start_buf[4]; + uint8_t end_buf[4]; + if (state(SBUF(start_buf), SBUF(start_key)) != 4 || + state(SBUF(end_buf), SBUF(end_key)) != 4) + NOPE("Window not set."); + uint32_t start_ledger = UINT32_FROM_BUF(start_buf); + uint32_t end_ledger = UINT32_FROM_BUF(end_buf); + int64_t current_ledger = ledger_seq(); + uint32_t current_ledger_u = (uint32_t)current_ledger; + uint32_t phase4_end = start_ledger + (4 * interval_offset); + if (current_ledger_u >= phase4_end) { + uint8_t refund_key[6] = {'R', 'E', 'F', 'U', 'N', 'D'}; + uint8_t refund_flag[1]; + int64_t refund_check = state(SBUF(refund_flag), SBUF(refund_key)); + if (refund_check < 0) { + uint8_t soft_cap_buf[8]; + if (hook_param(SBUF(soft_cap_buf), "SOFT_CAP", 8) != 8) + NOPE("SOFT_CAP parameter not set."); + uint64_t soft_cap_xah = UINT64_FROM_BUF(soft_cap_buf); + uint8_t xah_key[3] = {'X', 'A', 'H'}; + uint8_t total_xah_buf[8]; + uint64_t total_xah = 0; + if (state(SBUF(total_xah_buf), SBUF(xah_key)) == 8) + total_xah = UINT64_FROM_BUF(total_xah_buf); + TRACEVAR(total_xah); + TRACEVAR(soft_cap_xah); + if (total_xah < soft_cap_xah) { + uint8_t refund_active[1] = {1}; + state_set(SBUF(refund_active), SBUF(refund_key)); + TRACESTR("IDOM :: Soft cap NOT met. Phase 5 is now REFUND period."); + } else { + uint8_t refund_inactive[1] = {0}; + state_set(SBUF(refund_inactive), SBUF(refund_key)); + TRACESTR("IDOM :: Soft cap MET. Sale successful!"); + uint8_t total_raised_key[12] = {'T', 'O', 'T', 'A', 'L', '_', 'R', 'A', 'I', 'S', 'E', 'D'}; + state_set(SBUF(total_xah_buf), SBUF(total_raised_key)); + } + } + } + if (current_ledger_u >= end_ledger) { + uint8_t refund_key[6] = {'R', 'E', 'F', 'U', 'N', 'D'}; + uint8_t refund_flag[1]; + int64_t refund_mode = state(SBUF(refund_flag), SBUF(refund_key)); + + if (refund_mode == 1 && refund_flag[0] == 1) + REJECT("Window ended. Soft cap not met. Send IOU to unwind for refund."); + REJECT("Window has ended."); + } + int64_t received_drops = AMOUNT_TO_DROPS(amount_buffer); + int64_t received_xah = received_drops / 1000000; + TRACEVAR(received_xah); + uint32_t elapsed = current_ledger_u - start_ledger; + uint32_t phase = (elapsed / interval_offset) + 1; + int64_t multiplier = 0; + if (phase == 1) { + multiplier = 100; + TRACESTR("IDOM :: Phase 1 active, 100x multiplyer is in effect."); + } else if (phase == 2) { + multiplier = 75; + TRACESTR("IDOM :: Phase 2 active, 75x multiplyer is in effect."); + } else if (phase == 3) { + multiplier = 50; + TRACESTR("IDOM :: Phase 3 active, 50x multiplyer is in effect."); + } else if (phase == 4) { + multiplier = 25; + TRACESTR("IDOM :: Phase 4 active, 25x multiplyer is in effect."); + } else if (phase == 5) { + TRACESTR("IDOM :: Phase 5 active, Cooldown period enabled."); + REJECT("Phase 5 is for unwinding only, no new deposits."); + } else { + REJECT("Invalid phase."); + } + int64_t issued_amount = received_xah * multiplier; + if (issued_amount == 0) + FAIL("Issued amount is zero."); + TRACEVAR(issued_amount); + uint8_t exec_key[4] = {'E', 'X', 'E', 'C'}; + uint8_t xah_key[3] = {'X', 'A', 'H'}; + uint8_t iou_key[3] = {'I', 'O', 'U'}; + uint8_t exec_buf[8] = {0}; + uint64_t executions = 0; + if (state(SBUF(exec_buf), SBUF(exec_key)) == 8) + executions = UINT64_FROM_BUF(exec_buf); + executions++; + UINT64_TO_BUF(exec_buf, executions); + if (state_set(SBUF(exec_buf), SBUF(exec_key)) < 0) + FAIL("Failed to update executions counter."); + uint8_t xah_buf[8] = {0}; + uint64_t total_xah = 0; + if (state(SBUF(xah_buf), SBUF(xah_key)) == 8) + total_xah = UINT64_FROM_BUF(xah_buf); + total_xah += received_xah; + UINT64_TO_BUF(xah_buf, total_xah); + if (state_set(SBUF(xah_buf), SBUF(xah_key)) < 0) + FAIL("Failed to update XAH total."); + uint8_t iou_buf[8] = {0}; + uint64_t total_iou = 0; + if (state(SBUF(iou_buf), SBUF(iou_key)) == 8) + total_iou = UINT64_FROM_BUF(iou_buf); + total_iou += issued_amount; + UINT64_TO_BUF(iou_buf, total_iou); + if (state_set(SBUF(iou_buf), SBUF(iou_key)) < 0) + FAIL("Failed to update IOU total."); + uint8_t phase_key[6]; + phase_key[0] = 'P'; + phase_key[1] = 'H'; + phase_key[2] = 'A'; + phase_key[3] = 'S'; + phase_key[4] = 'E'; + phase_key[5] = '0' + (uint8_t)phase; + uint8_t phase_buf[8] = {0}; + uint64_t phase_exec = 0; + if (state(SBUF(phase_buf), phase_key, 6) == 8) + phase_exec = UINT64_FROM_BUF(phase_buf); + phase_exec++; + UINT64_TO_BUF(phase_buf, phase_exec); + if (state_set(SBUF(phase_buf), phase_key, 6) < 0) + FAIL("Failed to update phase executions counter."); + uint8_t user_namespace[32]; + for (int i = 0; GUARD(20), i < 20; ++i) + user_namespace[i] = otxn_acc[i]; + for (int i = 20; GUARD(32), i < 32; ++i) + user_namespace[i] = 0; + uint8_t ido_data_key[8] = {'I', 'D', 'O', '_', 'D', 'A', 'T', 'A'}; + uint8_t user_data[16] = {0}; + state_foreign(SBUF(user_data), ido_data_key, 8, user_namespace, 32, hook_acc, 20); + uint64_t user_total_xah = UINT64_FROM_BUF(user_data); + uint64_t user_total_iou = UINT64_FROM_BUF(user_data + 8); + user_total_xah += received_xah; + user_total_iou += issued_amount; + UINT64_TO_BUF(user_data, user_total_xah); + UINT64_TO_BUF(user_data + 8, user_total_iou); + if (state_foreign_set(user_data, 16, ido_data_key, 8, user_namespace, 32, hook_acc, 20) < 0) + FAIL("Failed to update user data."); + uint8_t* amounts_ptr = AMOUNTS_OUT; + *amounts_ptr++ = 0xF0U; + *amounts_ptr++ = 0x5CU; + *amounts_ptr++ = 0xE0U; + *amounts_ptr++ = 0x5BU; + uint8_t currency[20]; + if (hook_param(SBUF(currency), "CURRENCY", 8) != 20) + NOPE("CURRENCY parameter not set."); + int64_t amount_xfl = float_set(0, issued_amount); + int32_t amount_len_remit = float_sto( + amounts_ptr, 49, + currency, 20, + hook_acc, 20, + amount_xfl, + sfAmount + ); + if (amount_len_remit < 0) + FAIL("Failed to serialize amount."); + amounts_ptr += amount_len_remit; + *amounts_ptr++ = 0xE1U; + *amounts_ptr++ = 0xF1U; + int32_t amounts_len = amounts_ptr - AMOUNTS_OUT; + hook_account(HOOK_ACC, 20); + for (int i = 0; GUARD(20), i < 20; ++i) + DEST_ACC[i] = otxn_acc[i]; + etxn_reserve(1); + int32_t total_size = BASE_SIZE + amounts_len; + etxn_details(EMIT_OUT, 116U); + int64_t seq = ledger_seq() + 1; + txn[15] = (seq >> 24U) & 0xFFU; + txn[16] = (seq >> 16U) & 0xFFU; + txn[17] = (seq >> 8U) & 0xFFU; + txn[18] = seq & 0xFFU; + seq += 4; + txn[21] = (seq >> 24U) & 0xFFU; + txn[22] = (seq >> 16U) & 0xFFU; + txn[23] = (seq >> 8U) & 0xFFU; + txn[24] = seq & 0xFFU; + int64_t fee = etxn_fee_base(txn, total_size); + if (fee < 0) + FAIL("Fee calculation failed."); + uint64_t fee_tmp = fee; + uint8_t* fee_ptr = (uint8_t*)&fee; + *fee_ptr++ = 0b01000000 + ((fee_tmp >> 56) & 0b00111111); + *fee_ptr++ = (fee_tmp >> 48) & 0xFFU; + *fee_ptr++ = (fee_tmp >> 40) & 0xFFU; + *fee_ptr++ = (fee_tmp >> 32) & 0xFFU; + *fee_ptr++ = (fee_tmp >> 24) & 0xFFU; + *fee_ptr++ = (fee_tmp >> 16) & 0xFFU; + *fee_ptr++ = (fee_tmp >> 8) & 0xFFU; + *fee_ptr++ = (fee_tmp >> 0) & 0xFFU; + *((uint64_t*)(txn + 26)) = fee; + uint8_t emithash[32]; + int64_t emit_result = emit(SBUF(emithash), txn, total_size); + if (emit_result < 0) + FAIL("Emit failed."); + DONE("Accepted :: Incoming payment during active phase."); + _g(1,0); + return 0; +} diff --git a/IssuanceHookset/Fin/README.md b/IssuanceHookset/Fin/README.md new file mode 100644 index 0000000..508a590 --- /dev/null +++ b/IssuanceHookset/Fin/README.md @@ -0,0 +1,13 @@ +# Mainnet Hooks - Condensed Version + +This folder contains the condensed versions of the mainnet hooks for the IDO (Initial Dex Offering) system. These hooks have been stripped of comments to reduce file size and focus on the core functionality. + +## Hooks Included + +- **Router.c**: Routes transactions to appropriate hooks based on type and parameters. +- **Rewards.c**: Handles rewards claiming for participants. +- **IDOMulti.c**: Manages the IDO process, including phases, payments, and refunds. + +## Usage + +These hooks are intended for deployment on the Xahau mainnet. Ensure all parameters are set correctly before installation. \ No newline at end of file diff --git a/IssuanceHookset/Fin/Rewards.c b/IssuanceHookset/Fin/Rewards.c new file mode 100644 index 0000000..5a97223 --- /dev/null +++ b/IssuanceHookset/Fin/Rewards.c @@ -0,0 +1,252 @@ +#include "hookapi.h" + +#define sfAmountEntry ((14U << 16U) + 91U) +#define sfAmounts ((15U << 16U) + 92U) + +#define FLIP_ENDIAN(n) ((uint32_t) (((n & 0xFFU) << 24U) | \ + ((n & 0xFF00U) << 8U) | \ + ((n & 0xFF0000U) >> 8U) | \ + ((n & 0xFF000000U) >> 24U))) + +#define DONE(x) accept(SBUF("IRH :: Success :: " x), __LINE__) +#define NOPE(x) rollback(SBUF("IRH :: Error :: " x), __LINE__) +#define GUARD(maxiter) _g(__LINE__, (maxiter) + 1) +#define UINT64_FROM_BUF(buf) \ + (((uint64_t)(buf)[0] << 56) + ((uint64_t)(buf)[1] << 48) + \ + ((uint64_t)(buf)[2] << 40) + ((uint64_t)(buf)[3] << 32) + \ + ((uint64_t)(buf)[4] << 24) + ((uint64_t)(buf)[5] << 16) + \ + ((uint64_t)(buf)[6] << 8) + (uint64_t)(buf)[7]) + +uint8_t txn[350] = +{ +/* size,upto */ +/* 3, 0 */ 0x12U, 0x00U, 0x5FU, /* ttREMIT */ +/* 5, 3 */ 0x22U, 0x80U, 0x00U, 0x00U, 0x00U, /* Flags */ +/* 5, 8 */ 0x24U, 0x00U, 0x00U, 0x00U, 0x00U, /* Sequence */ +/* 6, 13 */ 0x20U, 0x1AU, 0x00U, 0x00U, 0x00U, 0x00U, /* FirstLedgerSequence */ +/* 6, 19 */ 0x20U, 0x1BU, 0x00U, 0x00U, 0x00U, 0x00U, /* LastLedgerSequence */ +/* 9, 25 */ 0x68U, 0x40U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, /* Fee */ +/* 35, 34 */ 0x73U, 0x21U, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* SigningPubKey */ +/* 22, 69 */ 0x81U, 0x14U, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* Account */ +/* 22, 91 */ 0x83U, 0x14U, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* Destination */ +/* 116, 113 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* EmitDetails */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +/* 0, 229 */ /* Amounts array appended here */ +}; +#define BASE_SIZE 229U +#define FLS_OUT (txn + 15U) +#define LLS_OUT (txn + 21U) +#define FEE_OUT (txn + 26U) +#define HOOK_ACC (txn + 71U) +#define DEST_ACC (txn + 93U) +#define EMIT_OUT (txn + 113U) +#define AMOUNTS_OUT (txn + 229U) +int64_t hook(uint32_t reserved) { + TRACESTR("IRH :: Issued Rewards Hook :: Called."); + if (otxn_type() != 99) + DONE("Non-INVOKE transaction passed through."); + uint8_t hook_acc[20]; + if (hook_account(SBUF(hook_acc)) != 20) + NOPE("Failed to get hook account."); + uint8_t otxn_acc[20]; + if (otxn_field(SBUF(otxn_acc), sfAccount) != 20) + NOPE("Failed to get origin account."); + if (BUFFER_EQUAL_20(hook_acc, otxn_acc)) + DONE("Outgoing invoke transaction passed through."); + uint8_t currency[20]; + if(hook_param(SBUF(currency), "CURRENCY", 8) != 20) + NOPE("Misconfigured. CURRENCY not set as Hook Parameter."); + uint8_t invoke_acc[20]; + if(hook_param(SBUF(invoke_acc), "ADMIN", 5) != 20) + NOPE("Misconfigured. ADMIN not set as Hook Parameter."); + uint8_t interest_rate_key[8] = "INT_RATE"; + uint8_t interval_key[8] = "CLAIM_INT"; + uint8_t max_claims_key[8] = "MAX_CLM\0"; + uint8_t install_int_rate[4]; + if(hook_param(SBUF(install_int_rate), "INT_RATE", 8) == 4) { + if(state_set(SBUF(install_int_rate), SBUF(interest_rate_key)) != 4) + NOPE("Failed to set install-time interest rate."); + } + uint8_t install_interval[4]; + if(hook_param(SBUF(install_interval), "SET_INTERVAL", 12) == 4) { + if(state_set(SBUF(install_interval), SBUF(interval_key)) != 4) + NOPE("Failed to set install-time claim interval."); + } + uint8_t install_max_claims[4]; + if(hook_param(SBUF(install_max_claims), "SET_MAX_CLAIMS", 14) == 4) { + if(state_set(SBUF(install_max_claims), SBUF(max_claims_key)) != 4) + NOPE("Failed to set install-time max claims."); + } + if (BUFFER_EQUAL_20(otxn_acc, invoke_acc)) { + uint8_t set_interest_param[4]; + if(otxn_param(SBUF(set_interest_param), "INT_RATE", 8) == 4) { + if(state_set(SBUF(set_interest_param), SBUF(interest_rate_key)) != 4) + NOPE("Failed to set interest rate."); + DONE("Interest rate configured successfully."); + } + uint8_t set_interval_param[4]; + if(otxn_param(SBUF(set_interval_param), "SET_INTERVAL", 12) == 4) { + if(state_set(SBUF(set_interval_param), SBUF(interval_key)) != 4) + NOPE("Failed to set claim interval."); + DONE("Claim interval configured successfully."); + } + uint8_t set_max_claims_param[4]; + if(otxn_param(SBUF(set_max_claims_param), "SET_MAX_CLAIMS", 14) == 4) { + if(state_set(SBUF(set_max_claims_param), SBUF(max_claims_key)) != 4) + NOPE("Failed to set max claims limit."); + DONE("Max claims limit configured successfully."); + } + DONE("Admin configuration: No valid parameters provided."); + } else { + uint8_t claim_param[20]; + if(otxn_param(SBUF(claim_param), "R_CLAIM", 7) == 20) { + uint8_t interest_rate_buf[4]; + if(state(SBUF(interest_rate_buf), SBUF(interest_rate_key)) != 4) + NOPE("INT_RATE not configured - admin must use SET_INTEREST_RATE first."); + uint32_t interest_rate = (uint32_t)((interest_rate_buf[0] << 24) | (interest_rate_buf[1] << 16) | + (interest_rate_buf[2] << 8) | interest_rate_buf[3]); + if (interest_rate == 0) + NOPE("Invalid interest rate - must be positive."); + uint8_t interval_buf[4]; + if(state(SBUF(interval_buf), SBUF(interval_key)) != 4) + NOPE("SET_INTERVAL not configured - admin must set claim interval first."); + + uint32_t claim_interval = (uint32_t)((interval_buf[0] << 24) | (interval_buf[1] << 16) | + (interval_buf[2] << 8) | interval_buf[3]); + uint32_t max_claims = 0; + uint8_t max_claims_buf[4]; + if(state(SBUF(max_claims_buf), SBUF(max_claims_key)) == 4) { + max_claims = (uint32_t)((max_claims_buf[0] << 24) | (max_claims_buf[1] << 16) | + (max_claims_buf[2] << 8) | max_claims_buf[3]); + } + uint8_t keylet[34]; + if (util_keylet(SBUF(keylet), KEYLET_LINE, SBUF(hook_acc), SBUF(otxn_acc), SBUF(currency)) != 34) + NOPE("Could not generate trustline keylet."); + if (slot_set(SBUF(keylet), 1) != 1) + NOPE("Claimant account does not have required trustline."); + if (slot_subfield(1, sfBalance, 1) != 1) + NOPE("Could not load trustline balance."); + int64_t balance_xfl = slot_float(1); + if (float_compare(balance_xfl, float_set(0, 0), COMPARE_LESS) == 1) + balance_xfl = float_negate(balance_xfl); + int64_t rate_xfl = float_set(0, interest_rate); + int64_t percent_xfl = float_set(0, 10000); + int64_t rate_fraction = float_divide(rate_xfl, percent_xfl); + if (rate_fraction < 0) + NOPE("Invalid rate calculation."); + int64_t claim_amount_xfl = float_multiply(balance_xfl, rate_fraction); + if (claim_amount_xfl < 0) + NOPE("Invalid claim amount calculation."); + uint8_t user_namespace[32]; + for (int i = 0; GUARD(20), i < 20; ++i) + user_namespace[i] = otxn_acc[i]; + for (int i = 20; GUARD(32), i < 32; ++i) + user_namespace[i] = 0; + uint8_t ido_data_key[8] = {'I', 'D', 'O', '_', 'D', 'A', 'T', 'A'}; + uint8_t ido_user_data[16] = {0}; + int64_t ido_result = state_foreign(SBUF(ido_user_data), SBUF(ido_data_key), SBUF(user_namespace), SBUF(hook_acc)); + if (ido_result == 16) { + uint64_t user_total_iou = UINT64_FROM_BUF(ido_user_data + 8); + if (user_total_iou > 0) { + uint32_t bonus_rate = interest_rate + 500; + int64_t bonus_rate_xfl = float_set(0, bonus_rate); + int64_t bonus_rate_fraction = float_divide(bonus_rate_xfl, percent_xfl); + if (bonus_rate_fraction >= 0) { + claim_amount_xfl = float_multiply(balance_xfl, bonus_rate_fraction); + } + } + } + uint8_t claim_key[32] = "CLAIM_DATA"; + for (int i = 10; GUARD(32), i < 32; ++i) + claim_key[i] = 0; + uint8_t user_state[8] = {0}; + int64_t state_result = state_foreign(SBUF(user_state), SBUF(claim_key), + SBUF(user_namespace), SBUF(hook_acc)); + uint32_t current_ledger = (uint32_t)ledger_seq(); + uint32_t last_claim_ledger = 0; + uint32_t total_claims = 0; + if (state_result == 8) { + last_claim_ledger = (uint32_t)((user_state[0] << 24) | (user_state[1] << 16) | + (user_state[2] << 8) | user_state[3]); + total_claims = (uint32_t)((user_state[4] << 24) | (user_state[5] << 16) | + (user_state[6] << 8) | user_state[7]); + } + if (last_claim_ledger > 0) { + uint32_t ledgers_elapsed = current_ledger - last_claim_ledger; + if (ledgers_elapsed < claim_interval) { + NOPE("Too soon - wait more ledgers before next claim."); + } + } + if (max_claims > 0 && total_claims >= max_claims) + NOPE("Maximum lifetime claims reached."); + hook_account(HOOK_ACC, 20); + for (int i = 0; GUARD(20), i < 20; ++i) + DEST_ACC[i] = otxn_acc[i]; + uint8_t* amounts_ptr = AMOUNTS_OUT; + *amounts_ptr++ = 0xF0U; + *amounts_ptr++ = 0x5CU; + *amounts_ptr++ = 0xE0U; + *amounts_ptr++ = 0x5BU; + int32_t amount_len = float_sto( + amounts_ptr, 49, + currency, 20, + HOOK_ACC, 20, + claim_amount_xfl, + sfAmount + ); + if (amount_len < 0) + NOPE("Failed to serialize claim amount."); + amounts_ptr += amount_len; + *amounts_ptr++ = 0xE1U; + *amounts_ptr++ = 0xF1U; + int32_t amounts_len = amounts_ptr - AMOUNTS_OUT; + etxn_reserve(1); + int32_t total_size = BASE_SIZE + amounts_len; + int64_t seq = current_ledger + 1; + txn[15] = (seq >> 24U) & 0xFFU; + txn[16] = (seq >> 16U) & 0xFFU; + txn[17] = (seq >> 8U) & 0xFFU; + txn[18] = seq & 0xFFU; + seq += 4; + txn[21] = (seq >> 24U) & 0xFFU; + txn[22] = (seq >> 16U) & 0xFFU; + txn[23] = (seq >> 8U) & 0xFFU; + txn[24] = seq & 0xFFU; + etxn_details(EMIT_OUT, 116U); + int64_t fee = etxn_fee_base(txn, total_size); + { + uint8_t *b = FEE_OUT; + *b++ = 0b01000000 + ((fee >> 56) & 0b00111111); + *b++ = (fee >> 48) & 0xFFU; + *b++ = (fee >> 40) & 0xFFU; + *b++ = (fee >> 32) & 0xFFU; + *b++ = (fee >> 24) & 0xFFU; + *b++ = (fee >> 16) & 0xFFU; + *b++ = (fee >> 8) & 0xFFU; + *b++ = (fee >> 0) & 0xFFU; + } + uint8_t claim_emithash[32]; + if(emit(SBUF(claim_emithash), txn, total_size) < 0) + NOPE("Failed to emit claim transaction."); + uint8_t new_state[8]; + new_state[0] = (current_ledger >> 24) & 0xFF; + new_state[1] = (current_ledger >> 16) & 0xFF; + new_state[2] = (current_ledger >> 8) & 0xFF; + new_state[3] = current_ledger & 0xFF; + uint32_t new_total_claims = total_claims + 1; + new_state[4] = (new_total_claims >> 24) & 0xFF; + new_state[5] = (new_total_claims >> 16) & 0xFF; + new_state[6] = (new_total_claims >> 8) & 0xFF; + new_state[7] = new_total_claims & 0xFF; + if(state_foreign_set(SBUF(new_state), SBUF(claim_key), + SBUF(user_namespace), SBUF(hook_acc)) != 8) + NOPE("Failed to update user state."); + DONE("Tokens claimed successfully."); + } else { + DONE("Invoke from non-whitelisted account passed through."); + } + } + _g(1,1); + return 0; +} \ No newline at end of file diff --git a/IssuanceHookset/Fin/Router.c b/IssuanceHookset/Fin/Router.c new file mode 100644 index 0000000..3696402 --- /dev/null +++ b/IssuanceHookset/Fin/Router.c @@ -0,0 +1,150 @@ +#include "hookapi.h" +#define UINT32_FROM_BUF(buf) \ + (((uint32_t)(buf)[0] << 24) + ((uint32_t)(buf)[1] << 16) + \ + ((uint32_t)(buf)[2] << 8) + (uint32_t)(buf)[3]) + +uint8_t IDO_HOOK_HASH[32] = {0x33,0x09,0x61,0xA6,0x81,0x1A,0x03,0x13,0x1B,0x59,0x0D,0x0C,0x69,0x21,0x14,0x47,0xE7,0x8D,0xF7,0x20,0x88,0x98,0xA4,0x4F,0x8C,0xC1,0xE1,0x3C,0x62,0x9F,0x2D,0x2D}; +uint8_t REWARDS_HOOK_HASH[32] = {0x8C,0xFC,0x9A,0xA6,0xAA,0x4A,0x85,0x8D,0xEF,0x04,0xD3,0x04,0x9D,0x4E,0x7D,0x22,0xA3,0x7F,0x96,0x8D,0x05,0x06,0x34,0x24,0x4E,0xC5,0xDA,0xCE,0xCC,0xE6,0x16,0x0D}; +uint8_t IDO_NAMESPACE[32] = {0x51,0x6B,0xA7,0x92,0x15,0x00,0x22,0x76,0xEF,0x4C,0x38,0x1B,0x90,0x19,0x55,0xC5,0x3A,0x04,0x57,0x55,0x89,0x60,0x7E,0x7D,0xBA,0x20,0x46,0x8D,0xD3,0x43,0xDD,0x72}; + +#define DONE(msg) accept(SBUF(msg), __LINE__) +#define NOPE(msg) rollback(SBUF(msg), __LINE__) +#define SKIP() { \ + int64_t r = hook_skip(IDO_HOOK_HASH, 32, 0); \ + if (r < 0) NOPE("Router: Skip failed"); \ +} +#define SKIP_REWARDS() { \ + int64_t r = hook_skip(REWARDS_HOOK_HASH, 32, 0); \ + if (r < 0) NOPE("Router: Skip rewards failed"); \ +} +#define GUARD(max) _g(__LINE__, (max) + 1) +int64_t hook(int32_t reserved) { + uint8_t hookacc[20]; + hook_account(SBUF(hookacc)); + uint8_t sender[20]; + if (otxn_field(SBUF(sender), sfAccount) != 20) { + NOPE("Router: Cannot read sender account"); + } + int outgoing = 1; + int i; + for (i = 0; GUARD(20), i < 20; ++i) { + if (sender[i] != hookacc[i]) { + outgoing = 0; + break; + } + } + int64_t ttype = otxn_type(); + if (outgoing) { + if (ttype == 99) { + SKIP(); + DONE("Router: Outgoing invoke → skip IDO"); + } else if (ttype == 0) { + uint8_t amount[48]; + int64_t alen = otxn_field(SBUF(amount), sfAmount); + if (alen == 8) { + SKIP_REWARDS(); + DONE("Router: Outgoing XAH → run IDO"); + } else { + SKIP(); + DONE("Router: Outgoing non-XAH → skip IDO"); + } + } + } + if (ttype == 99) { + uint8_t dummy[20]; + if (otxn_param(SBUF(dummy), "START", 5) == 4) { + SKIP_REWARDS(); + DONE("Router: START param → run IDO, skip rewards"); + } + if (otxn_param(SBUF(dummy), "INT_RATE", 8) == 8 || + otxn_param(SBUF(dummy), "SET_INTERVAL", 12) == 4 || + otxn_param(SBUF(dummy), "SET_MAX_CLAIMS", 14) == 4) { + SKIP(); + DONE("Router: Rewards admin params → skip IDO"); + } + if (otxn_param(SBUF(dummy), "R_CLAIM", 7) == 20) { + SKIP(); + DONE("Router: R_CLAIM param → skip IDO"); + } + SKIP(); + NOPE("Router: Invoke without START or rewards params → invalid"); + } + int64_t current_ledger = ledger_seq(); + uint8_t start_key[5] = {'S', 'T', 'A', 'R', 'T'}; + uint8_t end_key[3] = {'E', 'N', 'D'}; + uint8_t start_buf[4]; + uint8_t end_buf[4]; + int64_t start_len = state_foreign(SBUF(start_buf), SBUF(start_key), SBUF(IDO_NAMESPACE), SBUF(hookacc)); + int64_t end_len = state_foreign(SBUF(end_buf), SBUF(end_key), SBUF(IDO_NAMESPACE), SBUF(hookacc)); + int window_set = (start_len == 4 && end_len == 4); + int window_active = 0; + if (window_set) { + uint32_t start_ledger = UINT32_FROM_BUF(start_buf); + uint32_t end_ledger = UINT32_FROM_BUF(end_buf); + uint32_t curr = (uint32_t)current_ledger; + if (curr >= start_ledger && curr < end_ledger) { + window_active = 1; + } + } + uint8_t refund_key[6] = {'R','E','F','U','N','D'}; + uint8_t refund_flag = 0; + int64_t refund_len = state_foreign(&refund_flag, 1, SBUF(refund_key), SBUF(IDO_NAMESPACE), SBUF(hookacc)); + int refund_mode = (refund_len == 1 && refund_flag == 1); + if (refund_mode) { + if (ttype == 99) { + NOPE("Router: Refund mode + invoke → invalid"); + } else if (ttype == 0) { + if (outgoing) { + NOPE("Router: Refund mode + outgoing → invalid"); + } + uint8_t amount[48]; + int64_t alen = otxn_field(SBUF(amount), sfAmount); + if (alen != 48) { + NOPE("Router: Refund mode + not IOU → invalid"); + } + SKIP_REWARDS(); + DONE("Router: Refund mode + incoming IOU → run IDO"); + } + } + if (window_set && (uint32_t)current_ledger > UINT32_FROM_BUF(end_buf)) { + SKIP(); + DONE("Router: IDO ended → skip IDO"); + } + if (!window_active && !refund_mode) { + SKIP(); + DONE("Router: Window not active and not refund → skip IDO"); + } + uint8_t amount[48]; + int64_t alen = otxn_field(SBUF(amount), sfAmount); + int is_xah = (alen == 8); + if (is_xah) { + uint8_t wp_dummy[256]; + int64_t has_wp = otxn_param(SBUF(wp_dummy), "WP_LNK", 6); + if (has_wp >= 0) { + SKIP_REWARDS(); + DONE("Router: XAH + WP_LNK → run IDO"); + } + uint8_t xah_key[3] = {'X','A','H'}; + uint8_t dummy_buf[8]; + if (state(SBUF(dummy_buf), SBUF(xah_key)) == 8) { + SKIP_REWARDS(); + DONE("Router: XAH + raised exists → run IDO"); + } + SKIP(); + NOPE("Router: XAH without WP_LNK / no raised → invalid"); + } + uint8_t ns[32] = {0}; + for (i = 0; GUARD(20), i < 20; ++i) { + ns[i] = sender[i]; + } + uint8_t user_key[8] = {'I','D','O','_','D','A','T','A'}; + uint8_t user_data[16]; + int64_t has_part = state_foreign(SBUF(user_data), SBUF(user_key), SBUF(ns), SBUF(hookacc)); + if (has_part == 16) { + SKIP_REWARDS(); + DONE("Router: IOU + participation → run IDO"); + } + SKIP(); + NOPE("Router: IOU without participation → invalid"); + return 0; +} \ No newline at end of file diff --git a/IssuanceHookset/Hooks/IDOMaster.c b/IssuanceHookset/Hooks/IDOMaster.c new file mode 100644 index 0000000..ba0e3bf --- /dev/null +++ b/IssuanceHookset/Hooks/IDOMaster.c @@ -0,0 +1,771 @@ +//************************************************************** +// IDO Master Hook (IDOM) - Xahau HandyHook Collection +// Author: @Handy_4ndy +// +// Description: +// This hook manages Initial DEX Offerings (IDOs) on Xahau, enabling issuers to launch token sales +// with multiple phases, dynamic multipliers, soft caps, and refund mechanisms. Participants deposit +// XAH during active phases to receive IOU tokens at varying rates. Post-sale, users can unwind +// positions for refunds if soft cap is not met, or claim rewards via integrated rewards hook. +// Whitepaper link validation ensures user acknowledgment of terms. +// +// Hook Parameters: +// 'ADMIN' (20 bytes): Admin account ID for configuration. +// 'CURRENCY' (20 bytes): Currency code for IOU tokens to be issued. +// 'INTERVAL' (4 bytes): Ledger interval per phase (big-endian uint32). +// 'SOFT_CAP' (8 bytes): Soft cap in XAH (big-endian uint64). +// 'WP_LNK' (variable): Whitepaper/documentation link for validation. +// +// Admin Configuration Parameters (via invoke): +// 'START' (4 bytes): Ledger offset to start the IDO window (big-endian uint32). +// 'WP_LNK' (variable): Whitepaper link to store in state. +// +// User Actions: +// - Deposit XAH during active phases to receive IOU tokens. +// - Provide 'WP_LNK' parameter matching stored link for validation. +// - Unwind IOU tokens for XAH refunds during eligible periods. +// +// Phases: +// Phase 1: 100x multiplier +// Phase 2: 75x multiplier +// Phase 3: 50x multiplier +// Phase 4: 25x multiplier +// Phase 5: Cooldown/unwind period +// +// Usage: +// - Admin installs hook with parameters and invokes with 'START' to begin IDO. +// - Users send XAH payments with 'WP_LNK' during active window. +// - Hook issues IOU tokens via Remit transactions and tracks participation. +// - After window ends, evaluates soft cap; enables refunds if not met. +// - Users can unwind by sending exact IOU amount back for proportional XAH refund. +//****** + +#include "hookapi.h" + +// Define NULL if not already defined +#ifndef NULL +#define NULL 0 +#endif + +// Field codes for Remit transaction Amounts array +#define sfAmountEntry ((14U << 16U) + 91U) // 0xE0 0x5B +#define sfAmounts ((15U << 16U) + 92U) // 0xF0 0x5C + +// Utility macros +#define DONE(x) accept(SBUF(x), __LINE__) +#define NOPE(x) rollback(SBUF(x), __LINE__) +#define GUARD(maxiter) _g(__LINE__, (maxiter) + 1) + +// Convert 8-byte buffer to uint64 (big-endian) +#define UINT64_FROM_BUF(buf) \ + (((uint64_t)(buf)[0] << 56) + ((uint64_t)(buf)[1] << 48) + \ + ((uint64_t)(buf)[2] << 40) + ((uint64_t)(buf)[3] << 32) + \ + ((uint64_t)(buf)[4] << 24) + ((uint64_t)(buf)[5] << 16) + \ + ((uint64_t)(buf)[6] << 8) + (uint64_t)(buf)[7]) + +// Base Remit transaction template (229 bytes) +// clang-format off +uint8_t txn[350] = +{ +/* size,upto */ +/* 3, 0 */ 0x12U, 0x00U, 0x5FU, /* ttREMIT */ +/* 5, 3 */ 0x22U, 0x80U, 0x00U, 0x00U, 0x00U, /* Flags */ +/* 5, 8 */ 0x24U, 0x00U, 0x00U, 0x00U, 0x00U, /* Sequence */ +/* 6, 13 */ 0x20U, 0x1AU, 0x00U, 0x00U, 0x00U, 0x00U, /* FirstLedgerSequence */ +/* 6, 19 */ 0x20U, 0x1BU, 0x00U, 0x00U, 0x00U, 0x00U, /* LastLedgerSequence */ +/* 9, 25 */ 0x68U, 0x40U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, /* Fee */ +/* 35, 34 */ 0x73U, 0x21U, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* SigningPubKey */ +/* 22, 69 */ 0x81U, 0x14U, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* Account */ +/* 22, 91 */ 0x83U, 0x14U, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* Destination */ +/* 116, 113 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* EmitDetails */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +/* 0, 229 */ /* Amounts array appended here */ +}; +// clang-format on + +#define BASE_SIZE 229U +#define FLS_OUT (txn + 15U) +#define LLS_OUT (txn + 21U) +#define FEE_OUT (txn + 26U) +#define HOOK_ACC (txn + 71U) +#define DEST_ACC (txn + 93U) +#define EMIT_OUT (txn + 113U) +#define AMOUNTS_OUT (txn + 229U) + +int64_t hook(uint32_t reserved) { + + // TRACESTR("IDO :: Initial Dex Offering :: Called"); + + // Get hook account (always needed) + uint8_t hook_acc[20]; + if (hook_account(SBUF(hook_acc)) != 20) + rollback(SBUF("IDO :: Error :: Failed to get hook account."), __LINE__); + + // Get transaction type immediately for fast branching + int64_t tt = otxn_type(); + + // ======================================================================== + // INVOKE PATH: Set the sale window + // ======================================================================== + if (tt == ttINVOKE) { + // Get originating account + uint8_t otxn_acc[20]; + if (otxn_field(SBUF(otxn_acc), sfAccount) != 20) + rollback(SBUF("IDO :: Error :: Failed to get origin account."), __LINE__); + + // Check authorization (load admin only when needed) + if (!BUFFER_EQUAL_20(otxn_acc, hook_acc)) { + uint8_t admin_acc[20]; + if (hook_param(SBUF(admin_acc), "ADMIN", 5) != 20) + rollback(SBUF("IDO :: Error :: ADMIN parameter not set."), __LINE__); + if (!BUFFER_EQUAL_20(otxn_acc, admin_acc)) + rollback(SBUF("IDO :: Error :: Unauthorized invoke."), __LINE__); + } + + // Check if window already started (one-shot) + uint8_t start_key[5] = {'S', 'T', 'A', 'R', 'T'}; + uint8_t existing_start_buf[4]; + if (state(SBUF(existing_start_buf), SBUF(start_key)) == 4) { + uint32_t existing_start = UINT32_FROM_BUF(existing_start_buf); + int64_t current_ledger = ledger_seq(); + if ((uint32_t)current_ledger >= existing_start) + rollback(SBUF("IDO :: Error :: Window has already started, cannot restart."), __LINE__); + } + + // Validate WP_LNK parameter exists + uint8_t wp_buf[256]; + int64_t wp_len = hook_param(SBUF(wp_buf), "WP_LNK", 6); + if (wp_len < 1) + rollback(SBUF("IDO :: Error :: WP_LNK parameter not set."), __LINE__); + + // Validate INTERVAL parameter + uint8_t interval_key[8] = {'I','N','T','E','R','V','A','L'}; + uint8_t interval_buf[4]; + if (hook_param(SBUF(interval_buf), SBUF(interval_key)) != 4) + rollback(SBUF("IDO :: Error :: INTERVAL not set on install."), __LINE__); + uint32_t interval_offset = UINT32_FROM_BUF(interval_buf); + + // Validate START parameter + uint8_t start_buf[4]; + int64_t start_len = otxn_param(SBUF(start_buf), SBUF(start_key)); + if (start_len != 4) + rollback(SBUF("IDO :: Error :: Invalid START parameter."), __LINE__); + uint32_t start_offset = UINT32_FROM_BUF(start_buf); + + // Calculate window ledgers + int64_t current_ledger = ledger_seq(); + uint32_t current_ledger_u = (uint32_t)current_ledger; + // TRACE_num(SBUF("Current ledger at invoke = "), (uint64_t)current_ledger_u); + + uint32_t start_ledger = current_ledger_u + start_offset; + uint32_t end_ledger = start_ledger + 5 * interval_offset; + + // TRACESTR("IDO :: Setting window"); + // TRACE_num(SBUF("START offset = "), (uint64_t)start_offset); + // TRACE_num(SBUF("INTERVAL offset (per phase) = "), (uint64_t)interval_offset); + // TRACE_num(SBUF("Calculated start ledger = "), (uint64_t)start_ledger); + // TRACE_num(SBUF("Calculated end ledger = "), (uint64_t)end_ledger); + + // Store WP_LNK + uint8_t wp_lnk_key[6] = {'W', 'P', '_', 'L', 'N', 'K'}; + if (state_set(wp_buf, wp_len, wp_lnk_key, 6) < 0) + rollback(SBUF("IDO :: Error :: Failed to store WP_LNK in state."), __LINE__); + + // Store window ledgers + uint8_t start_state[4]; + UINT32_TO_BUF(start_state, start_ledger); + uint8_t end_state[4]; + UINT32_TO_BUF(end_state, end_ledger); + uint8_t end_key[3] = {'E', 'N', 'D'}; + if (state_set(start_state, 4, start_key, 5) < 0 || + state_set(interval_buf, 4, interval_key, 8) < 0 || + state_set(end_state, 4, end_key, 3) < 0) + rollback(SBUF("IDO :: Error :: Failed to set state."), __LINE__); + + // Store soft cap + uint8_t soft_cap_buf[8]; + if (hook_param(SBUF(soft_cap_buf), "SOFT_CAP", 8) != 8) + rollback(SBUF("IDO :: Error :: SOFT_CAP parameter not set."), __LINE__); + uint8_t soft_cap_key[8] = {'S', 'O', 'F', 'T', '_', 'C', 'A', 'P'}; + if (state_set(SBUF(soft_cap_buf), soft_cap_key, 8) < 0) + rollback(SBUF("IDO :: Error :: Failed to store SOFT_CAP in state."), __LINE__); + + accept(SBUF("IDO :: Success :: Window set."), __LINE__); + } + + // ======================================================================== + // PAYMENT PATH: Handle deposits and unwinds + // ======================================================================== + + // Get origin account + uint8_t otxn_acc[20]; + if (otxn_field(SBUF(otxn_acc), sfAccount) != 20) + rollback(SBUF("IDO :: Error :: Failed to get origin account."), __LINE__); + + // Read amount field ONCE to determine payment type + uint8_t amount_buffer[48]; + int64_t amount_len = otxn_field(SBUF(amount_buffer), sfAmount); + + // Handle outgoing payments from hook + if (BUFFER_EQUAL_20(hook_acc, otxn_acc)) { + if (amount_len == 48) { + // Outgoing IOU payment - accept + accept(SBUF("IDO :: Accepted :: Outgoing IOU payment."), __LINE__); + } else if (amount_len == 8) { + // Outgoing XAH payment - check balance protection + // Get account balance + uint8_t acct_kl[34]; + util_keylet(SBUF(acct_kl), KEYLET_ACCOUNT, SBUF(hook_acc), 0, 0, 0, 0); + if (slot_set(SBUF(acct_kl), 1) != 1) + rollback(SBUF("IDO :: Error :: Could not load account keylet."), __LINE__); + if (slot_subfield(1, sfBalance, 1) != 1) + rollback(SBUF("IDO :: Error :: Could not load sfBalance."), __LINE__); + int64_t balance_xfl = slot_float(1); + int64_t balance_drops = float_int(balance_xfl, 6, 0); + + // Get outgoing amount + int64_t outgoing_drops = AMOUNT_TO_DROPS(amount_buffer); + + // Get locked balance + uint8_t xah_key[3] = {'X', 'A', 'H'}; + uint8_t xah_buf[8]; + uint64_t total_xah = 0; + if (state(SBUF(xah_buf), SBUF(xah_key)) == 8) + total_xah = UINT64_FROM_BUF(xah_buf); + + // Check if we need to evaluate soft cap (in case no deposit/unwind triggered it) + uint8_t start_key[5] = {'S', 'T', 'A', 'R', 'T'}; + uint8_t interval_key[8] = {'I','N','T','E','R','V','A','L'}; + uint8_t start_buf[4]; + uint8_t interval_buf[4]; + if (state(SBUF(start_buf), SBUF(start_key)) == 4 && + state(SBUF(interval_buf), SBUF(interval_key)) == 4) { + uint32_t start_ledger = UINT32_FROM_BUF(start_buf); + uint32_t interval_offset = UINT32_FROM_BUF(interval_buf); + uint32_t phase4_end = start_ledger + (4 * interval_offset); + int64_t current_ledger = ledger_seq(); + uint32_t current_ledger_u = (uint32_t)current_ledger; + if (current_ledger_u >= phase4_end) { + uint8_t refund_key[6] = {'R', 'E', 'F', 'U', 'N', 'D'}; + uint8_t refund_flag[1]; + int64_t refund_check = state(SBUF(refund_flag), SBUF(refund_key)); + if (refund_check < 0) { + // Evaluate soft cap + uint8_t soft_cap_buf[8]; + if (hook_param(SBUF(soft_cap_buf), "SOFT_CAP", 8) == 8) { + uint64_t soft_cap_xah = UINT64_FROM_BUF(soft_cap_buf); + uint8_t total_xah_buf[8]; + uint64_t total_xah_eval = 0; + if (state(SBUF(total_xah_buf), SBUF(xah_key)) == 8) + total_xah_eval = UINT64_FROM_BUF(total_xah_buf); + if (total_xah_eval >= soft_cap_xah) { + uint8_t refund_inactive[1] = {0}; + state_set(SBUF(refund_inactive), SBUF(refund_key)); + uint8_t total_raised_key[12] = {'T', 'O', 'T', 'A', 'L', '_', 'R', 'A', 'I', 'S', 'E', 'D'}; + state_set(SBUF(total_xah_buf), SBUF(total_raised_key)); + } else { + uint8_t refund_active[1] = {1}; + state_set(SBUF(refund_active), SBUF(refund_key)); + } + } + } + } + } + + uint64_t locked_drops = total_xah * 1000000ULL; + + // Check if sale is over and soft cap met (locked balance should be zero) + uint8_t refund_key[6] = {'R', 'E', 'F', 'U', 'N', 'D'}; + uint8_t refund_flag[1]; + int64_t refund_mode = state(SBUF(refund_flag), SBUF(refund_key)); + // refund_mode == 1 && refund_flag[0] == 0 means sale successful, not refund mode + uint8_t end_key[3] = {'E', 'N', 'D'}; + uint8_t end_buf[4]; + int sale_over = 0; + if (state(SBUF(end_buf), SBUF(end_key)) == 4) { + uint32_t end_ledger = UINT32_FROM_BUF(end_buf); + int64_t current_ledger = ledger_seq(); + uint32_t current_ledger_u = (uint32_t)current_ledger; + if (current_ledger_u >= end_ledger) + sale_over = 1; + } + + if (sale_over && refund_mode == 1 && refund_flag[0] == 0) { + // Sale successful, all funds unlocked + locked_drops = 0; + // Ensure XAH state is set to zero for future checks + if (total_xah != 0) { + uint8_t zero_buf[8] = {0}; + state_set(SBUF(zero_buf), SBUF(xah_key)); + } + } + + // Check if sufficient unlocked balance + if (balance_drops - locked_drops >= outgoing_drops) { + accept(SBUF("IDO :: Accepted :: Outgoing XAH payment."), __LINE__); + } else { + rollback(SBUF("IDO :: Rejected :: Insufficient unlocked balance."), __LINE__); + } + } else { + // Other amount types - accept + accept(SBUF("IDO :: Accepted :: Outgoing payment."), __LINE__); + } + } + + // ======================================================================== + // IOU PAYMENT PATH: Unwind (return IOU for XAH) + // ======================================================================== + if (amount_len == 48) { + // TRACESTR("IDO :: Checking unwind"); + + // Validate issuer (offset 28 in amount) + if (!BUFFER_EQUAL_20(amount_buffer + 28, hook_acc)) + rollback(SBUF("IDO :: Unwind :: Wrong issuer."), __LINE__); + + // Get IOU amount + int64_t iou_xfl = -INT64_FROM_BUF(amount_buffer); + int64_t iou_amount = float_int(iou_xfl, 0, 1); + // TRACEVAR(iou_amount); + + // Get user namespace + uint8_t user_namespace[32]; + for (int i = 0; GUARD(20), i < 20; ++i) + user_namespace[i] = otxn_acc[i]; + for (int i = 20; GUARD(32), i < 32; ++i) + user_namespace[i] = 0; + + // Get user participation data + uint8_t ido_data_key[8] = {'I', 'D', 'O', '_', 'D', 'A', 'T', 'A'}; + uint8_t user_data[16]; + state_foreign(SBUF(user_data), ido_data_key, 8, user_namespace, 32, hook_acc, 20); + + uint64_t user_total_xah = UINT64_FROM_BUF(user_data); + uint64_t user_total_iou = UINT64_FROM_BUF(user_data + 8); + // TRACEVAR(user_total_xah); + // TRACEVAR(user_total_iou); + + // Ensure soft cap evaluation has occurred + uint8_t start_key[5] = {'S', 'T', 'A', 'R', 'T'}; + uint8_t interval_key[8] = {'I','N','T','E','R','V','A','L'}; + uint8_t start_buf[4]; + uint8_t interval_buf[4]; + if (state(SBUF(start_buf), SBUF(start_key)) == 4 && + state(SBUF(interval_buf), SBUF(interval_key)) == 4) { + uint32_t start_ledger = UINT32_FROM_BUF(start_buf); + uint32_t interval_offset = UINT32_FROM_BUF(interval_buf); + uint32_t phase4_end = start_ledger + (4 * interval_offset); + int64_t current_ledger = ledger_seq(); + uint32_t current_ledger_u = (uint32_t)current_ledger; + if (current_ledger_u >= phase4_end) { + uint8_t refund_key[6] = {'R', 'E', 'F', 'U', 'N', 'D'}; + uint8_t refund_flag[1]; + int64_t refund_check = state(SBUF(refund_flag), SBUF(refund_key)); + if (refund_check < 0) { + // Evaluate soft cap + uint8_t soft_cap_buf[8]; + if (hook_param(SBUF(soft_cap_buf), "SOFT_CAP", 8) == 8) { + uint64_t soft_cap_xah = UINT64_FROM_BUF(soft_cap_buf); + uint8_t xah_key[3] = {'X', 'A', 'H'}; + uint8_t total_xah_buf[8]; + uint64_t total_xah = 0; + if (state(SBUF(total_xah_buf), SBUF(xah_key)) == 8) + total_xah = UINT64_FROM_BUF(total_xah_buf); + // TRACEVAR(total_xah); + // TRACEVAR(soft_cap_xah); + if (total_xah < soft_cap_xah) { + uint8_t refund_active[1] = {1}; + state_set(SBUF(refund_active), SBUF(refund_key)); + // TRACESTR("IDO :: Soft cap NOT met. Phase 5 is now REFUND period."); + } else { + uint8_t refund_inactive[1] = {0}; + state_set(SBUF(refund_inactive), SBUF(refund_key)); + // TRACESTR("IDO :: Soft cap MET. Sale successful!"); + // Preserve total raised for records (funds unlock after cooldown period) + uint8_t total_raised_key[12] = {'T', 'O', 'T', 'A', 'L', '_', 'R', 'A', 'I', 'S', 'E', 'D'}; + state_set(SBUF(total_xah_buf), SBUF(total_raised_key)); + // TRACESTR("IDO :: Soft cap met. Funds will unlock after cooldown period."); + } + } + } + } + } + + // Check refund mode + uint8_t refund_key[6] = {'R', 'E', 'F', 'U', 'N', 'D'}; + uint8_t refund_flag[1]; + int64_t refund_mode = state(SBUF(refund_flag), SBUF(refund_key)); + int is_refund_active = (refund_mode == 1 && refund_flag[0] == 1); + + if (is_refund_active) { + // TRACESTR("IDO :: Refund mode - accepting any IOU amount for proportional refund."); + } else { + // Normal mode requires exact amount + if (iou_amount != user_total_iou) + rollback(SBUF("IDO :: Unwind :: Amount not exact to total IOU."), __LINE__); + // Check if window has ended (successful IDO, no more unwinds) + uint8_t end_key[3] = {'E', 'N', 'D'}; + uint8_t end_buf[4]; + if (state(SBUF(end_buf), SBUF(end_key)) == 4) { + uint32_t end_ledger = UINT32_FROM_BUF(end_buf); + int64_t current_ledger = ledger_seq(); + uint32_t current_ledger_u = (uint32_t)current_ledger; + if (current_ledger_u >= end_ledger) { + rollback(SBUF("IDO :: Unwind :: Sale successful and cooldown period has ended, unwind's are no longer possible."), __LINE__); + } + } + } + + // Build and emit XAH payment to user + etxn_reserve(1); + + uint8_t pay_txn[PREPARE_PAYMENT_SIMPLE_SIZE]; + uint64_t xah_drops = user_total_xah * 1000000; + PREPARE_PAYMENT_SIMPLE(pay_txn, xah_drops, otxn_acc, 0, 0); + + uint8_t emithash[32]; + if (emit(SBUF(emithash), SBUF(pay_txn)) < 0) + rollback(SBUF("IDO :: Unwind :: Emit failed."), __LINE__); + + // Update global counters + uint8_t exec_key[4] = {'E', 'X', 'E', 'C'}; + uint8_t xah_key[3] = {'X', 'A', 'H'}; + uint8_t iou_key[3] = {'I', 'O', 'U'}; + + uint8_t exec_buf[8]; + if (state(SBUF(exec_buf), SBUF(exec_key)) == 8) { + uint64_t executions = UINT64_FROM_BUF(exec_buf) - 1; + UINT64_TO_BUF(exec_buf, executions); + state_set(SBUF(exec_buf), SBUF(exec_key)); + } + + uint8_t xah_buf[8]; + if (state(SBUF(xah_buf), SBUF(xah_key)) == 8) { + uint64_t total_xah = UINT64_FROM_BUF(xah_buf) - user_total_xah; + UINT64_TO_BUF(xah_buf, total_xah); + state_set(SBUF(xah_buf), SBUF(xah_key)); + } + + uint8_t iou_buf[8]; + if (state(SBUF(iou_buf), SBUF(iou_key)) == 8) { + uint64_t total_iou = UINT64_FROM_BUF(iou_buf) - user_total_iou; + UINT64_TO_BUF(iou_buf, total_iou); + state_set(SBUF(iou_buf), SBUF(iou_key)); + } + + // Remove user data + state_foreign_set(0, 0, ido_data_key, 8, user_namespace, 32, hook_acc, 20); + + accept(SBUF("IDO :: Unwind :: XAH returned."), __LINE__); + } + + // ======================================================================== + // XAH PAYMENT PATH: Accept deposits during active phases + // ======================================================================== + + // TRACESTR("IDO :: Checking XAH deposit"); + + // Validate WP_LNK parameter + uint8_t otxn_wp_buf[256]; + int64_t otxn_wp_len = otxn_param(SBUF(otxn_wp_buf), "WP_LNK", 6); + + // Get and validate stored WP_LNK + uint8_t wp_lnk_key[6] = {'W', 'P', '_', 'L', 'N', 'K'}; + uint8_t stored_wp_buf[256]; + int64_t stored_wp_len = state(SBUF(stored_wp_buf), SBUF(wp_lnk_key)); + if (stored_wp_len < 1) + rollback(SBUF("IDO :: Error :: WP_LNK not found in state, awaiting issuer initialization."), __LINE__); + + // WP_LNK must match exactly + if (otxn_wp_len != stored_wp_len) + rollback(SBUF("IDO :: Rejected :: WP_LNK parameter does not match. Verify whitepaper link."), __LINE__); + + for (int i = 0; GUARD(256), i < otxn_wp_len; i++) { + if (otxn_wp_buf[i] != stored_wp_buf[i]) + rollback(SBUF("IDO :: Rejected :: WP_LNK parameter does not match. Verify whitepaper link."), __LINE__); + } + + // TRACESTR("IDO :: WP_LNK validated - user acknowledged documentation."); + + // Get INTERVAL offset (only read hook param once) + uint8_t interval_key[8] = {'I','N','T','E','R','V','A','L'}; + uint8_t interval_param_buf[4]; + if (hook_param(SBUF(interval_param_buf), SBUF(interval_key)) != 4) + rollback(SBUF("IDO :: Error :: INTERVAL not set."), __LINE__); + uint32_t interval_offset = UINT32_FROM_BUF(interval_param_buf); + + // Read window state + uint8_t start_key[5] = {'S', 'T', 'A', 'R', 'T'}; + uint8_t end_key[3] = {'E', 'N', 'D'}; + uint8_t start_buf[4]; + uint8_t end_buf[4]; + if (state(SBUF(start_buf), SBUF(start_key)) != 4 || + state(SBUF(end_buf), SBUF(end_key)) != 4) + rollback(SBUF("IDO :: Error :: Window not set."), __LINE__); + + uint32_t start_ledger = UINT32_FROM_BUF(start_buf); + uint32_t end_ledger = UINT32_FROM_BUF(end_buf); + int64_t current_ledger = ledger_seq(); + uint32_t current_ledger_u = (uint32_t)current_ledger; + + // Check if we're past Phase 4 (soft cap evaluation time) + uint32_t phase4_end = start_ledger + (4 * interval_offset); + + if (current_ledger_u >= phase4_end) { + uint8_t refund_key[6] = {'R', 'E', 'F', 'U', 'N', 'D'}; + uint8_t refund_flag[1]; + int64_t refund_check = state(SBUF(refund_flag), SBUF(refund_key)); + + // First time past Phase 4 - evaluate soft cap + if (refund_check < 0) { + uint8_t soft_cap_buf[8]; + if (hook_param(SBUF(soft_cap_buf), "SOFT_CAP", 8) != 8) + rollback(SBUF("IDO :: Error :: SOFT_CAP parameter not set."), __LINE__); + uint64_t soft_cap_xah = UINT64_FROM_BUF(soft_cap_buf); + + uint8_t xah_key[3] = {'X', 'A', 'H'}; + uint8_t total_xah_buf[8]; + uint64_t total_xah = 0; + if (state(SBUF(total_xah_buf), SBUF(xah_key)) == 8) + total_xah = UINT64_FROM_BUF(total_xah_buf); + + // TRACEVAR(total_xah); + // TRACEVAR(soft_cap_xah); + + if (total_xah < soft_cap_xah) { + uint8_t refund_active[1] = {1}; + state_set(SBUF(refund_active), SBUF(refund_key)); + // TRACESTR("IDO :: Soft cap NOT met. Phase 5 is now REFUND period."); + } else { + uint8_t refund_inactive[1] = {0}; + state_set(SBUF(refund_inactive), SBUF(refund_key)); + // TRACESTR("IDO :: Soft cap MET. Sale successful!"); + // Preserve total raised for records (funds unlock after cooldown period) + uint8_t total_raised_key[11] = {'T', 'O', 'T', 'A', 'L', '_', 'R', 'A', 'I', 'S', 'E', 'D'}; + state_set(SBUF(total_xah_buf), SBUF(total_raised_key)); + // TRACESTR("IDO :: Soft cap met. Funds will unlock after cooldown period."); + } + } + } + + // Check if window has ended + if (current_ledger_u >= end_ledger) { + uint8_t refund_key[6] = {'R', 'E', 'F', 'U', 'N', 'D'}; + uint8_t refund_flag[1]; + int64_t refund_mode = state(SBUF(refund_flag), SBUF(refund_key)); + + if (refund_mode == 1 && refund_flag[0] == 1) + rollback(SBUF("IDO :: Rejected :: Window ended. Soft cap not met. Send IOU to unwind for refund."), __LINE__); + rollback(SBUF("IDO :: Rejected :: Window has ended."), __LINE__); + } + + // TRACE_num(SBUF("Current ledger = "), (uint64_t)current_ledger_u); + // TRACE_num(SBUF("Start ledger = "), (uint64_t)start_ledger); + // TRACE_num(SBUF("End ledger = "), (uint64_t)end_ledger); + + // Extract received XAH amount (amount_buffer already read earlier) + int64_t received_drops = AMOUNT_TO_DROPS(amount_buffer); + int64_t received_xah = received_drops / 1000000; + // TRACEVAR(received_drops); + // TRACEVAR(received_xah); + + // Calculate phase and multiplier + uint32_t elapsed = current_ledger_u - start_ledger; + uint32_t phase = (elapsed / interval_offset) + 1; + int64_t multiplier = 0; + + if (phase == 1) { + multiplier = 100; + // TRACESTR("IDO :: Phase 1 active."); + } else if (phase == 2) { + multiplier = 75; + // TRACESTR("IDO :: Phase 2 active."); + } else if (phase == 3) { + multiplier = 50; + // TRACESTR("IDO :: Phase 3 active."); + } else if (phase == 4) { + multiplier = 25; + // TRACESTR("IDO :: Phase 4 active."); + } else if (phase == 5) { + // Phase 5: Unwinding only + // TRACESTR("IDO :: Phase 5 active (unwinding only)."); + rollback(SBUF("IDO :: Rejected :: Phase 5 is unwinding only, no new deposits."), __LINE__); + } else { + rollback(SBUF("IDO :: Rejected :: Invalid phase."), __LINE__); + } + + // TRACEVAR(phase); + + int64_t issued_amount = received_xah * multiplier; + if (issued_amount == 0) + rollback(SBUF("IDO :: Issued amount is zero."), __LINE__); + // TRACEVAR(issued_amount); + + // Update global counters + uint8_t exec_key[4] = {'E', 'X', 'E', 'C'}; + uint8_t xah_key[3] = {'X', 'A', 'H'}; + uint8_t iou_key[3] = {'I', 'O', 'U'}; + + uint8_t exec_buf[8] = {0}; + uint64_t executions = 0; + if (state(SBUF(exec_buf), SBUF(exec_key)) == 8) + executions = UINT64_FROM_BUF(exec_buf); + executions++; + UINT64_TO_BUF(exec_buf, executions); + if (state_set(SBUF(exec_buf), SBUF(exec_key)) < 0) + rollback(SBUF("IDO :: Failed to update executions counter."), __LINE__); + + uint8_t xah_buf[8] = {0}; + uint64_t total_xah = 0; + if (state(SBUF(xah_buf), SBUF(xah_key)) == 8) + total_xah = UINT64_FROM_BUF(xah_buf); + total_xah += received_xah; + UINT64_TO_BUF(xah_buf, total_xah); + if (state_set(SBUF(xah_buf), SBUF(xah_key)) < 0) + rollback(SBUF("IDO :: Failed to update XAH total."), __LINE__); + + uint8_t iou_buf[8] = {0}; + uint64_t total_iou = 0; + if (state(SBUF(iou_buf), SBUF(iou_key)) == 8) + total_iou = UINT64_FROM_BUF(iou_buf); + total_iou += issued_amount; + UINT64_TO_BUF(iou_buf, total_iou); + if (state_set(SBUF(iou_buf), SBUF(iou_key)) < 0) + rollback(SBUF("IDO :: Failed to update IOU total."), __LINE__); + + // TRACEVAR(executions); + // TRACEVAR(total_xah); + // TRACEVAR(total_iou); + + // Update phase-specific counter + uint8_t phase_key[6]; + phase_key[0] = 'P'; + phase_key[1] = 'H'; + phase_key[2] = 'A'; + phase_key[3] = 'S'; + phase_key[4] = 'E'; + phase_key[5] = '0' + (uint8_t)phase; + + uint8_t phase_buf[8] = {0}; + uint64_t phase_exec = 0; + if (state(SBUF(phase_buf), phase_key, 6) == 8) + phase_exec = UINT64_FROM_BUF(phase_buf); + phase_exec++; + UINT64_TO_BUF(phase_buf, phase_exec); + if (state_set(SBUF(phase_buf), phase_key, 6) < 0) + rollback(SBUF("IDO :: Failed to update phase executions counter."), __LINE__); + // TRACEVAR(phase_exec); + + // Record user participation data + uint8_t user_namespace[32]; + for (int i = 0; GUARD(20), i < 20; ++i) + user_namespace[i] = otxn_acc[i]; + for (int i = 20; GUARD(32), i < 32; ++i) + user_namespace[i] = 0; + + uint8_t ido_data_key[8] = {'I', 'D', 'O', '_', 'D', 'A', 'T', 'A'}; + uint8_t user_data[16] = {0}; + state_foreign(SBUF(user_data), ido_data_key, 8, user_namespace, 32, hook_acc, 20); + + uint64_t user_total_xah = UINT64_FROM_BUF(user_data); + uint64_t user_total_iou = UINT64_FROM_BUF(user_data + 8); + + user_total_xah += received_xah; + user_total_iou += issued_amount; + + UINT64_TO_BUF(user_data, user_total_xah); + UINT64_TO_BUF(user_data + 8, user_total_iou); + + if (state_foreign_set(user_data, 16, ido_data_key, 8, user_namespace, 32, hook_acc, 20) < 0) + rollback(SBUF("IDO :: Failed to update user data."), __LINE__); + + // Build Amounts array for Remit transaction + uint8_t* amounts_ptr = AMOUNTS_OUT; + + *amounts_ptr++ = 0xF0U; // sfAmounts array start + *amounts_ptr++ = 0x5CU; + + *amounts_ptr++ = 0xE0U; // sfAmountEntry object start + *amounts_ptr++ = 0x5BU; + + // Load currency only when needed + uint8_t currency[20]; + if (hook_param(SBUF(currency), "CURRENCY", 8) != 20) + rollback(SBUF("IDO :: Error :: CURRENCY parameter not set."), __LINE__); + + int64_t amount_xfl = float_set(0, issued_amount); + int32_t amount_len_remit = float_sto( + amounts_ptr, 49, + currency, 20, + hook_acc, 20, + amount_xfl, + sfAmount + ); + + if (amount_len_remit < 0) + rollback(SBUF("IDO :: Failed to serialize amount."), __LINE__); + + amounts_ptr += amount_len_remit; + + *amounts_ptr++ = 0xE1U; // End AmountEntry + *amounts_ptr++ = 0xF1U; // End Amounts array + + int32_t amounts_len = amounts_ptr - AMOUNTS_OUT; + + // Fill transaction fields + hook_account(HOOK_ACC, 20); + + for (int i = 0; GUARD(20), i < 20; ++i) + DEST_ACC[i] = otxn_acc[i]; + + // Prepare for emission + etxn_reserve(1); + + int32_t total_size = BASE_SIZE + amounts_len; + + etxn_details(EMIT_OUT, 116U); + + // Encode ledger sequences + int64_t seq = ledger_seq() + 1; + txn[15] = (seq >> 24U) & 0xFFU; + txn[16] = (seq >> 16U) & 0xFFU; + txn[17] = (seq >> 8U) & 0xFFU; + txn[18] = seq & 0xFFU; + + seq += 4; + txn[21] = (seq >> 24U) & 0xFFU; + txn[22] = (seq >> 16U) & 0xFFU; + txn[23] = (seq >> 8U) & 0xFFU; + txn[24] = seq & 0xFFU; + + // Calculate and encode fee + int64_t fee = etxn_fee_base(txn, total_size); + + if (fee < 0) + rollback(SBUF("IDO :: Fee calculation failed."), __LINE__); + + uint64_t fee_tmp = fee; + uint8_t* fee_ptr = (uint8_t*)&fee; + *fee_ptr++ = 0b01000000 + ((fee_tmp >> 56) & 0b00111111); + *fee_ptr++ = (fee_tmp >> 48) & 0xFFU; + *fee_ptr++ = (fee_tmp >> 40) & 0xFFU; + *fee_ptr++ = (fee_tmp >> 32) & 0xFFU; + *fee_ptr++ = (fee_tmp >> 24) & 0xFFU; + *fee_ptr++ = (fee_tmp >> 16) & 0xFFU; + *fee_ptr++ = (fee_tmp >> 8) & 0xFFU; + *fee_ptr++ = (fee_tmp >> 0) & 0xFFU; + + *((uint64_t*)(txn + 26)) = fee; + + // Emit transaction + uint8_t emithash[32]; + int64_t emit_result = emit(SBUF(emithash), txn, total_size); + + if (emit_result < 0) + rollback(SBUF("IDO :: Emit failed."), __LINE__); + + accept(SBUF("IDO :: Accepted :: Incoming payment during active phase."), __LINE__); + + _g(1,1); // Guard + return 0; +} diff --git a/IssuanceHookset/Hooks/RewardsMaster.c b/IssuanceHookset/Hooks/RewardsMaster.c new file mode 100644 index 0000000..63d8054 --- /dev/null +++ b/IssuanceHookset/Hooks/RewardsMaster.c @@ -0,0 +1,389 @@ +//************************************************************** +// Issuance Rewards Hook (IRH) - Xahau HandyHook Collection +// Author: @Handy_4ndy +// +// Description: +// This hook enables IOU holders to claim rewards on their holdings after issuance completion. +// Interest rate and claim intervals are configurable by admins via invoke transactions. +// Users can claim rewards while timing and trustline constraints are enforced. +// Integrated with issuance hook for post-completion rewards distribution. +// +// Hook Parameters: +// 'CURRENCY' (20 bytes): Currency code to be distributed as daily rewards. +// 'ADMIN' (20 bytes): Admin account ID for configuration. +// 'INT_RATE' (4 bytes): Set daily interest rate (big-endian uint32, e.g., 1000 = 10%). +// 'SET_INTERVAL' (4 bytes): Set claim interval in ledgers (big-endian uint32). +// 'SET_MAX_CLAIMS' (4 bytes): Set lifetime claim limit per user (big-endian uint32). (Optional) +// +// Admin Configuration Parameters (can be set at install or via invoke): +// 'INT_RATE' (4 bytes): Set daily interest rate (big-endian uint32, e.g., 1000 = 10%). +// 'SET_INTERVAL' (4 bytes): Set claim interval in ledgers (big-endian uint32). +// 'SET_MAX_CLAIMS' (4 bytes): Set lifetime claim limit per user (big-endian uint32). +// +// User Claim Parameters: +// 'R_CLAIM' (20 bytes): Claim daily rewards (claimant account ID). +// +// Usage: +// - Admin configures interest rate with 'INT_RATE', intervals, and limits at install or via invoke transactions. + - After issuance completion, IOU holders send invoke transactions with 'R_CLAIM' to claim rewards. + - Hook validates issuance status, timing constraints, trustlines, and calculates rewards based on holdings. +// - User state tracked in hierarchical namespaces for unlimited scalability. +//************************************************************** + +#include "hookapi.h" + +// Field codes for Remit transaction Amounts array +#define sfAmountEntry ((14U << 16U) + 91U) // 0xE0 0x5B +#define sfAmounts ((15U << 16U) + 92U) // 0xF0 0x5C + +#define FLIP_ENDIAN(n) ((uint32_t) (((n & 0xFFU) << 24U) | \ + ((n & 0xFF00U) << 8U) | \ + ((n & 0xFF0000U) >> 8U) | \ + ((n & 0xFF000000U) >> 24U))) + +#define DONE(x) accept(SBUF("IRH :: Success :: " x), __LINE__) +#define NOPE(x) rollback(SBUF("IRH :: Error :: " x), __LINE__) +#define GUARD(maxiter) _g(__LINE__, (maxiter) + 1) + +#define UINT64_FROM_BUF(buf) \ + (((uint64_t)(buf)[0] << 56) + ((uint64_t)(buf)[1] << 48) + \ + ((uint64_t)(buf)[2] << 40) + ((uint64_t)(buf)[3] << 32) + \ + ((uint64_t)(buf)[4] << 24) + ((uint64_t)(buf)[5] << 16) + \ + ((uint64_t)(buf)[6] << 8) + (uint64_t)(buf)[7]) + + +// Base Remit transaction template (229 bytes) +// clang-format off +uint8_t txn[350] = +{ +/* size,upto */ +/* 3, 0 */ 0x12U, 0x00U, 0x5FU, /* ttREMIT */ +/* 5, 3 */ 0x22U, 0x80U, 0x00U, 0x00U, 0x00U, /* Flags */ +/* 5, 8 */ 0x24U, 0x00U, 0x00U, 0x00U, 0x00U, /* Sequence */ +/* 6, 13 */ 0x20U, 0x1AU, 0x00U, 0x00U, 0x00U, 0x00U, /* FirstLedgerSequence */ +/* 6, 19 */ 0x20U, 0x1BU, 0x00U, 0x00U, 0x00U, 0x00U, /* LastLedgerSequence */ +/* 9, 25 */ 0x68U, 0x40U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, /* Fee */ +/* 35, 34 */ 0x73U, 0x21U, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* SigningPubKey */ +/* 22, 69 */ 0x81U, 0x14U, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* Account */ +/* 22, 91 */ 0x83U, 0x14U, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* Destination */ +/* 116, 113 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* EmitDetails */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +/* 0, 229 */ /* Amounts array appended here */ +}; +// clang-format on + +#define BASE_SIZE 229U +#define FLS_OUT (txn + 15U) +#define LLS_OUT (txn + 21U) +#define FEE_OUT (txn + 26U) +#define HOOK_ACC (txn + 71U) +#define DEST_ACC (txn + 93U) +#define EMIT_OUT (txn + 113U) +#define AMOUNTS_OUT (txn + 229U) + +int64_t hook(uint32_t reserved) { + + TRACESTR("IRH :: Issuance Rewards Hook :: Called."); + + // Only process ttINVOKE transactions (type 99) + if (otxn_type() != 99) + DONE("Non-INVOKE transaction passed through."); + + // Get accounts first for validation + uint8_t hook_acc[20]; + if (hook_account(SBUF(hook_acc)) != 20) + NOPE("Failed to get hook account."); + + uint8_t otxn_acc[20]; + if (otxn_field(SBUF(otxn_acc), sfAccount) != 20) + NOPE("Failed to get origin account."); + + // Ignore outgoing transactions (hook account invoking itself) + if (BUFFER_EQUAL_20(hook_acc, otxn_acc)) + DONE("Outgoing invoke transaction passed through."); + + uint8_t currency[20]; + if(hook_param(SBUF(currency), "CURRENCY", 8) != 20) + NOPE("Misconfigured. CURRENCY not set as Hook Parameter."); + + uint8_t invoke_acc[20]; + if(hook_param(SBUF(invoke_acc), "ADMIN", 5) != 20) + NOPE("Misconfigured. ADMIN not set as Hook Parameter."); + + // State keys for configuration + uint8_t interest_rate_key[8] = "INT_RATE"; + uint8_t interval_key[8] = "CLAIM_INT"; + uint8_t max_claims_key[8] = "MAX_CLM\0"; + + // Optional install-time configuration parameters + uint8_t install_int_rate[4]; + if(hook_param(SBUF(install_int_rate), "INT_RATE", 8) == 4) { + if(state_set(SBUF(install_int_rate), SBUF(interest_rate_key)) != 4) + NOPE("Failed to set install-time interest rate."); + } + + uint8_t install_interval[4]; + if(hook_param(SBUF(install_interval), "SET_INTERVAL", 12) == 4) { + if(state_set(SBUF(install_interval), SBUF(interval_key)) != 4) + NOPE("Failed to set install-time claim interval."); + } + + uint8_t install_max_claims[4]; + if(hook_param(SBUF(install_max_claims), "SET_MAX_CLAIMS", 14) == 4) { + if(state_set(SBUF(install_max_claims), SBUF(max_claims_key)) != 4) + NOPE("Failed to set install-time max claims."); + } + + // Check transaction type - admin configuration, admin issuance, or daily claim + if (BUFFER_EQUAL_20(otxn_acc, invoke_acc)) { + // ADMIN COMMANDS - from whitelisted account only + + // Check for configuration commands first + uint8_t set_interest_param[4]; + if(otxn_param(SBUF(set_interest_param), "INT_RATE", 8) == 4) { + // Set daily interest rate + if(state_set(SBUF(set_interest_param), SBUF(interest_rate_key)) != 4) + NOPE("Failed to set interest rate."); + DONE("Interest rate configured successfully."); + } + + uint8_t set_interval_param[4]; + if(otxn_param(SBUF(set_interval_param), "SET_INTERVAL", 12) == 4) { + // Set claim interval + if(state_set(SBUF(set_interval_param), SBUF(interval_key)) != 4) + NOPE("Failed to set claim interval."); + DONE("Claim interval configured successfully."); + } + + uint8_t set_max_claims_param[4]; + if(otxn_param(SBUF(set_max_claims_param), "SET_MAX_CLAIMS", 14) == 4) { + // Set max claims limit + if(state_set(SBUF(set_max_claims_param), SBUF(max_claims_key)) != 4) + NOPE("Failed to set max claims limit."); + DONE("Max claims limit configured successfully."); + } + + // No valid admin configuration parameters provided + DONE("Admin configuration: No valid parameters provided."); + + } else { + // Check for daily claim parameter + uint8_t claim_param[20]; + if(otxn_param(SBUF(claim_param), "R_CLAIM", 7) == 20) { + // DAILY CLAIM PATH - from any non-whitelisted account + + // Load daily interest rate configuration from state + uint8_t interest_rate_buf[8]; + if(state(SBUF(interest_rate_buf), SBUF(interest_rate_key)) != 8) + NOPE("INT_RATE not configured - admin must use SET_INTEREST_RATE first."); + + uint64_t interest_rate = UINT64_FROM_BUF(interest_rate_buf); + if (interest_rate == 0) + NOPE("Invalid interest rate - must be positive."); + + // Load claim interval (required configuration) + uint8_t interval_buf[4]; + if(state(SBUF(interval_buf), SBUF(interval_key)) != 4) + NOPE("SET_INTERVAL not configured - admin must set claim interval first."); + + uint32_t claim_interval = (uint32_t)((interval_buf[0] << 24) | (interval_buf[1] << 16) | + (interval_buf[2] << 8) | interval_buf[3]); + + // Load max claims limit (default unlimited if not set) + uint32_t max_claims = 0; // Default unlimited + uint8_t max_claims_buf[4]; + if(state(SBUF(max_claims_buf), SBUF(max_claims_key)) == 4) { + max_claims = (uint32_t)((max_claims_buf[0] << 24) | (max_claims_buf[1] << 16) | + (max_claims_buf[2] << 8) | max_claims_buf[3]); + } + + // CRITICAL: Check trustline exists for claimant account BEFORE any processing + uint8_t keylet[34]; + if (util_keylet(SBUF(keylet), KEYLET_LINE, SBUF(hook_acc), SBUF(otxn_acc), SBUF(currency)) != 34) + NOPE("Could not generate trustline keylet."); + + if (slot_set(SBUF(keylet), 1) != 1) + NOPE("Claimant account does not have required trustline."); + + // Get user's IOU balance for calculation + if (slot_subfield(1, sfBalance, 1) != 1) + NOPE("Could not load trustline balance."); + + int64_t balance_xfl = slot_float(1); + + // Take absolute value for rewards calculation + if (float_compare(balance_xfl, float_set(0, 0), COMPARE_LESS) == 1) + balance_xfl = float_negate(balance_xfl); + + // Calculate claim amount: balance * interest_rate / 10000 (for percentage) + int64_t rate_xfl = float_set(0, interest_rate); + int64_t percent_xfl = float_set(0, 10000); // 100.00% + int64_t rate_fraction = float_divide(rate_xfl, percent_xfl); + if (rate_fraction < 0) + NOPE("Invalid rate calculation."); + + int64_t claim_amount_xfl = float_multiply(balance_xfl, rate_fraction); + if (claim_amount_xfl < 0) + NOPE("Invalid claim amount calculation."); + + // Generate user-specific namespace from their account ID + uint8_t user_namespace[32]; + // Copy user account ID to first 20 bytes + for (int i = 0; GUARD(20), i < 20; ++i) + user_namespace[i] = otxn_acc[i]; + // Pad remaining 12 bytes with zeros + for (int i = 20; GUARD(32), i < 32; ++i) + user_namespace[i] = 0; + + // Check for issuance participation bonus + uint8_t ido_data_key[8] = {'I', 'D', 'O', '_', 'D', 'A', 'T', 'A'}; + uint8_t ido_user_data[16] = {0}; + int64_t ido_result = state_foreign(SBUF(ido_user_data), SBUF(ido_data_key), SBUF(user_namespace), SBUF(hook_acc)); + if (ido_result == 16) { + uint64_t user_total_iou = UINT64_FROM_BUF(ido_user_data + 8); + if (user_total_iou > 0) { + // Issuance participant bonus: recalculate with +5% interest + uint64_t bonus_rate = interest_rate + 500; + int64_t bonus_rate_xfl = float_set(0, bonus_rate); + int64_t bonus_rate_fraction = float_divide(bonus_rate_xfl, percent_xfl); + if (bonus_rate_fraction >= 0) { + claim_amount_xfl = float_multiply(balance_xfl, bonus_rate_fraction); + } + } + } + + // Simple state key for claim data + uint8_t claim_key[32] = "CLAIM_DATA"; + // Pad remainder with zeros + for (int i = 10; GUARD(32), i < 32; ++i) + claim_key[i] = 0; + + // Load user claim state from user-specific namespace on hook account + uint8_t user_state[8] = {0}; // {last_claim_ledger:4, total_claims:4} + int64_t state_result = state_foreign(SBUF(user_state), SBUF(claim_key), + SBUF(user_namespace), SBUF(hook_acc)); + + uint32_t current_ledger = (uint32_t)ledger_seq(); + uint32_t last_claim_ledger = 0; + uint32_t total_claims = 0; + + if (state_result == 8) { + // Existing user - parse state + last_claim_ledger = (uint32_t)((user_state[0] << 24) | (user_state[1] << 16) | + (user_state[2] << 8) | user_state[3]); + total_claims = (uint32_t)((user_state[4] << 24) | (user_state[5] << 16) | + (user_state[6] << 8) | user_state[7]); + } + + // Check timing constraint + if (last_claim_ledger > 0) { + uint32_t ledgers_elapsed = current_ledger - last_claim_ledger; + if (ledgers_elapsed < claim_interval) { + NOPE("Too soon - wait more ledgers before next claim."); + } + } + + // Check lifetime claim limit + if (max_claims > 0 && total_claims >= max_claims) + NOPE("Maximum lifetime claims reached."); + + // Set hook account and claimant as destination + hook_account(HOOK_ACC, 20); + for (int i = 0; GUARD(20), i < 20; ++i) + DEST_ACC[i] = otxn_acc[i]; + + // Build main claim transaction + // Build Amounts array for Remit transaction + uint8_t* amounts_ptr = AMOUNTS_OUT; + + *amounts_ptr++ = 0xF0U; // sfAmounts array start + *amounts_ptr++ = 0x5CU; + + *amounts_ptr++ = 0xE0U; // sfAmountEntry object start + *amounts_ptr++ = 0x5BU; + + int32_t amount_len = float_sto( + amounts_ptr, 49, + currency, 20, + HOOK_ACC, 20, + claim_amount_xfl, + sfAmount + ); + + if (amount_len < 0) + NOPE("Failed to serialize claim amount."); + + amounts_ptr += amount_len; + + *amounts_ptr++ = 0xE1U; // End AmountEntry + *amounts_ptr++ = 0xF1U; // End Amounts array + + int32_t amounts_len = amounts_ptr - AMOUNTS_OUT; + + etxn_reserve(1); // Reserve space for claim + int32_t total_size = BASE_SIZE + amounts_len; + + // Encode ledger sequences + int64_t seq = current_ledger + 1; + txn[15] = (seq >> 24U) & 0xFFU; + txn[16] = (seq >> 16U) & 0xFFU; + txn[17] = (seq >> 8U) & 0xFFU; + txn[18] = seq & 0xFFU; + + seq += 4; + txn[21] = (seq >> 24U) & 0xFFU; + txn[22] = (seq >> 16U) & 0xFFU; + txn[23] = (seq >> 8U) & 0xFFU; + txn[24] = seq & 0xFFU; + + etxn_details(EMIT_OUT, 116U); + int64_t fee = etxn_fee_base(txn, total_size); + { + uint8_t *b = FEE_OUT; + *b++ = 0b01000000 + ((fee >> 56) & 0b00111111); + *b++ = (fee >> 48) & 0xFFU; + *b++ = (fee >> 40) & 0xFFU; + *b++ = (fee >> 32) & 0xFFU; + *b++ = (fee >> 24) & 0xFFU; + *b++ = (fee >> 16) & 0xFFU; + *b++ = (fee >> 8) & 0xFFU; + *b++ = (fee >> 0) & 0xFFU; + } + + // Emit main claim transaction + uint8_t claim_emithash[32]; + if(emit(SBUF(claim_emithash), txn, total_size) < 0) + NOPE("Failed to emit claim transaction."); + + // Update user state + uint8_t new_state[8]; + new_state[0] = (current_ledger >> 24) & 0xFF; + new_state[1] = (current_ledger >> 16) & 0xFF; + new_state[2] = (current_ledger >> 8) & 0xFF; + new_state[3] = current_ledger & 0xFF; + + uint32_t new_total_claims = total_claims + 1; + new_state[4] = (new_total_claims >> 24) & 0xFF; + new_state[5] = (new_total_claims >> 16) & 0xFF; + new_state[6] = (new_total_claims >> 8) & 0xFF; + new_state[7] = new_total_claims & 0xFF; + + if(state_foreign_set(SBUF(new_state), SBUF(claim_key), + SBUF(user_namespace), SBUF(hook_acc)) != 8) + NOPE("Failed to update user state."); + + // Note: User state stored in hierarchical namespace derived from account ID + // This provides unlimited scalability without namespace congestion + + DONE("Tokens claimed successfully."); + + } else { + // Not admin issuance and no R_CLAIM parameter - pass through + DONE("Invoke from non-whitelisted account passed through."); + } + } + + _g(1,1); + return 0; +} \ No newline at end of file diff --git a/IssuanceHookset/Hooks/RouterMaster.c b/IssuanceHookset/Hooks/RouterMaster.c new file mode 100644 index 0000000..f4ba200 --- /dev/null +++ b/IssuanceHookset/Hooks/RouterMaster.c @@ -0,0 +1,238 @@ +//************************************************************** +// IDO Router Hook - Xahau HandyHook Collection +// Author: @Handy_4ndy +// +// Description: +// This hook acts as a router for IDO and rewards hooks in a hook chain. +// It determines whether to execute the IDO hook or the rewards hook based on transaction type, +// payment details, window status, and refund modes. Hardcoded hashes and namespace ensure +// compatibility with specific IDO and rewards implementations. +// +// Hardcoded Configuration: +// IDO_HOOK_HASH: Hash of the IDO hook to skip/execute. +// REWARDS_HOOK_HASH: Hash of the rewards hook to skip/execute. +// IDO_NAMESPACE: Namespace for IDO state data. +// +// Parameters (Previously Dynamic, Now Hardcoded): +// IDO_HASH (32 bytes): Hash of the IDO hook (hardcoded). +// REWARDS_HASH (32 bytes): Hash of the rewards hook (hardcoded). +// NAMESPACE (32 bytes): Namespace for IDO data (hardcoded). +// +// Usage: +// - Install as the first hook in a chain with IDO and rewards hooks. +// - For outgoing transactions: Routes based on payment type (XAH skips rewards, IOU skips IDO). +// - For incoming invokes: Allows START param (runs IDO), rewards admin params (runs rewards), or R_CLAIM (runs rewards). +// - For incoming payments: Checks IDO window, refund mode, XAH/IOU type, and participation to decide execution. +// - Skips hooks appropriately to ensure only relevant logic runs. +// +// Accepts: +// - Outgoing payments and invokes. +// - Incoming invokes with START, rewards params, or R_CLAIM. +// - Incoming XAH payments with WP_LNK or raised funds during active IDO. +// - Incoming IOU payments from participants during active IDO or refund mode. +// - Incoming IOU payments for unwinding during any phase. +// +// Rejects: +// - Incoming payments outside active window (unless refund mode). +// - XAH deposits without WP_LNK acknowledgment or raised funds. +// - IOU deposits without participation data. +// - Invalid invokes without required parameters. +//************************************************************** + +#include "hookapi.h" + +#define UINT32_FROM_BUF(buf) \ + (((uint32_t)(buf)[0] << 24) + ((uint32_t)(buf)[1] << 16) + \ + ((uint32_t)(buf)[2] << 8) + (uint32_t)(buf)[3]) + +// IDO hook hash +uint8_t IDO_HOOK_HASH[32] = {0x33,0x09,0x61,0xA6,0x81,0x1A,0x03,0x13,0x1B,0x59,0x0D,0x0C,0x69,0x21,0x14,0x47,0xE7,0x8D,0xF7,0x20,0x88,0x98,0xA4,0x4F,0x8C,0xC1,0xE1,0x3C,0x62,0x9F,0x2D,0x2D}; + +// Rewards hook hash +uint8_t REWARDS_HOOK_HASH[32] = {0x8C,0xFC,0x9A,0xA6,0xAA,0x4A,0x85,0x8D,0xEF,0x04,0xD3,0x04,0x9D,0x4E,0x7D,0x22,0xA3,0x7F,0x96,0x8D,0x05,0x06,0x34,0x24,0x4E,0xC5,0xDA,0xCE,0xCC,0xE6,0x16,0x0D}; + +// namespace for the IDO hook data +uint8_t IDO_NAMESPACE[32] = {0x51,0x6B,0xA7,0x92,0x15,0x00,0x22,0x76,0xEF,0x4C,0x38,0x1B,0x90,0x19,0x55,0xC5,0x3A,0x04,0x57,0x55,0x89,0x60,0x7E,0x7D,0xBA,0x20,0x46,0x8D,0xD3,0x43,0xDD,0x72}; + + +#define DONE(msg) accept(SBUF(msg), __LINE__) +#define NOPE(msg) rollback(SBUF(msg), __LINE__) + +#define SKIP() { \ + int64_t r = hook_skip(IDO_HOOK_HASH, 32, 0); \ + if (r < 0) NOPE("Router: Skip failed"); \ +} +#define SKIP_REWARDS() { \ + int64_t r = hook_skip(REWARDS_HOOK_HASH, 32, 0); \ + if (r < 0) NOPE("Router: Skip rewards failed"); \ +} + +#define GUARD(max) _g(__LINE__, (max) + 1) + +int64_t hook(int32_t reserved) { + + uint8_t hookacc[20]; + hook_account(SBUF(hookacc)); + + uint8_t sender[20]; + if (otxn_field(SBUF(sender), sfAccount) != 20) { + NOPE("Router: Cannot read sender account"); + } + + int outgoing = 1; + int i; + for (i = 0; GUARD(20), i < 20; ++i) { + if (sender[i] != hookacc[i]) { + outgoing = 0; + break; + } + } + + int64_t ttype = otxn_type(); + + if (outgoing) { + if (ttype == 99) { + SKIP(); + DONE("Router: Outgoing invoke → skip IDO"); + } else if (ttype == 0) { + // For outgoing payment, check if XAH + uint8_t amount[48]; + int64_t alen = otxn_field(SBUF(amount), sfAmount); + if (alen == 8) { + SKIP_REWARDS(); + DONE("Router: Outgoing XAH → run IDO"); + } else { + SKIP(); + DONE("Router: Outgoing non-XAH → skip IDO"); + } + } + } + + // Invoke: allow START param or rewards admin params + if (ttype == 99) { + uint8_t dummy[20]; + if (otxn_param(SBUF(dummy), "START", 5) == 4) { + SKIP_REWARDS(); + DONE("Router: START param → run IDO, skip rewards"); + } + // Check for rewards admin params - skip IDO for these + if (otxn_param(SBUF(dummy), "INT_RATE", 8) == 8 || + otxn_param(SBUF(dummy), "SET_INTERVAL", 12) == 4 || + otxn_param(SBUF(dummy), "SET_MAX_CLAIMS", 14) == 4) { + SKIP(); + DONE("Router: Rewards admin params → skip IDO"); + } + // Check for user claim param - skip IDO for this + if (otxn_param(SBUF(dummy), "R_CLAIM", 7) == 20) { + SKIP(); + DONE("Router: R_CLAIM param → skip IDO"); + } + SKIP(); + NOPE("Router: Invoke without START or rewards params → invalid"); + } + + // Incoming Payment + + // Get current ledger + int64_t current_ledger = ledger_seq(); + + // Query IDO window state + uint8_t start_key[5] = {'S', 'T', 'A', 'R', 'T'}; + uint8_t end_key[3] = {'E', 'N', 'D'}; + uint8_t start_buf[4]; + uint8_t end_buf[4]; + int64_t start_len = state_foreign(SBUF(start_buf), SBUF(start_key), SBUF(IDO_NAMESPACE), SBUF(hookacc)); + int64_t end_len = state_foreign(SBUF(end_buf), SBUF(end_key), SBUF(IDO_NAMESPACE), SBUF(hookacc)); + int window_set = (start_len == 4 && end_len == 4); + int window_active = 0; + if (window_set) { + uint32_t start_ledger = UINT32_FROM_BUF(start_buf); + uint32_t end_ledger = UINT32_FROM_BUF(end_buf); + uint32_t curr = (uint32_t)current_ledger; + if (curr >= start_ledger && curr < end_ledger) { + window_active = 1; + } + } + + // REFUND flag (post-phase-4) + uint8_t refund_key[6] = {'R','E','F','U','N','D'}; + uint8_t refund_flag = 0; + int64_t refund_len = state_foreign(&refund_flag, 1, SBUF(refund_key), SBUF(IDO_NAMESPACE), SBUF(hookacc)); + int refund_mode = (refund_len == 1 && refund_flag == 1); + + // If refund mode active, only allow incoming IOU payments + if (refund_mode) { + if (ttype == 99) { + NOPE("Router: Refund mode + invoke → invalid"); + } else if (ttype == 0) { + if (outgoing) { + NOPE("Router: Refund mode + outgoing → invalid"); + } + uint8_t amount[48]; + int64_t alen = otxn_field(SBUF(amount), sfAmount); + if (alen != 48) { + NOPE("Router: Refund mode + not IOU → invalid"); + } + SKIP_REWARDS(); + DONE("Router: Refund mode + incoming IOU → run IDO"); + } + } + + // Skip if IDO has ended + if (window_set && (uint32_t)current_ledger > UINT32_FROM_BUF(end_buf)) { + SKIP(); + DONE("Router: IDO ended → skip IDO"); + } + + // If window not active and not refund mode, skip + if (!window_active && !refund_mode) { + SKIP(); + DONE("Router: Window not active and not refund → skip IDO"); + } + + // Detect XAH vs IOU + uint8_t amount[48]; + int64_t alen = otxn_field(SBUF(amount), sfAmount); + int is_xah = (alen == 8); + + if (is_xah) { + uint8_t wp_dummy[256]; + int64_t has_wp = otxn_param(SBUF(wp_dummy), "WP_LNK", 6); + + if (has_wp >= 0) { + SKIP_REWARDS(); + DONE("Router: XAH + WP_LNK → run IDO"); + } + + // Permissive: if raised XAH exists + uint8_t xah_key[3] = {'X','A','H'}; + uint8_t dummy_buf[8]; + if (state(SBUF(dummy_buf), SBUF(xah_key)) == 8) { + SKIP_REWARDS(); + DONE("Router: XAH + raised exists → run IDO"); + } + + SKIP(); + NOPE("Router: XAH without WP_LNK / no raised → invalid"); + } + + // IOU unwind + uint8_t ns[32] = {0}; + for (i = 0; GUARD(20), i < 20; ++i) { + ns[i] = sender[i]; + } + + uint8_t user_key[8] = {'I','D','O','_','D','A','T','A'}; + uint8_t user_data[16]; + int64_t has_part = state_foreign(SBUF(user_data), SBUF(user_key), SBUF(ns), SBUF(hookacc)); + + if (has_part == 16) { + SKIP_REWARDS(); + DONE("Router: IOU + participation → run IDO"); + } + + SKIP(); + NOPE("Router: IOU without participation → invalid"); + + return 0; +} \ No newline at end of file diff --git a/IssuanceHookset/IssuanceHookset.md b/IssuanceHookset/IssuanceHookset.md new file mode 100644 index 0000000..2be0246 --- /dev/null +++ b/IssuanceHookset/IssuanceHookset.md @@ -0,0 +1,83 @@ +# Handy_4ndy_IssuanceHookset + +## Project Title +IssuanceHookset: A Suite of Hooks for Secure, Atomic Token Issuance on Xahau + +## Brief Description +IssuanceHookset is an open-source collection of programmable Hooks that enable fully on-chain, atomic token issuance and distribution for fungible IOU tokens on Xahau Mainnet. + +The flagship component is a complete **Initial Dex Offering (IDO) Hook** that powers phased, fair token launches directly from the issuer account—no servers, no intermediaries. + +Key features include: +- 4 active phases with time-decaying multipliers (100× → 75× → 50× → 25×) to reward early participants +- Soft-cap threshold with automatic permanent refund/unwind mode if unmet +- Atomic issuance: incoming XAH Payment → Hook logic → emitted Remit with multiplied IOU (trust lines created on-the-fly) +- On-chain tracking of global totals (raised XAH, issued IOU, executions, per-phase stats) + per-user participation data +- Built-in compliance aids: mandatory `WP_LNK` URI parameter (hex-encoded whitepaper/docs link) for disclosures and user acknowledgment +- Unwind mechanism: users return exact IOU amount → Hook emits proportional XAH refund + +Designed for end-users (project creators & participants), it lowers barriers to secure, transparent token launches while promoting participation-first models over speculation. The Hooks are modular and extensible—more issuance patterns (e.g. subscription rewards, governance) are in development. + +Live on Xahau Mainnet with real transaction examples verifiable via explorers. + +## File Structure + +``` +IssuanceHookset/ +├── Docs/ # Detailed documentation +│ ├── IDOMulti.md # IDO Hook documentation +│ ├── Rewards.md # Rewards Hook documentation +│ └── Router.md # Router Hook documentation +├── Fin/ # Production-ready condensed hooks +│ ├── IDOMulti.c # Condensed IDO hook +│ ├── Rewards.c # Condensed Rewards hook +│ ├── Router.c # Condensed Router hook +│ └── README.md # Production notes +├── Hooks/ # Master hooks +│ ├── IDOMaster.c # Commented IDO hook source +| ├── RewardsMaster.c # Commented Rewards hook source +| └── RouterMaster.c # Commented Router hook source +│ +├── IssuanceHookset.md +└── README.md # This file +``` + +## Participants +Handy Andy (@Handy_4ndy) – Creator of Xahau Hooks 101 and the Handy Hooks collection + +## Participants’ Social Media +- X / Twitter: https://x.com/Handy_4ndy +- GitHub: https://github.com/Handy4ndy + +## Contact Email +[handy_4ndy@outlook.com] + +## Link to the Online Project +Live mainnet demo via explorer transactions and state: +https://xahau.xrplwin.com/account/raXdWCS1Ro8gVER2zRQMPn3pm4kLdD7okD/ +(Example SetHook install tx: https://xahau.xrplwin.com/tx/7189E633C9DA44F6DC30F8633F2E1D34DF7C6730BE412C1DA3BD4FA932365036) + +## Xahau Address +[rGe24P5aZckhpfsXSsSwRa68pgtaio4yZw] + +## Link to Documentation +- Main README: https://github.com/Handy4ndy/HandyHooks/blob/main/IssuanceHookset/README.md +- Installation & Usage Guide: https://github.com/Handy4ndy/HandyHooks/tree/main/IssuanceHookset/Docs +- Transaction Templates & Mainnet Examples: https://github.com/Handy4ndy/HandyHooks/tree/main/IssuanceHookset/Docs/Transactions + +## Hooks code in C and matching hash +- Flagship Hook: **IDO Hook** (IDOMaster.c) – full source attached in repo + → View: https://github.com/Handy4ndy/HandyHooks/blob/main/IssuanceHookset/Hooks/IDOMaster.c +- HookDefinition / Install Tx Hash (confirms deployed code): + 7189E633C9DA44F6DC30F8633F2E1D34DF7C6730BE412C1DA3BD4FA932365036 + → Explorer: https://xahau.xrplwin.com/tx/7189E633C9DA44F6DC30F8633F2E1D34DF7C6730BE412C1DA3BD4FA932365036) + +## Hooks account of the project +raXdWCS1Ro8gVER2zRQMPn3pm4kLdD7okD, +r9cRbr7HFoPBfRhP7v9sTjSKTRJoydcTyQ +(Issuer account where the IDO Hook is installed and active on Mainnet) + +## Link to Project’s Repository +https://github.com/Handy4ndy/HandyHooks + +This submission heavily leverages **Xahau Hooks** for smart, user-facing token issuance logic—making complex fundraising safe, transparent, and fully on-chain for everyday projects and participants. \ No newline at end of file diff --git a/IssuanceHookset/README.md b/IssuanceHookset/README.md new file mode 100644 index 0000000..8aa634b --- /dev/null +++ b/IssuanceHookset/README.md @@ -0,0 +1,419 @@ +# IssuanceHookset: A Comprehensive Suite of Hooks for Secure, Atomic Token Issuance on Xahau + +## Executive Summary + +IssuanceHookset is an open-source initiative to empower projects and developers on the Xahau network with a robust, modular toolkit of programmable Hooks designed specifically for atomic, on-chain token issuance. Built entirely on Xahau's WebAssembly-based Hooks framework, this suite enables fully decentralized, automated, and compliant mechanisms for launching and distributing fungible IOU tokens (Issued Currencies) without relying on off-chain infrastructure, intermediaries, or manual processes. + +At its core, IssuanceHookset addresses the challenges of traditional token launches by providing "atomic issuance solutions"—meaning every aspect of token creation, distribution, participation tracking, and compliance enforcement happens atomically within a single ledger transaction or a tightly coupled sequence of Hook-triggered emissions (e.g., via Remit for trustless delivery). This ensures transparency, immutability, and efficiency while minimizing risks like front-running, reentrancy, or human error. + +The project draws inspiration from real-world regulatory landscapes, emphasizing built-in compliance features, on-ledger metadata for disclosures, and a sequential "hook-chain" design where individual Hooks can interconnect for complex workflows. Starting with the flagship IDO (Initial Dex Offering) Hook as a foundational example, IssuanceHookset is expanding rapidly with more specialized Hooks in development—aiming to cover a wide range of issuance models, from phased fundraising to subscription-based rewards, governance tokens, and beyond. + +This is not just a single tool; it's a growing ecosystem of Hooks that democratizes secure token issuance on Xahau, fostering a participation-first economy where value is tied to active engagement rather than speculation. With Hooks handling everything from phase-based multipliers to soft-cap refunds, IssuanceHookset positions Xahau as the premier platform for programmable, compliant DeFi primitives. More examples and integrations are on the horizon, making this a pivotal step toward a fully automated, decentralized token economy. + +## Project Vision and Goals + +IssuanceHookset envisions a future where token issuance on Xahau is as seamless and secure as sending a payment—yet enriched with sophisticated logic for fairness, compliance, and utility. Key goals include: + +- **Atomic Issuance**: Ensure tokens are issued instantly and trustlessly in response to user actions (e.g., payments), with all validations, calculations, and deliveries occurring on-chain in one atomic operation. +- **Modularity and Extensibility**: Design Hooks that can be installed independently or chained together, allowing projects to mix-and-match features like timed phases, user tracking, and refund mechanisms. +- **Regulatory Clarity and User Protection**: Embed compliance tools directly into the Hooks, reducing barriers for projects while providing clear disclosures and safeguards for participants. +- **On-Chain Transparency**: Leverage Xahau's ledger for immutable records of totals raised, tokens issued, per-user participation, and more—eliminating the need for external dashboards or audits. +- **Sustainability and Fairness**: Promote models that reward genuine participation over hype, with features like decaying multipliers, soft caps, and unwind options to align incentives. + +By focusing on these principles, IssuanceHookset transforms token launches from opaque, high-risk events into reliable, programmable processes that scale with Xahau's efficient consensus. + +## Design Inspirations + +The architecture of IssuanceHookset is deeply rooted in practical discussions around blockchain usability, regulatory challenges, and the unique capabilities of Xahau Hooks. Early conceptual talks emphasized the need for "regulatory clarity" in token issuance—drawing from global frameworks like the U.S. SEC's Howey Test, EU's MiCA regulations, UK's FCA guidelines, and FATF standards. This inspired built-in features such as: + +- **Embedded Compliance Metadata**: Hooks incorporate mandatory parameters for risk disclosures, terms of service, and KYC/AML self-certification. For instance, the IDO Hook requires a WP_LNK (Whitepaper Link) parameter—a hex-encoded URI stored on-ledger during installation. This acts as an "access token" where participants implicitly acknowledge terms by including it in transaction params, ensuring on-chain evidence of informed consent. This idea evolved from conversations about using URI fields (inspired by XRPL's URI-based metadata standards) to link immutable IPFS-hosted documents for whitepapers, audits, and legal terms—making compliance auditable and tamper-proof. +- **Sequential Hook Interconnectivity**: A key innovation is the "hook-chain" concept, where Hooks are designed to "follow onto" each other in a logical sequence. For example, an initial Setup Hook might configure parameters and activate a Fundraising Hook, which in turn triggers a Distribution Hook for rewards. This modular flow stems from early ideation on creating composable primitives: one Hook handles window timing and multipliers, another manages user namespaces for participation data, and a third enforces refunds or governance. This allows for complex, multi-stage issuance without bloating a single Hook, while ensuring atomicity through emitted transactions (e.g., Remit for token delivery). +- **Regulatory-Driven Safeguards**: Discussions on avoiding "securities-like" pitfalls led to features like soft caps (minimum raise thresholds with automatic refunds if unmet), unwind mechanisms (exact token returns for proportional refunds), and phase-based multipliers that reflect risk/reward without promising profits. URI fields extend this by enabling dynamic links to audit reports, tax guidance, and sustainability notes—promoting self-assessed utility token classifications while advising users to consult local laws. + +These inspirations ensure IssuanceHookset isn't just functional but resilient in a regulated world, turning potential liabilities into strengths. + +## Components + +### Core Hooks + +#### 1. IDO Master Hook (IDOM) +The main hook that manages the entire IDO lifecycle: +- **Phased Token Sales**: 5 phases with decreasing multipliers (100x, 75x, 50x, 25x, cooldown) +- **Soft Cap Evaluation**: Automatic evaluation after Phase 4 with refund activation if not met +- **Balance Protection**: Locks raised funds during active IDO, unlocks after successful completion +- **Unwinding**: Allows participants to return IOU tokens for XAH refunds during eligible periods +- **Whitepaper Validation**: Ensures user acknowledgment of terms via WP_LNK parameter + +#### 2. Router Hook +A smart router that manages execution flow in hook chains: +- **Transaction Routing**: Determines whether to run IDO or Rewards hooks based on transaction type +- **State-Aware**: Checks IDO window status, refund modes, and participation data +- **Hardcoded Configuration**: Uses predefined hook hashes and namespaces for security +- **Chain Management**: Ensures only relevant hooks execute per transaction + +#### 3. Rewards Hook (IRH) +Post-IDO rewards distribution system: +- **Configurable Rates**: Admin-settable interest rates and claim intervals +- **Participation Bonuses**: +5% bonus rates for original IDO participants +- **Trustline Validation**: Ensures claimants have required IOU holdings +- **Timing Constraints**: Enforces claim intervals and lifetime limits +- **Scalable State**: Uses hierarchical namespaces for unlimited user tracking + +## Core Features and Technical Highlights + +IssuanceHookset leverages Xahau's Hooks for 100% on-chain automation: + +- **Atomic Operations**: Hooks react to incoming transactions (e.g., Payments or Invokes) and emit responses like Remit for IOU delivery—creating trust lines on-the-fly without pre-setup. +- **State Management**: Uses hierarchical namespaces for per-user data (e.g., invested amounts and received tokens) and global counters (executions, totals raised/issued, per-phase stats). +- **Security Best Practices**: Includes guard macros to prevent overflows/reentrancy, restricted access (e.g., only admin can start windows), and precise amount validations. +- **Customization via Parameters**: Install-time params like INTERVAL (phase duration), ADMIN (authorized invoker), CURRENCY (token code), WP_LNK (disclosures URI), and SOFT_CAP (refund threshold) make Hooks adaptable. +- **Render Components Integration**: Future expansions will include inline citations for on-chain data and image rendering for visual metadata (e.g., token icons via URI). + +All code is written in C with HookAPI conventions, ensuring efficiency and compatibility. + +## Flagship Example: The IDO Hook + +The Initial Dex Offering (IDO) Hook serves as the cornerstone of IssuanceHookset, demonstrating atomic issuance in a phased fundraising model: + +- **Mechanics**: Installed on the issuer account, it accepts XAH payments during a configurable 5-phase window (4 active + 1 cooldown). Multipliers decay over time (100x → 75x → 50x → 25x → 0x), rewarding early participants while closing deposits in the final phase. +- **Atomic Flow**: Incoming XAH → Hook calculates phase/multiplier → Emits Remit with multiplied IOU → Updates state atomically. +- **Protections**: Soft cap check at window end—if unmet, enters permanent refund mode. Users unwind by sending exact IOU back for XAH refund. +- **Compliance Ties**: Requires WP_LNK for disclosures; participants self-certify via transaction params. +- **Real-World Templates**: Includes documented transaction examples (SetHook for install, Invoke for activation, Payments for deposits/unwinds) with hashes verifiable on Xahau explorers. + +This Hook encapsulates the project's ethos: secure, fair, and fully on-chain. + +## File Structure + +``` +IssuanceHookset/ +├── Docs/ # Detailed documentation +│ ├── IDOMulti.md # IDO Hook documentation +│ ├── Rewards.md # Rewards Hook documentation +│ └── Router.md # Router Hook documentation +├── Fin/ # Production-ready condensed hooks +│ ├── IDOMulti.c # Condensed IDO hook +│ ├── Rewards.c # Condensed Rewards hook +│ ├── Router.c # Condensed Router hook +│ └── README.md # Production notes +├── Hooks/ # Master hooks +│ ├── IDOMaster.c # Commented IDO hook source +| ├── RewardsMaster.c # Commented Rewards hook source +| └── RouterMaster.c # Commented Router hook source +│ +└── README.md # This file +``` + +## Installation and Setup + +### Hook Chain Order +Install hooks in this order for proper chain execution: +1. **Router Hook** (first in chain) +2. **IDO Hook** (second) +3. **Rewards Hook** (third) + +### Required Parameters + +#### IDO Hook Parameters +- `ADMIN` (20 bytes): Admin account ID +- `CURRENCY` (20 bytes): IOU currency code +- `INTERVAL` (4 bytes): Phase interval in ledgers +- `SOFT_CAP` (8 bytes): Soft cap in XAH +- `WP_LNK` (variable): Whitepaper link + +#### Rewards Hook Parameters +- `CURRENCY` (20 bytes): Reward currency code +- `ADMIN` (20 bytes): Admin account ID +- `INT_RATE` (4 bytes): Interest rate (optional) +- `SET_INTERVAL` (4 bytes): Claim interval (optional) +- `SET_MAX_CLAIMS` (4 bytes): Max claims limit (optional) + +#### Router Hook +No runtime parameters - uses hardcoded configuration. + +## Usage Flow + +### 1. Setup Phase +- Install hooks with required parameters +- Admin invokes IDO hook with `START` parameter to begin window + +### 2. Active IDO Phase +- Users send XAH payments with `WP_LNK` parameter +- Router directs to IDO hook for token issuance +- Automatic phase progression based on ledger intervals + +### 3. Evaluation Phase +- After Phase 4: Soft cap automatically evaluated +- Success: Funds unlock after cooldown +- Failure: Refund mode activated + +### 4. Post-IDO Phase +- Successful sales: Users can unwind during cooldown or hold for rewards +- Failed sales: Users must unwind for refunds +- Rewards hook becomes active for claim distribution + +### 5. Rewards Phase +- IOU holders claim periodic rewards +- IDO participants receive bonus rates +- Admin can adjust rates and intervals + +## XahRise Application + +Complementing the IssuanceHookset is the **XahRise** application - a user-friendly platform that enables automated asset issuance on the Xahau network through intelligent hook chain deployment. + +### Overview + +XahRise provides a complete solution for users to: +- Authenticate via Xaman wallet integration +- Select and configure hook combinations with conflict prevention +- Automatically deploy Router-coordinated hook chains +- Issue assets through orchestrated hook systems on Xahau + +### Key Features + +#### ✅ Completed Features +- **Authentication System**: Xaman wallet integration with modal-based sign-in flow +- **Theme Implementation**: "Aureum X Rebirth" cyber-alchemical luxury theme +- **Hook Selection Interface**: Modal-based selector with conflict prevention +- **Router Architecture**: Intelligent hook coordination system +- **Parameter Configuration UI**: Advanced forms with duration selectors and validation +- **Backend API**: Complete Express server with Xumm SDK integration +- **SetHook Transaction Engine**: Single-transaction hookchain installation +- **Automated Installation**: QR code generation with WebSocket status monitoring + +#### 🔄 In Development +- **Frontend-Backend Integration**: Connecting UI to payload generation API +- **Installation Status Tracking**: Real-time progress updates +- **Transaction Monitoring**: Post-installation verification + +### Technical Architecture + +#### Frontend Stack +- **React 19** with Vite for fast development +- **Custom CSS Variables** for theme management +- **Modal-based UX** for authentication and configuration +- **Responsive design** with mobile-first approach + +#### Backend Integration +- **Express.js** server with Xumm SDK +- **WebSocket support** for real-time updates +- **SetHook Transaction Engine** for atomic hookchain deployment +- **Hook Parameter Processing** with dynamic configuration + +#### Hook Chain Implementation +- **Modular Architecture**: Individual hooks with single responsibilities +- **Router-Based Coordination**: Intelligent transaction routing +- **Namespace Isolation**: Clean state separation between chains +- **Parameter Injection**: Automatic dependency configuration + +### Current Status + +**Project Phase**: Integration & Testing +**Completion Level**: ~95% (Backend API complete, frontend-backend integration pending) + +The XahRise platform features a complete backend API capable of generating proper SetHook transactions for single-transaction hookchain installation. The frontend UI is fully implemented with advanced parameter configuration. The next phase focuses on connecting these components and testing the complete user flow from hook selection to blockchain deployment. + +### Performance Optimizations + +- **Bundle Size**: Optimized from 869KB to 191KB main app bundle +- **Lazy Loading**: Route-based code splitting for heavy components +- **Manual Chunking**: Separated vendor libraries for better caching +- **Progressive Loading**: Components load only when needed + +### Single-Transaction Hookchain Installation + +XahRise implements a revolutionary approach where entire hook chains deploy atomically in one Xahau transaction: + +```json + +{ +"TransactionType": "SetHook", +"Account": "raXdWCS1Ro8gVER2zRQMPn3pm4kLdD7okD", +"Flags": 0, +"Hooks": [ +{ +"Hook": { +"HookHash": "4F7053A3D4B9D433DAB627BDE119B5C2F2304F9A2090FB7BBB181FF42DECAE8B", +"Flags": 1, +"HookOn": "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFFFFFFFFFBFFFFE", +"HookNamespace": "065D8E6C0BF74A69A6D312C3D5B5CC627434CECE07B2787C1A538FCFD9F9C8DE", +"HookParameters": [ +{ +"HookParameter": { +"HookParameterName": "49444F5F48415348", +"HookParameterValue": "330961A6811A03131B590D0C69211447E78DF7208898A44F8CC1E13C629F2D2D" +} +}, +{ +"HookParameter": { +"HookParameterName": "524557415244535F48415348", +"HookParameterValue": "8CFC9AA6AA4A858DEF04D3049D4E7D22A37F968D050634244EC5DACECCE6160D" +} +}, +{ + "HookParameter": { + "HookParameterName": "4E414D455350414345", +"HookParameterValue": "516BA79215002276EF4C381B901955C53A04575589607E7DBA20468DD343DD72" +} +} +] +} +}, +{ + "Hook": { + "HookHash": "330961A6811A03131B590D0C69211447E78DF7208898A44F8CC1E13C629F2D2D", + "Flags": 1, +"HookOn": "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFFFFFFFFFBFFFFE", +"HookNamespace": "516BA79215002276EF4C381B901955C53A04575589607E7DBA20468DD343DD72", +"HookParameters": [ +{ +"HookParameter": { +"HookParameterName": "43555252454E4359", +"HookParameterValue": "5453540000000000000000000000000000000000" +} +}, +{ +"HookParameter": { +"HookParameterName": "494E54455256414C", +"HookParameterValue": "0000001E" +} +}, +{ + "HookParameter": { + "HookParameterName": "57505F4C4E4B", +"HookParameterValue": "787370656E63652E636F2E756B" +} +} +] +} +}, +{ + "Hook": { + "HookHash": "8CFC9AA6AA4A858DEF04D3049D4E7D22A37F968D050634244EC5DACECCE6160D", + "Flags": 1, +"HookOn": "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFFFFFFFFFBFFFFF", +"HookNamespace": "59AFE47D9D3772675632EE5EBBFFEEB325D9A094387C87E3818357F4BD46FCC7", +"HookParameters": [ +{ +"HookParameter": { +"HookParameterName": "43555252454E4359", +"HookParameterValue": "5453540000000000000000000000000000000000" +} +}, +{ +"HookParameter": { +"HookParameterName": "494E545F52415445", +"HookParameterValue": "000000C8" +} +}, +{ +"HookParameter": { +"HookParameterName": "5345545F494E54455256414C", +"HookParameterValue": "00000014" +} +}, +{ +"HookParameter": { +"HookParameterName": "5345545F4D41585F434C41494D53", +"HookParameterValue": "00000000" +} +} +] +} +} +], +"Sequence": 800025814, +"NetworkID": 21337, +"Fee": "1000", +"LastLedgerSequence": 20391662 +} +``` + +This provides optimal UX with atomic deployment guarantees, single signature requirements, and intelligent state coordination. + +### Links + +- **XahRise Repository**: [GitHub Link] +- **Live Demo**: [Demo Link] +- **Documentation**: [XahRise Docs] + +## Roadmap and Future Expansions + +## Key Features + +### Security +- **Admin Authorization**: Strict access controls for configuration +- **Parameter Validation**: Comprehensive input checking +- **Balance Protection**: Prevents premature fund withdrawal +- **State Integrity**: Foreign namespace queries for secure data access + +### Flexibility +- **Configurable Parameters**: Rates, intervals, limits adjustable by admin +- **Multi-Phase System**: Incentivizes early participation +- **Refund Mechanisms**: Protects participants if soft cap not met +- **Bonus Systems**: Rewards loyal participants + +### Scalability +- **Hierarchical Namespaces**: Unlimited user tracking +- **Efficient Routing**: Minimizes unnecessary hook execution +- **State Optimization**: Minimal storage usage with packed data + +## Integration Notes + +- **Hook Chain Compatibility**: Designed for sequential execution +- **State Sharing**: Hooks communicate via shared namespaces +- **Transaction Types**: Supports invokes and payments +- **Ledger Awareness**: Time-based phase management + +## Error Handling + +All hooks provide detailed error messages for debugging: +- Configuration errors +- Authorization failures +- Timing violations +- Invalid parameters +- State access issues + +## Production Deployment + +Use the condensed versions in the `Fin/` folder for production deployment. These have comments removed for smaller binary size while maintaining full functionality. + +## Documentation + +Detailed documentation for each hook: +- [IDO Hook Documentation](Docs/IDOMulti.md) +- [Router Hook Documentation](Docs/Router.md) +- [Rewards Hook Documentation](Docs/Rewards.md) + +## Participants + +- **Handy Andy** (@Handy_4ndy) + +## Social Media & Contact + +- **X (Twitter)**: https://x.com/Handy_4ndy +- **GitHub**: https://github.com/Handy4ndy +- **Contact Email**: handy_4ndy@outlook.com + +## Links + +- **Project Repository**: https://github.com/Handy4ndy/HandyHooks/tree/main +- **Live Demo**: Mainnet explorer links in documentation +- **Xahau Address**: raXdWCS1Ro8gVER2zRQMPn3pm4kLdD7okD (Issuer/Hook account with live mainnet installation) +- **Hook Code & Hash**: IDO.c - Hash: 330961A6811A03131B590D0C69211447E78DF7208898A44F8CC1E13C629F2D2D (Verify: https://xahau.xrplwin.com/tx/7189E633C9DA44F6DC30F8633F2E1D34DF7C6730BE412C1DA3BD4FA932365036 +- **Additional Resources**: + - Transaction Template: \Docs\Transactions + - Metadata Template: \Docs\MetaTemplate + + +## Disclaimer + +Always test on testnet, seek audits, and consult professionals. Token issuance carries risks—use responsibly. Updated: January 31, 2026. + +## Author + +@Handy_4ndy + +## License + +Part of the Xahau HandyHook Collection. See repository license for details. \ No newline at end of file diff --git a/README.md b/README.md deleted file mode 100644 index f7e3b19..0000000 --- a/README.md +++ /dev/null @@ -1,189 +0,0 @@ -# Xahau Dev Contest: Ecosystem Rising - -Welcome to the **Xahau Dev Contest: Ecosystem Rising**! -This contest invites innovators to build **user-facing services powered by Xahau** and compete for prizes while strengthening the Xahau ecosystem. - ---- - -## 🏆 Prizes - -* **3 main prizes in XAH** for the winning projects. - * **🥇 1st Prize** 4000 USD value in XAH. - * **🥈 2nd Prize** 2000 USD value in XAH. - * **🥉 3rd Prize** 1000 USD value in XAH. - ---- - -## 📅 Timeline - -* **Submission deadline:** February 1st, 2026. -* **Judging panel:** 5 members from the Xahau and XRPL community (see below). - ---- - -## 👩‍⚖️ Judges Panel - -The contest will be evaluated by **five community members**: - -* [**tequ**](https://x.com/_tequ_) – Xahau Blockchain Developer -* [**Robert Kiuru**](https://x.com/robertkiuru) – COO, *XRPL Labs* -* **[gadget78](https://x.com/gadget78)** – Evernode Developer -* [**Andrei Rosseti**](https://x.com/andreirosseti) – Architect of Xahau DocProof | CTO, *EleveCRM* -* [**Vet**](https://x.com/Vet_X0) – XRPL Community contributor - ---- - -## 🎯 Theme: Services on Xahau - -Participants must build **web-based services that interact with Xahau (Mainnet)** and are designed for the **end user**, whether casual users, power users, public sector, or private sector audiences. - -Examples include **(but are not limited to)**: - -* **Everyday user tools**: personal finance dashboards, wallet managers, or community apps. -* **Business services**: payment portals, loyalty platforms, or client service tools. -* **Public platforms**: NFT marketplaces, voting systems, donation hubs, cultural apps, or utilities for social good. - ---- - -## 📌 Participation Rules - -* You can submit **as many projects as you like**. -* Each project may be submitted by an individual or a group of participants. -* Different projects from the same participant(s) can be eligible for different prizes. -* Projects **must run on the Xahau Mainnet**. -* Each project **must be accessible online**, so that both judges and the public can use or view it. - - * This avoids the need for judges to install or configure projects locally, and reduces the risk of unexpected errors or participant assistance being required. -* Each submission must include **basic documentation** to help others understand the project. - - * Optionally, you can also include **multimedia material** (videos, slides, demos, etc.) to better explain your work. -* **AI tools** may be used both for development and documentation. -* If your project uses **Hooks**, the Hook code must be open source, so that it can be audited for safety and serve as a learning resource for the community. You must attach their C code in your submission along with the hook hash. Check the “Submission Format” section. -* Projects that clearly offer regulated financial services or that target illegal activities are not eligible. -* To be evaluated by the judges, you must include your submission with a PR as indicated in the “Submission Format” section. -* Once your submission PR has been created, post a tweet on X about your project, tagging @XahauNetwork, to announce that you’ve participated in the Xahau Dev Contest. - ---- - -## 📝 Evaluation Criteria - -When reviewing submissions, judges will especially value: - -* **Originality and creativity** of the idea. -* **Absence of existing competitors** providing the same service on Xahau Mainnet prior to the contest. -* **Impact and usefulness** for end users (individuals, businesses, or public sector). -* **Quality of execution** (stability, documentation, user experience). -* **Use of Hooks (Smart Contracts on Xahau)**. - ---- - -## 📂 Submission Format - -Each project must include a folder and at least a **submission file** inside submissions directory of this repository. -The file and directory must be named with your GitHub username followed by the project name, separated by an underscore, and using the .md extension for the file. - -Example: submissions/GitHubName_ProjectName/GitHubName_ProjectName.md - -The file should contain the following fields: - -* **Project Title** -* **Brief Description** -* **Participants** (names or nicknames) -* **Participants’ Social Media** -* **Contact Email** -* **Link to the Online Project** -* **Xahau Address to receive the prize in case of winning** -* **Link to Documentation** -* **Hooks code in C and matching hash** (in case your project uses one or more, to confirm it's safe, you should add .c files in your submission folder) -* **Hooks account of the project** (to confirm you are using the hooks previously provided for this project) -* **Link to Project's Repository** (optional) -* **Other Links** (optional, e.g., demo video, presentation, slides) - -A template directory and file are available in the repository folder, which participants can use to fill in their project details. - ---- - -## 💬 Support & Community - -If you have questions or need guidance: - -* Join the **[Xahau Builders Discord](https://discord.gg/ds7nb93mYj)**. -* Or email us at **[contests@xahau.org](mailto:contests@xahau.org)**. - -We will try to answer as soon as possible. Your questions may also be added to the FAQ in this README so that others can benefit from the answers. - ---- - -## 🔑 Ownership - -* All submitted projects remain the **property of their original creators**. - ---- - -## 📎 Useful Links - -Here are some useful resources for Xahau developers: - -* [Xahau Documentation](https://docs.xahau.network) -* [Xahau Hooks Documentation](https://docs.xahau.network/hooks/) -* [Xahau GitHub Repositories](https://github.com/Xahau) -* [Xaman Website](https://xaman.app) -* [Xahau Testnet Faucet](https://xahau-test.net/) -* [Xahau Discord](https://discord.gg/ds7nb93mYj) - ---- - -## 🧭 Recap: What You Need to Do - -* Get inspired. Be creative and motivated to build something that strengthens the Xahau ecosystem. -* Build your project. Develop your web-based service using the Xahau Mainnet. -* Submit your work, Create a PR (Pull Request) following the instructions in the “Submission Format” section. -* Announce your participation. Post a tweet on X about your project, tagging @XahauNetwork, and share that you’ve joined the **Xahau Dev Contest**. - ---- - -## ❓ FAQ - -**Q: Can I submit more than one project?** -- A: Yes! You can submit as many as you want, individually or as part of a group. - -**Q: Do the projects have to be open source?** -- A: No, but they must include at least basic documentation so the judges can understand how they work. If your project includes Hooks, you must attach their C code in your submission along with the hook hash. Check the “Submission Format” section. - -**Q: Can I use AI to help me build or document my project?** -- A: Yes, AI usage is fully allowed. - -**Q: What kind of services are you expecting?** -- A: Any service that provides **value to end users** — whether individuals, businesses, or the public sector. From NFT marketplaces and financial dashboards to voting systems, payment apps, donation hubs, or any innovative public/private service. - -**Q: Is there an advantage to using Hooks?** -- A: Yes, projects that creatively implement **Hooks (smart contracts in Xahau)** will receive special recognition. - -**Q: What happens to my project after the contest?** -- A: You keep full ownership. - -**Q: Where can I ask questions?** -- A: On the [Xahau Community Discord](https://discord.gg/ds7nb93mYj) or by emailing **[contests@xahau.org](mailto:contests@xahau.org)**. - -## ⚠️ Final Disclaimer - -By participating, you agree to the following: - -Participants must meet eligibility criteria and adhere to all rules. It is not allowed to submit projects that have already been published before the competition. - -Projects remain the property of their creators, but organizers reserve the right to showcase, share, or feature submissions with appropriate credit. - -The organizers retain the right to disqualify submissions that violate rules or compromise the contest's integrity. All jury decisions are final and not subject to appeal. - -Organizers are not liable for damages, expenses or losses during participation. The organizers also reserve the right to modify the contest requirements at any time if necessary. - -You acknowledge that sanctions and certain jurisdictional restrictions may apply. Eligibility to receive rewards may require compliance with applicable laws, including the completion of KYC (Know Your Customer) verification. - -All taxes, fees, or other financial obligations related to rewards are the sole responsibility of the participants. - -If you have any concerns or doubts regarding eligibility, requirements, or tax obligations, please reach out to us through the provided communication channels before submitting your entry. - - ---- - -👉 Now it’s your turn: **Build, submit, and showcase your innovation with Xahau blockchain!** diff --git a/submissions/GithubUser_MyProjectName/GithubUser_MyProjectName.md b/submissions/GithubUser_MyProjectName/GithubUser_MyProjectName.md deleted file mode 100644 index ccf8555..0000000 --- a/submissions/GithubUser_MyProjectName/GithubUser_MyProjectName.md +++ /dev/null @@ -1,12 +0,0 @@ -* **Project Title**: You Project Title -* **Brief Description**: Brief Description -* **Participants** Full name 1, Full name 2,... -* **Participants’ Social Media**: Social: X , handle: @account1, Social: Instagram , handle: @account2 -* **Contact Email**: yourmail@yourprovider.com -* **Link to the Online Project**: https://wwww.yourwebsite.com -* **Xahau Address to receive the prize in case of winning**: rXahauAccount -* **Link to Documentation**: https://wwww.yourdocumentationlink.com -* **Hooks code in C and matching hash** Add them in your folder and add here the hashcodes -* **Hooks account of the project** rXahauAccount2 -* **Link to Project's Repository** https://www.github.com/yourRepo/yourProject -* **Other Links** (optional, e.g., demo video, presentation, slides) \ No newline at end of file