Module (nplex=0x0)::ltc1
NPLEX LTC1 - Manages the creation of LTC1 contracts
This contract provides the logic for the LTC1 contract.
- Struct
LTC1 - Struct
LTC1Witness - Struct
LTC1Token - Struct
LTC1Package - Constants
- Function
init - Function
create_contract - Function
buy_token - Function
withdraw_funding - Function
deposit_revenue - Function
claim_revenue_owner - Function
transfer_ownership - Function
transfer_token - Function
send_token_to - Function
toggle_sales - Function
claim_revenue - Function
balance - Function
claimed_revenue - Function
package_id - Function
verify_document - Function
owner_identity - Function
subtract_balance - Function
create_token_from_fraction - Function
add_fraction_balance
use (iota_identity=0x0)::controller;
use (iota_identity=0x0)::permissions;
use (iota_notarization=0x0)::method;
use (iota_notarization=0x0)::notarization;
use (iota_notarization=0x0)::timelock;
use (nplex=0x0)::events;
use (nplex=0x0)::registry;
use iota::address;
use iota::bag;
use iota::balance;
use iota::borrow;
use iota::clock;
use iota::coin;
use iota::config;
use iota::deny_list;
use iota::display;
use iota::dynamic_field;
use iota::dynamic_object_field;
use iota::event;
use iota::hex;
use iota::object;
use iota::package;
use iota::table;
use iota::transfer;
use iota::tx_context;
use iota::types;
use iota::url;
use iota::vec_map;
use std::address;
use std::ascii;
use std::bcs;
use std::option;
use std::string;
use std::type_name;
use std::vector;
Struct LTC1
The OTW for package initialization The drop ability ensures it’s a valid One-Time Witness.
public struct LTC1 has drop
Fields
Struct LTC1Witness
The LTC1 Witness for Registry Binding
public struct LTC1Witness has drop
Fields
Struct LTC1Token
The Investor Token Represents a share of the NPL package and revenue rights. No store ability — transfers are DID-gated via transfer_token.
public struct LTC1Token has key
Fields
-
id: iota::object::UID - Unique identifier: UID
-
balance: u64 - Number of "shares" this token represents: u64
-
package_id: iota::object::ID - Reference to parent LTC1Package: ID
-
claimed_revenue: u64 - Total Coin
this token has already claimed: u64 </dd> </dl> </details> ## Struct `LTC1Package` The LTC1 Package (Shared Object) Contains the state, pools, and metadata visible to everyone. TODO Immutable fields like name hash and total supply should be made immutable by embedding them in a different obj and using transfer::freeze_object public struct LTC1Package<phantom T> has key## ConstantsFields
-
id: iota::object::UID -
name: std::string::String -
document_hash: u256 -
notary_object_id: iota::object::ID - ID of the external Notarization Object (created via IOTA SDK)
-
total_supply: u64 -
max_sellable_supply: u64 - Maximum supply that can be sold to investors
-
tokens_sold: u64 -
token_price: u64 -
nominal_value: u64 -
funding_pool: iota::balance::Balance<T> -
revenue_pool: iota::balance::Balance<T> -
total_revenue_deposited: u64 -
owner_legacy_revenue: u64 - Revenue earned by unsold tokens (belongs to owner)
-
owner_identity: iota::object::ID - DID Identity ID of the current owner (Originator/Servicer)
-
owner_claimed_revenue: u64 - Total revenue claimed by the owner so far (moved from deleted OwnerBond)
-
creation_timestamp: u64 -
metadata_uri: std::string::String -
sales_open: bool - Whether primary sales are open (controlled by NPLEX admin)
const E_INSUFFICIENT_SUPPLY: u64 = 1001;const E_INSUFFICIENT_PAYMENT: u64 = 1002;const E_CONTRACT_REVOKED: u64 = 1003;const E_WRONG_BOND: u64 = 1004;const E_INVALID_SPLIT: u64 = 1005;const E_INVALID_TOKEN: u64 = 1006;const E_SUPPLY_TOO_LOW: u64 = 1007;const E_SALES_CLOSED: u64 = 1008;const E_ZERO_AMOUNT: u64 = 1009;const E_INSUFFICIENT_BALANCE: u64 = 1010;
Max investor share in BPS (95.0000%) - 6 decimalsconst E_INVALID_AMOUNT: u64 = 1011;const MAX_INVESTOR_BPS: u64 = 950000;
Min total supply (decrease the dust due to divisions rounding)const SPLIT_DENOMINATOR: u64 = 1000000;const MIN_SUPPLY: u64 = 1000000000;const TOKEN_DISPLAY_NAME: vector<u8> = vector[78, 80, 76, 69, 88, 32, 73, 110, 118, 101, 115, 116, 111, 114, 32, 84, 111, 107, 101, 110];const TOKEN_DISPLAY_DESCRIPTION: vector<u8> = vector[73, 110, 118, 101, 115, 116, 111, 114, 32, 115, 104, 97, 114, 101, 32, 102, 111, 114, 32, 76, 84, 67, 49, 32, 80, 97, 99, 107, 97, 103, 101, 32, 123, 112, 97, 99, 107, 97, 103, 101, 95, 105, 100, 125];const TOKEN_DISPLAY_IMAGE_URL: vector<u8> = vector[104, 116, 116, 112, 115, 58, 47, 47, 97, 112, 105, 46, 110, 112, 108, 101, 120, 46, 101, 117, 47, 105, 99, 111, 110, 115, 47, 116, 111, 107, 101, 110, 95, 98, 108, 117, 101, 46, 112, 110, 103];const TOKEN_DISPLAY_PROJECT_URL: vector<u8> = vector[104, 116, 116, 112, 115, 58, 47, 47, 110, 112, 108, 101, 120, 46, 101, 117];const DISPLAY_KEY_NAME: vector<u8> = vector[110, 97, 109, 101];const DISPLAY_KEY_DESCRIPTION: vector<u8> = vector[100, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110];const DISPLAY_KEY_IMAGE_URL: vector<u8> = vector[105, 109, 97, 103, 101, 95, 117, 114, 108];
## Function `init` Module initializer. Automatically called when the package is published. Sets up the IOTA Display standard forconst DISPLAY_KEY_PROJECT_URL: vector<u8> = vector[112, 114, 111, 106, 101, 99, 116, 95, 117, 114, 108];LTC1Tokenobjects.fun init(otw: (nplex=0x0)::ltc1::LTC1, ctx: &mut iota::tx_context::TxContext)## Function `create_contract` Creates a new LTC1 Package (NPL Fractionalization Contract) This is the entry point for Originators to tokenize an NPL package. ### Arguments *Implementation
fun init(otw: LTC1, ctx: &mut iota::tx_context::TxContext) { // 1. Claim Publisher let publisher = package::claim(otw, ctx); // 2. Setup Display for LTC1Token display_utils::setup_display! <LTC1Token> ( &publisher, vector[ std::string::utf8(DISPLAY_KEY_NAME), std::string::utf8(DISPLAY_KEY_DESCRIPTION), std::string::utf8(DISPLAY_KEY_IMAGE_URL), std::string::utf8(DISPLAY_KEY_PROJECT_URL), ], vector[ std::string::utf8(TOKEN_DISPLAY_NAME), std::string::utf8(TOKEN_DISPLAY_DESCRIPTION), std::string::utf8(TOKEN_DISPLAY_IMAGE_URL), std::string::utf8(TOKEN_DISPLAY_PROJECT_URL), ], ctx ); // 3. Cleanup & Transfer iota::transfer::public_transfer(publisher, iota::tx_context::sender(ctx)); }registry- The NPLEX Registry shared object, used to verify authorization. *name- The display name of the NPL Package. *notarization- The IOTA SDK Notarization object bounding the off-chain documents to this contract. *total_supply- The total number of token shares to emit (must be >=MIN_SUPPLY). *token_price- The price of a single token share in NANOS (1,000,000,000 = 1 IOTA). *nominal_value- The gross book value (GBV) of the underlying NPL package. *investor_split_bps- The percentage of future revenue destined to investors (in Basis Points). *metadata_uri- A link (e.g., IPFS) to the prospectus or public metadata. *owner_identity- The Decentralized Identifier (DID) of the Originator/Servicer. *token- The sender'sDelegationTokenproving theirROLE_INSTITUTIONauthority. *clock- The IOTA system clock for timestamping. ### Aborts *E_INVALID_SPLIT- ifinvestor_split_bps>MAX_INVESTOR_BPS. *E_SUPPLY_TOO_LOW- iftotal_supply<MIN_SUPPLY. * Reverts if theDelegationTokendoes not authorize the caller as an Institution.public entry fun create_contract<T>(registry: &mut (nplex=0x0)::registry::NPLEXRegistry, name: std::string::String, notarization: &(iota_notarization=0x0)::notarization::Notarization<u256>, total_supply: u64, token_price: u64, nominal_value: u64, investor_split_bps: u64, metadata_uri: std::string::String, owner_identity: iota::object::ID, token: &(iota_identity=0x0)::controller::DelegationToken, clock: &iota::clock::Clock, ctx: &mut iota::tx_context::TxContext)## Function `buy_token` Purchase tokens (fractional shares) from the package Investors use this function to finance the NPL package by acquiringImplementation
public entry fun create_contract<T>( registry: &mut NPLEXRegistry, name: String, notarization: &Notarization<u256>, total_supply: u64, token_price: u64, nominal_value: u64, investor_split_bps: u64, metadata_uri: String, owner_identity: ID, token: &DelegationToken, clock: &Clock, ctx: &mut iota::tx_context::TxContext ) { // Verify caller has approved Institution DID registry::verify_identity(registry, token, registry::role_institution()); let owner = iota::tx_context::sender(ctx); // Owner is the creator // 0. Extract hash and ID from Notarization let state = notarization::state(notarization); let document_hash = *notarization::data(state); let notary_object_id = iota::object::id(notarization); // 0. Validate Split assert!(investor_split_bps <= MAX_INVESTOR_BPS, E_INVALID_SPLIT); // 1. Validate Total Supply assert!(total_supply >= MIN_SUPPLY, E_SUPPLY_TOO_LOW); // 2. Claim notarization let claim = registry::claim_notarization(registry, notary_object_id, document_hash, ctx); // 3. Create UID for Package let package_uid = iota::object::new(ctx); let package_id = iota::object::uid_to_inner(&package_uid); // Calculate limits let max_sellable_supply = (((total_supply as u256) * (investor_split_bps as u256)) / (SPLIT_DENOMINATOR as u256)) as u64; // 4. Create the Package (Shared Object) let package = LTC1Package<T> { id: package_uid, name, document_hash, notary_object_id, // Supply & Pricing total_supply, max_sellable_supply, tokens_sold: 0, token_price, nominal_value, // Pools funding_pool: balance::zero<T>(), revenue_pool: balance::zero<T>(), total_revenue_deposited: 0, owner_legacy_revenue: 0, // Metadata & Admin owner_identity, owner_claimed_revenue: 0, creation_timestamp: clock::timestamp_ms(clock), metadata_uri, sales_open: false, }; // 5. Bind hash with Witness registry::bind_executor( registry, claim, package_id, LTC1Witness {} ); // 6. Publish // Share the package so ANYONE can find it and interact (buy tokens, view status) iota::transfer::share_object(package); // 7. Emit Event events::emit_contract_created( package_id, owner, nominal_value, ); }LTC1Tokenshares. ### Arguments *registry- The NPLEX Registry to verify the investor's identity. *package- TheLTC1Packageoffering the tokens. *payment- An IOTACoinused to pay for the tokens. Change is refunded. *amount- The number of tokens requested. *token- The sender'sDelegationTokenproving theirROLE_INVESTORauthority. ### Logic Implements "Dividend-stripping protection" by pre-calculating theinitial_claimedrevenue. This ensures the new investor cannot claim past revenue that was generated before they bought the token. The past revenue is credited to the Originator. ### Aborts *E_SALES_CLOSED- if the package sales are not active. *E_INSUFFICIENT_SUPPLY- if the requestedamountexceeds themax_sellable_supply. *E_INSUFFICIENT_PAYMENT- if thepaymentcoin value is lower than the required cost.public entry fun buy_token<T>(registry: &(nplex=0x0)::registry::NPLEXRegistry, package: &mut (nplex=0x0)::ltc1::LTC1Package<T>, payment: iota::coin::Coin<T>, amount: u64, token: &(iota_identity=0x0)::controller::DelegationToken, ctx: &mut iota::tx_context::TxContext)## Function `withdraw_funding` Withdraw Funding from the package (Owner Only) Verified via DelegationToken matching package.owner_identityImplementation
public entry fun buy_token<T>( registry: &NPLEXRegistry, package: &mut LTC1Package<T>, mut payment: Coin<T>, amount: u64, token: &DelegationToken, ctx: &mut iota::tx_context::TxContext ) { // Verify caller has approved Investor DID registry::verify_identity(registry, token, registry::role_investor()); // 0. Verify Contract Status (not revoked) assert!(registry::is_valid_notarization(registry, package.notary_object_id), E_CONTRACT_REVOKED); // 0.1. amount must be greater than 0 assert!(amount > 0, E_INVALID_AMOUNT); // 0.5. Verify Sales are Open assert!(package.sales_open, E_SALES_CLOSED); // 1. Check supply assert!(amount <= package.max_sellable_supply - package.tokens_sold, E_INSUFFICIENT_SUPPLY); // 2. Calculate cost let cost = (((amount as u256) * (package.token_price as u256)) as u64); assert!(iota::coin::value(&payment) >= cost, E_INSUFFICIENT_PAYMENT); // 3. Handle Payment let coin_value = iota::coin::value(&payment); let paid_balance = if (coin_value == cost) { iota::coin::into_balance(payment) } else { let split = iota::coin::split(&mut payment, cost, ctx); iota::transfer::public_transfer(payment, iota::tx_context::sender(ctx)); // Return change iota::coin::into_balance(split) }; balance::join(&mut package.funding_pool, paid_balance); // 4. Calculate Claims // When buying new tokens, we must prevent "buying into" past revenue. // The revenue attached to these tokens *up to this point* belongs to the Owner (old owner). // "Dividend Stripping" protection turned into "Back Pay" for Owner. let initial_claimed = (((amount as u256) * (package.total_revenue_deposited as u256)) / (package.total_supply as u256) as u64); // 5. Mint Token package.tokens_sold = package.tokens_sold + amount; let token = LTC1Token { id: iota::object::new(ctx), balance: amount, package_id: iota::object::uid_to_inner(&package.id), claimed_revenue: initial_claimed, }; // 6. Credit Owner Legacy Revenue // The `initial_claimed` amount is money the new buyer IS NOT entitled to. // Therefore, it is money the Owner WAS entitled to (as previous owner of unsold stock). package.owner_legacy_revenue = package.owner_legacy_revenue + initial_claimed; iota::transfer::transfer(token, iota::tx_context::sender(ctx)); // 7. Emit Event events::emit_token_purchased( iota::object::uid_to_inner(&package.id), iota::tx_context::sender(ctx), amount, cost, ); }public entry fun withdraw_funding<T>(registry: &(nplex=0x0)::registry::NPLEXRegistry, package: &mut (nplex=0x0)::ltc1::LTC1Package<T>, amount: u64, token: &(iota_identity=0x0)::controller::DelegationToken, ctx: &mut iota::tx_context::TxContext)## Function `deposit_revenue` Deposit revenue into the package (Owner Only) Verified via DelegationToken matching package.owner_identityImplementation
public entry fun withdraw_funding<T>( registry: &NPLEXRegistry, package: &mut LTC1Package<T>, amount: u64, token: &DelegationToken, ctx: &mut iota::tx_context::TxContext ) { // Verify caller has approved Institution DID registry::verify_identity(registry, token, registry::role_institution()); // 0. Verify Contract Status (not revoked) assert!(registry::is_valid_notarization(registry, package.notary_object_id), E_CONTRACT_REVOKED); // 1. Verify caller's DID matches package owner let caller_identity = iota_identity::controller::delegation_token_controller_of(token); assert!(caller_identity == package.owner_identity, E_WRONG_BOND); // 2. Withdraw let funding = iota::coin::take(&mut package.funding_pool, amount, ctx); // Aborts if amount > funding_pool.value iota::transfer::public_transfer(funding, iota::tx_context::sender(ctx)); // 3. Emit Event events::emit_funding_withdrawn( iota::object::uid_to_inner(&package.id), amount, iota::tx_context::sender(ctx), ); }public entry fun deposit_revenue<T>(registry: &(nplex=0x0)::registry::NPLEXRegistry, package: &mut (nplex=0x0)::ltc1::LTC1Package<T>, payment: iota::coin::Coin<T>, token: &(iota_identity=0x0)::controller::DelegationToken, _ctx: &mut iota::tx_context::TxContext)## Function `claim_revenue_owner` Claim Revenue for Owner Owner is entitled to: 1. The revenue share of the currently UNSOLD tokens. 2. The "Legacy Revenue" accumulated from tokens they owned in the past but then sold. Verified via DelegationToken matching package.owner_identityImplementation
public entry fun deposit_revenue<T>( registry: &NPLEXRegistry, package: &mut LTC1Package<T>, payment: Coin<T>, token: &DelegationToken, _ctx: &mut iota::tx_context::TxContext ) { // Verify caller has approved Institution DID registry::verify_identity(registry, token, registry::role_institution()); // 0. Verify Contract Status (not revoked) assert!(registry::is_valid_notarization(registry, package.notary_object_id), E_CONTRACT_REVOKED); // 1. Verify caller's DID matches package owner let caller_identity = iota_identity::controller::delegation_token_controller_of(token); assert!(caller_identity == package.owner_identity, E_WRONG_BOND); // 2. Update Metadata let amount = iota::coin::value(&payment); package.total_revenue_deposited = package.total_revenue_deposited + amount; // 3. Deposit to Revenue Pool balance::join(&mut package.revenue_pool, iota::coin::into_balance(payment)); // 4. Emit Event events::emit_revenue_deposited( iota::object::uid_to_inner(&package.id), amount, ); }public entry fun claim_revenue_owner<T>(registry: &(nplex=0x0)::registry::NPLEXRegistry, package: &mut (nplex=0x0)::ltc1::LTC1Package<T>, token: &(iota_identity=0x0)::controller::DelegationToken, ctx: &mut iota::tx_context::TxContext)## Function `transfer_ownership` Transfer ownership of the package to a new owner (DID-based) Requires prior authorization from NPLEX via RegistryImplementation
public entry fun claim_revenue_owner<T>( registry: &NPLEXRegistry, package: &mut LTC1Package<T>, token: &DelegationToken, ctx: &mut iota::tx_context::TxContext ) { // Verify caller has approved Institution DID registry::verify_identity(registry, token, registry::role_institution()); // Verify Contract Status (not revoked) assert!(registry::is_valid_notarization(registry, package.notary_object_id), E_CONTRACT_REVOKED); // 1. Verify caller's DID matches package owner let caller_identity = iota_identity::controller::delegation_token_controller_of(token); assert!(caller_identity == package.owner_identity, E_WRONG_BOND); // 2. Calculate Current Entitlement (Unsold Tokens) let unsold_supply = package.total_supply - package.tokens_sold; let current_share = (((unsold_supply as u256) * (package.total_revenue_deposited as u256)) / (package.total_supply as u256) as u64); // 3. Calculate Total Entitlement (Current + Legacy) let total_entitled = current_share + package.owner_legacy_revenue; // 4. Calculate Due let due = total_entitled - package.owner_claimed_revenue; // In the rare case due is 0 (double claim), we just return. if (due == 0) { return }; // 5. Update Package State package.owner_claimed_revenue = package.owner_claimed_revenue + due; // 6. Payout let payment = iota::coin::take(&mut package.revenue_pool, due, ctx); iota::transfer::public_transfer(payment, iota::tx_context::sender(ctx)); // 7. Emit Event events::emit_revenue_claimed_owner( iota::object::uid_to_inner(&package.id), due, iota::tx_context::sender(ctx), ); }public entry fun transfer_ownership<T>(registry: &mut (nplex=0x0)::registry::NPLEXRegistry, package: &mut (nplex=0x0)::ltc1::LTC1Package<T>, new_owner: address, new_owner_identity: iota::object::ID, sender_token: &(iota_identity=0x0)::controller::DelegationToken, _ctx: &mut iota::tx_context::TxContext)## Function `transfer_token` Transfer an LTC1Token to another address (DID-gated sender) Sender must be a whitelisted Investor. Recipient is not verified on-chain — the real gate is at the point of USE (claim_revenue, transfer_token, etc.)Implementation
public entry fun transfer_ownership<T>( registry: &mut NPLEXRegistry, package: &mut LTC1Package<T>, new_owner: address, new_owner_identity: ID, sender_token: &DelegationToken, _ctx: &mut iota::tx_context::TxContext ) { // Verify sender has approved Institution DID registry::verify_identity(registry, sender_token, registry::role_institution()); // Verify caller's DID matches current package owner let caller_identity = iota_identity::controller::delegation_token_controller_of(sender_token); assert!(caller_identity == package.owner_identity, E_WRONG_BOND); // 1. Validate and Consume Ticket from Registry let pkg_id = iota::object::uid_to_inner(&package.id); registry::consume_transfer_ticket(registry, pkg_id, new_owner, new_owner_identity, LTC1Witness {}); // 2. Update ownership on package package.owner_identity = new_owner_identity; // 3. Emit Event events::emit_ownership_transferred(pkg_id, new_owner_identity); }public entry fun transfer_token(registry: &(nplex=0x0)::registry::NPLEXRegistry, token: (nplex=0x0)::ltc1::LTC1Token, recipient: address, sender_did: &(iota_identity=0x0)::controller::DelegationToken)## Function `send_token_to` Package-internal helper: transfer a LTC1Token to an address. Used by sibling modules (e.g. fractional::redeem) that cannot call the privateImplementation
public entry fun transfer_token( registry: &NPLEXRegistry, token: LTC1Token, recipient: address, sender_did: &DelegationToken, ) { // Verify sender is whitelisted Investor registry::verify_identity(registry, sender_did, registry::role_investor()); let token_id = iota::object::uid_to_inner(&token.id); iota::transfer::transfer(token, recipient); events::emit_transfer_token(token_id, recipient); }iota::transfer::transferdirectly on LTC1Token.public(package) fun send_token_to(token: (nplex=0x0)::ltc1::LTC1Token, recipient: address)## Function `toggle_sales` Toggle sales state for the package Requires prior authorization from NPLEX via RegistryImplementation
public(package) fun send_token_to(token: LTC1Token, recipient: address) { iota::transfer::transfer(token, recipient); }public entry fun toggle_sales<T>(registry: &mut (nplex=0x0)::registry::NPLEXRegistry, package: &mut (nplex=0x0)::ltc1::LTC1Package<T>, token: &(iota_identity=0x0)::controller::DelegationToken, _ctx: &mut iota::tx_context::TxContext)## Function `claim_revenue` Claim Revenue for Investors Investors can claim their share of the revenue based on their token balance. Maybe should be allowed even if the contract is revoked (so investors can exit), to check later when a better control over permissions is implemented.Implementation
public entry fun toggle_sales<T>( registry: &mut NPLEXRegistry, package: &mut LTC1Package<T>, token: &DelegationToken, _ctx: &mut iota::tx_context::TxContext ) { // Verify caller has approved Institution DID registry::verify_identity(registry, token, registry::role_institution()); // 1. Consume Ticket from Registry (validates executor + authorization) let new_state = registry::consume_sales_toggle_ticket( registry, iota::object::uid_to_inner(&package.id), LTC1Witness {} ); // 2. Update Sales State package.sales_open = new_state; // 3. Emit Event events::emit_sales_toggled( iota::object::uid_to_inner(&package.id), new_state, ); }public entry fun claim_revenue<T>(registry: &(nplex=0x0)::registry::NPLEXRegistry, package: &mut (nplex=0x0)::ltc1::LTC1Package<T>, token: &mut (nplex=0x0)::ltc1::LTC1Token, did_token: &(iota_identity=0x0)::controller::DelegationToken, ctx: &mut iota::tx_context::TxContext)## Function `balance` Accessor forImplementation
public entry fun claim_revenue<T>( registry: &NPLEXRegistry, package: &mut LTC1Package<T>, token: &mut LTC1Token, did_token: &DelegationToken, ctx: &mut iota::tx_context::TxContext ) { // Verify caller has approved Investor DID registry::verify_identity(registry, did_token, registry::role_investor()); // Verify Contract Status (not revoked) // TODO this has to be checked in the future when we have a more granular control over permissions assert!(registry::is_valid_notarization(registry, package.notary_object_id), E_CONTRACT_REVOKED); // 1. Verify Token belongs to this package assert!(token.package_id == iota::object::uid_to_inner(&package.id), E_INVALID_TOKEN); // 2. Calculate Entitlement // Formula: (balance * total_revenue_deposited) / total_supply let total_entitled = (((token.balance as u256) * (package.total_revenue_deposited as u256)) / (package.total_supply as u256) as u64); // 3. Calculate Due let due = total_entitled - token.claimed_revenue; if (due == 0) { return }; // 4. Update Token token.claimed_revenue = token.claimed_revenue + due; // 5. Payout let payment = iota::coin::take(&mut package.revenue_pool, due, ctx); iota::transfer::public_transfer(payment, iota::tx_context::sender(ctx)); // 6. Emit Event events::emit_revenue_claimed_investor( iota::object::uid_to_inner(&package.id), iota::object::uid_to_inner(&token.id), due, iota::tx_context::sender(ctx), ); }LTC1Token.balance
## Function `claimed_revenue` Accessor forpublic fun balance(token: &(nplex=0x0)::ltc1::LTC1Token): u64LTC1Token.claimed_revenuepublic fun claimed_revenue(token: &(nplex=0x0)::ltc1::LTC1Token): u64## Function `package_id` Accessor forImplementation
public fun claimed_revenue(token: <C1Token): u64 { token.claimed_revenue }LTC1Token.package_idpublic fun package_id(token: &(nplex=0x0)::ltc1::LTC1Token): iota::object::ID## Function `verify_document` Verify if a proposed document hash matches the package's registered hash Returns true ifImplementation
public fun package_id(token: <C1Token): ID { token.package_id }document_hashequalspackage.document_hash.public fun verify_document<T>(package: &(nplex=0x0)::ltc1::LTC1Package<T>, document_hash: u256): bool## Function `owner_identity` Accessor forImplementation
public fun verify_document<T>(package: <C1Package<T>, document_hash: u256): bool { package.document_hash == document_hash }LTC1Package.owner_identitypublic fun owner_identity<T>(package: &(nplex=0x0)::ltc1::LTC1Package<T>): iota::object::ID## Function `subtract_balance` SubtractImplementation
public fun owner_identity<T>(package: <C1Package<T>): ID { package.owner_identity }amountfrom a token's balance, splitting claimed_revenue proportionally. Returns (balance_removed, claimed_revenue_removed). Asserts amount > 0 and amount < token.balance (cannot fractionalize entire token).public(package) fun subtract_balance(token: &mut (nplex=0x0)::ltc1::LTC1Token, amount: u64): (u64, u64)## Function `create_token_from_fraction` Create a new LTC1Token with exact values. Used during fraction redemption.Implementation
public(package) fun subtract_balance(token: &mut LTC1Token, amount: u64): (u64, u64) { assert!(amount > 0, E_ZERO_AMOUNT); assert!(amount < token.balance, E_INSUFFICIENT_BALANCE); // Split claimed_revenue proportionally let claimed_split = (((token.claimed_revenue as u256) * (amount as u256)) / (token.balance as u256) as u64); token.balance = token.balance - amount; token.claimed_revenue = token.claimed_revenue - claimed_split; (amount, claimed_split) }public(package) fun create_token_from_fraction(package_id: iota::object::ID, balance: u64, claimed_revenue: u64, ctx: &mut iota::tx_context::TxContext): (nplex=0x0)::ltc1::LTC1Token## Function `add_fraction_balance` Add balance and claimed_revenue from a fraction back to an existing token. Used by fractional::merge().Implementation
public(package) fun create_token_from_fraction( package_id: ID, balance: u64, claimed_revenue: u64, ctx: &mut iota::tx_context::TxContext ): LTC1Token { LTC1Token { id: iota::object::new(ctx), balance, package_id, claimed_revenue, } }public(package) fun add_fraction_balance(token: &mut (nplex=0x0)::ltc1::LTC1Token, balance: u64, claimed_revenue: u64)Implementation
public(package) fun add_fraction_balance( token: &mut LTC1Token, balance: u64, claimed_revenue: u64, ) { token.balance = token.balance + balance; token.claimed_revenue = token.claimed_revenue + claimed_revenue; } -