Trust Bitcoin Info
Trust Bitcoin has an edge in DeFi services because of its best-in-class offerings. With the likes of services like mining, smart contracts, digital wallets, governance and creating dApps. Also, miners will have exceptional benefits for adding a block to the Trust Bitcoin blockchain.
Team and KYC Verification
The KYC verification for this project is currently in progress.
The team has submitted their information and verification is pending.
TrustNet Score
The TrustNet Score evaluates crypto projects based on audit results, security, KYC verification, and social media presence. This score offers a quick, transparent view of a project's credibility, helping users make informed decisions in the Web3 space.
Real-Time Threat Detection
Real-time threat detection, powered by Cyvers.io,
is currently not
activated
for this project.
This advanced feature provides continuous monitoring and instant alerts to safeguard your assets from potential security threats. Real-time detection enhances your project's security by proactively identifying and mitigating risks.
For more information, click here.
Security Assessments
Summary and Final Words
No crucial issues found
The contract does not contain issues of high or medium criticality. This means that no known vulnerabilities were found in the source code.
Contract owner cannot mint
It is not possible to mint new tokens.
Contract owner cannot blacklist addresses.
It is not possible to lock user funds by blacklisting addresses.
Contract owner cannot set high fees
The fees, if applicable, can be a maximum of 25% or lower. The contract can therefore not be locked. Please take a look in the comment section for more details.
Token transfer can be locked
Owner can lock user funds with owner functions.
Token cannot be burned
There is no burning within the contract without any allowances
Ownership is not renounced
The owner retains significant control, which could potentially be used to modify key contract parameters.
Contract is not upgradeable
The contract does not use proxy patterns or other mechanisms to allow future upgrades. Its behavior is locked in its current state.
Scope of Work
This audit encompasses the evaluation of the files listed below, each verified with a SHA-1 Hash. The team referenced above has provided the necessary files for assessment.
The auditing process consists of the following systematic steps:
- Specification Review: Analyze the provided specifications, source code, and instructions to fully understand the smart contract's size, scope, and functionality.
- Manual Code Examination: Conduct a thorough line-by-line review of the source code to identify potential vulnerabilities and areas for improvement.
- Specification Alignment: Ensure that the code accurately implements the provided specifications and intended functionalities.
- Test Coverage Assessment: Evaluate the extent and effectiveness of test cases in covering the codebase, identifying any gaps in testing.
- Symbolic Execution: Analyze the smart contract to determine how various inputs affect execution paths, identifying potential edge cases and vulnerabilities.
- Best Practices Evaluation: Assess the smart contracts against established industry and academic best practices to enhance efficiency, maintainability, and security.
- Actionable Recommendations: Provide detailed, specific, and actionable steps to secure and optimize the smart contracts.
A file with a different Hash has been intentionally or otherwise modified after the security review. A different Hash may indicate a changed condition or potential vulnerability that was not within the scope of this review.
Final Words
The following provides a concise summary of the audit report, accompanied by insightful comments from the auditor. This overview captures the key findings and observations, offering valuable context and clarity.
Explorer
This project utilizes a dedicated blockchain explorer. The deployed smart contract is publicly accessible at the following address:
TBCDistribution.sol
Ownership Privileges
Owner
- Map old wallet addresses to new ones before migration starts.
- Overwrite any user's complete financial history including paid amounts, income records, royalty status, and bonus rates during migration.
Inject and modify sell position records for any user at any stage during migration. - Overwrite stage availability, sell queue pointer, and active status for all five stages during migration.
- Set the Referrals contract address once — this cannot be updated later.
- Execute purchases before the public sale opens, allowing pre-seeding of positions and referral chains.
- Start the public sale — this action is permanent and cannot be reversed or paused.
- Transfer ownership to any new address at any time.
- Permanently renounce ownership, after which all owner functions are locked forever.
FundWallet
- Lock or unlock any user's working bonus payments permanently, with no expiry limit.
- Set the monthly direct business reward configuration including threshold and payout amount — this can be overwritten even after some users have already claimed for that period.
- Withdraw any amount of native TBC from the system liquidity pool directly to itself.
- Silently disable all user reward claims and withdrawals across the entire protocol simply by reducing its AUSD token approval — no transaction or announcement is required.
Note: Team Trust Bitcoin provided the contract file for this project. Afterward, they launched their own blockchain, TrustBitcoin. Any changes made after the audit are considered outside the scope of the audit, and the audit team holds no responsibility for those changes.
Files and details
Functions
public
/
State variables
public
/
Total lines
of code
/
Capabilities
Hover on items
/
Findings and Audit result
high Issues | 7 findings
Pending
#1 high Issue
Migration Silently Discards depositedTBC, Causing 100% Principal Loss for All V1 Users
On line 575, the return tuple from oldVersion.mapUserInfo(buyer) is unpacked as (..., claimedAmount, , bool royalty). The double comma between claimedAmount and royalty is a silent discard of the 11th return value, which corresponds to uint256 depositedTBC as defined in the UserInfo struct at lines 42–55. As a result, mapUserInfo[newBuyer].depositedTBC defaults to zero for every migrated user. Simultaneously, setSellPosition correctly migrates all position records into positionWiseTBC, positionWiseWallet, and stageWiseUserPosition. This creates a fatal mismatch: migrated users have fully populated sell positions backed by zero deposit. When __updateStageWiseSell encounters any such position, it reads userDeposited = mapUserInfo[userOnPosition].depositedTBC = 0, caps sellableTBC to zero, then unconditionally executes positionWiseTBC[stage][i] = 0 and stageWiseUserTBC[stage][userOnPosition] -= remainingOnPosition, permanently deleting the entire position while paying the user nothing. Every V1 user loses their complete sell position principal on first encounter with the sell loop.
Pending
#2 high Issue
Sell Position Partially Wiped Without Compensation Causes Silent Fund Loss
Inside the general sell loop, when sellableTBC > userDeposited, the code correctly caps sellableTBC = userDeposited. However, line 358 then unconditionally executes positionWiseTBC[stage][i] = 0 and line 357 executes stageWiseUserTBC[stage][userOnPosition] -= remainingOnPosition, permanently deleting the full position regardless of how much was actually sold. Payment at lines 361–374 is made only for sellableTBC, while the difference remainingOnPosition - sellableTBC is erased from state with no compensation and no way to recover it. For example, if a user has a position of 1000 TBC with only 400 TBC deposited, the protocol pays for 400 and silently destroys the remaining 600 with no record, no refund, and no error message.
Pending
#3 high Issue
communitySeller 20% Sell Cap Bypassed by Dual-Loop Design
Function: __updateStageWiseSell — TBCDistributionPlan.sol The function contains two sequential loops. Loop 1 at lines 296–324 iterates over stageWiseUserPosition[stage][communitySeller] and enforces a hard cap of 20% of totalTBC via sellerSellLimit. Loop 2 at lines 340–395 iterates over the general positionWiseTBC[stage] array starting from stageWiseCurrentSellPosition[stage]. Since __updateStageWiseRecord adds all positions — including the communitySeller's — to the same positionWiseTBC[stage] array, the communitySeller's position indices appear in both data structures. If any of their indices fall within the Loop 2 scan window, Loop 2 processes their remaining balance again under the general 30% user quota with no check for ownership. Loop 1 may sell 20% from the communitySeller; Loop 2 then sells additional amounts from the same positions. The communitySeller can effectively capture up to 50% of each transaction, directly at the expense of legitimate FIFO-queue sellers.
Pending
#4 high Issue
setSellPosition Records Wrong Position Index When Old Contract Has Zero-Address Holes
The function iterates over old position indices i from start to end. At line 615, for valid (non-zero) positions, it records stageWiseUserPosition[stage][newBuyer].push(i) — the old contract index — while at line 616 it pushes data to the new positionWiseTBC[stage] array sequentially. If the old contract has any zero-address entries (skipped by the if(buyer != address(0)) guard at line 614), the new array gains fewer entries than the old index suggests. For example, with old positions [Alice, address(0), Bob]: Alice is added at new index 0 (records i=0, correct), the zero address is skipped, Bob is added at new index 1 but records i=2. When Loop 1 in __updateStageWiseSell later reads positionWiseTBC[stage][stageWiseUserPosition[stage][Bob][0]], it accesses index 2, but the new array only has indices 0 and 1 — an out-of-bounds revert in Solidity 0.8+. If Bob is ever used as communitySeller, every buyTBC call at that stage reverts permanently. The presence of if(buyer != address(0)) in the code confirms the developers anticipated zero-address entries but did not handle the index shift.
Pending
#5 high Issue
Referral Bonus Distribution Reverts When systemTBC Is Depleted, Bricking All Stage-0 Purchases
Every bonus function in the contract has a balance guard before paying except __referralBonusDistribution. At lines 422 and 434, it calls __transferTo(sponsor, reward) directly without checking IERC20(ausd).balanceOf(address(this)) >= reward, while __workingBonusDistribution at line 468 and __royaltyBonusDistribution at line 516 both check balance before transferring. When systemTBC is zero, the shortage mechanism at lines 329–332 redirects the system's 50% share obligation to user sellers (userSellLimit += shortage). At stage 0 where incentivePerStage[0] = 0, sellers receive 100% of TBC value in AUSD: sellerFund = (sellableTBC * 1e18) / 1e18 = sellableTBC AUSD. If user sellers cover the full totalTBC = packageAmount, they receive the entire packageAmount in AUSD, leaving the contract balance at zero. The subsequent call to __referralBonusDistribution at line 238 then calls safeTransfer with a zero-balance contract, reverting the entire buyTBC transaction. Since systemTBC naturally depletes as the protocol matures, this becomes a guaranteed failure condition on all stage-0 purchases.
Pending
#6 high Issue
Any AUSD-Blacklisted Seller in the Active Window Permanently Freezes All Protocol Purchases
The AUSD contract at AUSD.sol line 118 enforces notBlacklisted(receiver) on all transfers. Inside Loop 2 of __updateStageWiseSell, seller payments are made at lines 374 and 393 via __transferTo(userOnPosition, payableFund), which calls IERC20(ausd).safeTransfer(userOnPosition, sendAmount). If that seller has been AUSD-blacklisted — for any reason, whether regulatory, admin action, or compromised key — safeTransfer reverts. There is no try/catch wrapper. The revert propagates through __updateStageWiseSell and causes the entire buyTBC to fail. Critically, because the transaction reverts, stageWiseCurrentSellPosition[stage] is never advanced past the blacklisted position. Every subsequent buyTBC call hits the same position and reverts identically. With potentially thousands of sellers across the position array, any single blacklisted address creates a complete and unrecoverable purchase freeze.
Pending
#7 high Issue
Monthly Reward Front-Running Permanently Locks Victims Into Lower Reward Tiers at Zero Attacker Cost
The function has no access control and accepts a caller-specified topSponsor for each user. Reward tier is determined by the split between topSponsorSale and remainingTeamSale, which changes depending on which direct downline is chosen. At line 680, monthlySaleClaimed[user][month] = payableReward permanently marks the user as claimed, and line 652 prevents any re-claim with if (monthlySaleClaimed[user][month] != 0) continue. An attacker monitors the mempool for a user's optimal claim transaction (choosing the downline that maximizes the minimum of both legs for the highest tier) and front-runs with a transaction using a suboptimal direct downline of that user. The suboptimal split may qualify for the 5M/5M tier (400,000 AUSD) instead of the 10M/10M tier (1,000,000 AUSD). The 600,000 AUSD difference is irrecoverable — no admin function can reset monthlySaleClaimed, and no upgrade path exists without full redeployment. A bot can automate this attack against every eligible user every month at zero capital cost.
medium Issues | 3 findings
Pending
#1 medium Issue
Unbounded communitySeller Position Loop Can Exceed Block Gas Limit
Loop 1 at line 296 iterates over stageWiseUserPosition[stage][communitySeller] with no iteration cap — it runs for as many entries as the communitySeller has accumulated at that stage. Each iteration involves multiple storage reads and AUSD transfers. If the communitySeller accumulates a large number of positions through repeated purchases, migration seeding, or extended protocol operation, this array can grow to thousands of entries. Although the loop breaks early when sellerSellLimit == 0, reaching that condition through many small positions still consumes proportional gas. At approximately 1,500+ small positions, the loop exceeds the block gas limit, causing every buyTBC call to revert regardless of the buyer, stage, or package size.
Pending
#2 medium Issue
Blacklisting buyBurnWallet Permanently Bricks Every AUSD Transfer in the Protocol
Every AUSD movement in the protocol — seller proceeds, referral bonuses, working bonuses, royalties, monthly rewards, and user withdrawals — passes through either __transferTo (line 534) or __transferFrom (line 526). Both functions unconditionally send a fee to buyBurnWallet as their first operation: IERC20(ausd).safeTransfer(buyBurnWallet, fee) at line 538 and IERC20(ausd).safeTransferFrom(from, buyBurnWallet, fee) at line 530. AUSD enforces notBlacklisted(receiver) on all transfers per AUSD.sol line 118. If buyBurnWallet is blacklisted, every call to both helper functions reverts, simultaneously disabling all bonus payments, all seller proceeds, all monthly claims, and all withdrawal operations. Because buyBurnWallet is declared immutable at line 37, it cannot be updated after deployment, leaving no on-chain recovery path.
Pending
#3 medium Issue
claimMonthlyReward Allowance Check Undercounts Royalty Consumption, Causing Primary Payment Revert
At line 679, the function checks IERC20(ausd).allowance(fundWallet, address(this)) >= payableReward before proceeding. Inside the payment block, line 684 calls __royaltyBonusDistribution(sponsor, royaltyAmount) where royaltyAmount = payableReward * royaltyIncentive / divider = 10% of payableReward. Since buyTBC sweeps the contract's AUSD to treasury at line 243 after every purchase, the contract balance at claim time is typically zero. __royaltyBonusDistribution therefore falls through to __transferFrom(fundWallet, sponsor, royaltyAmount) at line 521, consuming royaltyAmount of fundWallet's allowance. When the primary payment __transferFrom(fundWallet, user, payableReward) executes at line 689, only payableReward - royaltyAmount = 0.9 × payableReward of allowance remains. The safeTransferFrom reverts on insufficient allowance, causing the entire function to fail. Any user whose upline sponsor holds royalty status cannot claim their monthly reward unless fundWallet maintains 1.1× the expected allowance — a requirement the contract never communicates or enforces.
low Issues | 3 findings
Pending
#1 low Issue
Single Global depositedTBC Shared Across All Stages Cascades Wipes to Later-Stage Positions
mapUserInfo[user].depositedTBC is a single global counter shared across all sell stages. A stage-0 buyer who places 250 TBC at each of stages 1, 2, 3, and 4 needs 1000 TBC deposited in total, but the contract never enforces or communicates this requirement. When __updateStageWiseSell processes the user's stage-1 position, it deducts at line 387: mapUserInfo[userOnPosition].depositedTBC -= sellableTBC. The stage-2, 3, and 4 positions now have less backing. When those positions are subsequently encountered, the reduced depositedTBC triggers the zero-deposit branch at line 353, which wipes the full remaining position at lines 357–358 without payment per bug. A user who deposits only enough for their first stage is systematically wiped across all subsequent stages.
Pending
#2 low Issue
setTeam Guards on Old Address but Registers New Address, Breaking Migrated Referral Chains
At line 571, the guard checks referrals.getSponsor(buyer) — the OLD address — for registration status in the NEW Referrals contract. But line 572 registers newBuyer — the REMAPPED address. When mapNewAddress[buyer] != buyer, these are different. The old address was never registered in the new Referrals, so getSponsor(buyer) always returns address(0), making the guard always pass. On a retry batch for the same user, the guard passes again and addMember(newBuyer, newSponsor) reverts with "Member already added in list", failing the entire batch. If users call buyTBC using their old address post-migration, the old address is independently registered with no migrated financial data, creating a shadow entity.
Pending
#3 low Issue
Caller-Controlled communitySeller Enables Sell Queue Front-Running by Colluding Parties
The communitySeller parameter accepts any address with zero validation. Loop 1 of __updateStageWiseSell grants that address priority access to 20% of each purchase volume, bypassing the FIFO ordering enforced by stageWiseCurrentSellPosition. Any two parties can collude: the buyer passes the seller's address as communitySeller, granting 20% priority regardless of queue position. Legitimate sellers waiting in the FIFO queue are bypassed indefinitely for 20% of every transaction orchestrated by colluding pairs.
optimization Issues | 4 findings
Pending
#1 optimization Issue
maxLoops = 512 Makes Every Purchase Transaction Prohibitively Expensive
The immutable maxLoops = 512 at line 143 governs three separate loops per purchase: the general sell loop in __updateStageWiseSell (up to 512 iterations, each calling __transferTo which executes two safeTransfer calls), __workingBonusDistribution (up to 512 external getSponsor calls and storage writes), and __monthlyBonusDistribution (up to 512 storage writes). On Ethereum mainnet, each safeTransfer costs approximately 30,000–50,000 gas; the sell loop alone can consume 25–50 million gas at full utilization, far exceeding the block gas limit of ~30 million. Even at partial fill rates, single buyTBC transactions routinely cost $500–800+, making the protocol inaccessible to retail participants and concentrating usage to institutional actors only.
Pending
#2 optimization Issue
IERC20(ausd).balanceOf(address(this)) Called Repeatedly in the Same Transaction
The same external call IERC20(ausd).balanceOf(address(this)) is made independently in each bonus distribution function during a single buyTBC execution: at line 468 in __workingBonusDistribution, at line 516 in __royaltyBonusDistribution, at line 501 in __foreignTourBonusDistribution, and finally at line 243 for the treasury sweep. Each balanceOf call costs approximately 800–1,000 gas as an external view call. In a single buyTBC transaction with multiple sponsors and royalty holders, this call can occur 8–12 times when counting all nested invocations.
Pending
#3 optimization Issue
referrals.getSponsor() Called Redundantly Inside the Referral Bonus Loop
Inside __referralBonusDistribution, the loop at line 407 calls referrals.getSponsor(sponsor) to get sponsorWallet for royalty checks, and again at line 439 calls referrals.getSponsor(sponsor) to advance sponsor to the next upline. These two calls return the same value — the next sponsor in the chain. Additionally, across __referralBonusDistribution (line 399), __workingBonusDistribution (line 455), and __monthlyBonusDistribution (line 444), all three functions independently call referrals.getSponsor(buyer) at the start to begin their upline traversal. Each external call costs approximately 2,100–5,000 gas. With 10 referral levels, up to 20 redundant external calls occur per buyTBC execution.
Pending
#4 optimization Issue
Redundant Storage Struct Reads in Sell Loop — Use Storage Pointer for Gas Efficiency
In Loop 2 of __updateStageWiseSell, each iteration accesses mapUserInfo[userOnPosition] multiple times as separate storage reads and writes: mapUserInfo[userOnPosition].depositedTBC is read at line 349, written at line 368 or 387, mapUserInfo[userOnPosition].receivedFromSale is written at lines 372 or 390, and mapUserInfo[userOnPosition].claimedAmount is written at lines 373 or 391. In Solidity, each individual field access on a storage struct costs a full cold or warm SLOAD/SSTORE. With up to 512 iterations, these repeated struct accesses can add millions of gas units to a single transaction.
informational Issues | 7 findings
Pending
#1 informational Issue
Atomicity Gap Between Position Creation and Deposit Creates Unavoidable Position Wipe Window
When a buyer purchases TBC, __updateStageWiseRecord creates sell positions in positionWiseTBC and inflates stageWiseAvailableTBC for future stages. However, the native tokens are delivered to the buyer's external wallet at line 215 (payable(buyer).call{value: totalTBC}), not into the contract. The buyer must separately call depositTBC to back their positions. However, the shared nonReentrant guard with _locked = 2 during buyTBC execution makes atomic buy-and-deposit impossible — any depositTBC call inside a receive() callback reverts. This creates a mandatory one-block exposure window. During this window, any concurrent buyTBC call at the relevant stage invokes __updateStageWiseSell, which encounters the unfunded position. If the transaction succeeds, the wipe at lines 357–358 permanently destroys the position without compensation. Every buyer faces this exposure window with no on-chain way to eliminate it.
Pending
#2 informational Issue
Single Global depositedTBC Shared Across All Stages Creates Cross-Stage Depletion Risk
mapUserInfo[user].depositedTBC is a single global counter shared across all sell stages. Selling at stage 1 reduces the deposit balance available for stage-2, 3, and 4 positions. With C-4 unpatched, cross-stage depletion triggers silent position wipes. With fixed, positions simply skip when underfunded and resume once the user re-deposits. The residual harm is UX confusion — users may not understand that selling at an early stage depletes collateral for later stages.
Pending
#3 informational Issue
Treasury Wallet Blacklisting Halts All Protocol Purchases
The final statement in buyTBC at line 243 executes IERC20(ausd).safeTransfer(treasuryWallet, IERC20(ausd).balanceOf(address(this))). AUSD enforces notBlacklisted(receiver). If treasuryWallet is blacklisted — by regulatory action or a compromised key — every buyTBC call fails. Since treasuryWallet is immutable, there is no recovery without redeployment.
Pending
#4 informational Issue
ETH Sent via selfdestruct Is Permanently Locked With No Extraction Path
withdrawSystemTBC at line 801 enforces require(systemTBC >= amount). ETH forcibly delivered via selfdestruct bypasses the receive() function at line 152 and does not increment systemTBC. The excess address(this).balance - systemTBC - usersTBC has no extraction mechanism.
Pending
#5 informational Issue
Caller Can Force-Register Any Address as a Protocol Participant Without Consent
buyTBC accepts address buyer as a caller-controlled parameter with no validation that buyer == msg.sender. The caller deducts AUSD from their own wallet but permanently registers buyer in the referral system under a sponsor of the caller's choosing via referrals.addMember(buyer, sponsor) at line 179. The referral chain assignment is irreversible.
Pending
#6 informational Issue
Monthly Reward Period Clock Drifts During Protocol Inactivity
At lines 218–220, nextRewardDrain advances by exactly 30 days only when a purchase triggers the condition. After 90 days of inactivity, the first purchase advances by only one period, leaving the clock 60 days behind real time, distorting monthly reward attribution.
Pending
#7 informational Issue
Foreign Tour Bonus Formula Applies Integer Division First, Causing Systematic Underpayment
At line 488, (amount / 3000e18) * 300e18 performs integer division before multiplication. For any amount between N×3000e18 and (N+1)×3000e18−1, the bonus is N×300e18. Users with up to 2,999 AUSD below a threshold boundary receive zero credit for that portion. The correct formula is (amount * 300e18) / 3000e18.