├── README.md ├── smart-contracts ├── TratokBatch.sol ├── BatchETHSender.sol ├── tratokv1.sol ├── tratok_current.sol └── tratokv2.sol ├── Tratok-blockchain-bridge ├── README.md ├── IERC20.sol ├── ReentrancyGuard.sol ├── MultiSigWallet.sol ├── TratokETHBridge.sol └── TratokBNB.sol └── escrow-smart-contracts ├── TratokEmployeeEscrow.sol └── TratokPromotionEscrow.sol /README.md: -------------------------------------------------------------------------------- 1 | # smart-contracts 2 | The Tratok Token (TRAT) smart contracts. In compliance with Tratok Holding Limited's policy on maximum transparency, copies of the verified smart 3 | contracts found on etherscan are included here. 4 | 5 | # escrow-smart-contracts 6 | The open source code of the smart contracts reprsenting the escrows for promotion programs and staff compensation are shared for 7 | the public to scrutinize at their desire. 8 | 9 | # Tratok-blockchain-bridge 10 | The smart contracts represnting the bridge for migration from Tratok to other blockchains is available for inspection and logic checking. 11 | This coupled with the source code for implementing the multi sig wallet used to mitigate risk. 12 | -------------------------------------------------------------------------------- /smart-contracts/TratokBatch.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.26; 3 | 4 | /** 5 | * @title TratokBatch 6 | * @dev This contract enables batch transfers of Tratok to multiple recipients in one transaction. The purpose for this is to cut down on delays when there are multiple transactions when the ecosystem grows. 7 | */ 8 | contract TratokBatch { 9 | /** 10 | * @dev Executes a batch transfer of Tratok tokens to multiple recipients. 11 | * @param recipients An array of addresses to receive the tokens. 12 | * @param amounts An array of token amounts corresponding to each recipient. 13 | * @notice The lengths of recipients and amounts arrays must be equal. 14 | */ 15 | function batchTransfer(address[] memory recipients, uint256[] memory amounts) public { 16 | // Validate input arrays 17 | require(recipients.length == amounts.length, "Recipients and amounts arrays must have the same length"); 18 | require(recipients.length > 0, "At least one recipient is required"); 19 | 20 | // Interface to interact with the ERC20 token contract 21 | address tokenAddress = 0x99d7a7F4C5551955c4bA5bA3C8965fFD9C869B4c; // Fixed: use address literal 22 | ERC20 erc20 = ERC20(tokenAddress); 23 | 24 | // Perform transfers in a loop 25 | for (uint256 i = 0; i < recipients.length; i++) { 26 | require(erc20.transferFrom(msg.sender, recipients[i], amounts[i]), "Token transfer failed"); 27 | } 28 | } 29 | } 30 | 31 | /** 32 | * @dev Minimal ERC20 interface for interacting with the Tratok token for sending. 33 | */ 34 | interface ERC20 { 35 | function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); 36 | } 37 | -------------------------------------------------------------------------------- /Tratok-blockchain-bridge/README.md: -------------------------------------------------------------------------------- 1 | The following Blockchain Migration bridges are currently under developlemt 2 | 3 | # Ethereum to BNB 4 | This bridge uses locking and minting for migration of Tratok from the Ethereum blockchain to the BNB blockchain. 5 | 6 | For migration from the BNB blockchain to the Ethereum blockchain it uses burning and unlocking. 7 | 8 | The bridge is managed by a dedicated oracle maintained by Tratok. 9 | 10 | Security is enhanced through the use of multisig wallets. 11 | 12 | # Mechanism of Tracking Migration 13 | **Event Monitoring:** 14 | 15 | The oracle continuously monitors events on both blockchains. For instance, it listens for specific events emitted by smart contracts that indicate a lock or mint operation on one blockchain and a burn or unlock operation on the other. 16 | 17 | **Cross-Chain Communication:** 18 | 19 | When a user locks tokens on Blockchain A, the corresponding event is emitted. The oracle captures this event and can then trigger a minting operation on Blockchain B. Similarly, when tokens are burned on Blockchain B, the oracle detects this and can initiate an unlocking operation on Blockchain A. 20 | 21 | **Data Verification:** 22 | 23 | The oracle ensures that the data it relays between the two blockchains is accurate and trustworthy. This is often achieved through consensus mechanisms or by using multiple data sources to confirm the validity of the events being tracked. 24 | 25 | **State Synchronization:** 26 | 27 | The oracle maintains a synchronized state between the two blockchains. It keeps track of how many tokens are locked on Blockchain A and how many are minted on Blockchain B, ensuring that the total supply across both chains remains consistent and that no tokens are created or destroyed without proper authorization. 28 | 29 | # Example Workflow 30 | **Locking Tokens:** 31 | 32 | A user locks 100 TRAT tokens on Blockchain A. The smart contract emits an event indicating that 100 TRAT tokens have been locked. 33 | 34 | **Oracle Notification:** 35 | 36 | The oracle detects this event and verifies it. 37 | 38 | **Minting Tokens:** 39 | 40 | Upon verification, the oracle sends a command to the smart contract on Blockchain B to mint 100 TRAT tokens for the user. 41 | 42 | **Burning Tokens:** 43 | 44 | If the user wants to unlock their tokens, they burn 100 TRAT tokens on Blockchain B. The oracle again monitors this event. 45 | 46 | **Unlocking Tokens:** 47 | 48 | After confirming the burn, the oracle instructs the smart contract on Blockchain A to unlock the corresponding 100 TRAT tokens. 49 | -------------------------------------------------------------------------------- /Tratok-blockchain-bridge/IERC20.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/IERC20.sol) 3 | 4 | pragma solidity ^0.8.20; 5 | 6 | /** 7 | * @dev Interface of the ERC-20 standard as defined in the ERC. 8 | */ 9 | interface IERC20 { 10 | /** 11 | * @dev Emitted when `value` tokens are moved from one account (`from`) to 12 | * another (`to`). 13 | * 14 | * Note that `value` may be zero. 15 | */ 16 | event Transfer(address indexed from, address indexed to, uint256 value); 17 | 18 | /** 19 | * @dev Emitted when the allowance of a `spender` for an `owner` is set by 20 | * a call to {approve}. `value` is the new allowance. 21 | */ 22 | event Approval(address indexed owner, address indexed spender, uint256 value); 23 | 24 | /** 25 | * @dev Returns the value of tokens in existence. 26 | */ 27 | function totalSupply() external view returns (uint256); 28 | 29 | /** 30 | * @dev Returns the value of tokens owned by `account`. 31 | */ 32 | function balanceOf(address account) external view returns (uint256); 33 | 34 | /** 35 | * @dev Moves a `value` amount of tokens from the caller's account to `to`. 36 | * 37 | * Returns a boolean value indicating whether the operation succeeded. 38 | * 39 | * Emits a {Transfer} event. 40 | */ 41 | function transfer(address to, uint256 value) external returns (bool); 42 | 43 | /** 44 | * @dev Returns the remaining number of tokens that `spender` will be 45 | * allowed to spend on behalf of `owner` through {transferFrom}. This is 46 | * zero by default. 47 | * 48 | * This value changes when {approve} or {transferFrom} are called. 49 | */ 50 | function allowance(address owner, address spender) external view returns (uint256); 51 | 52 | /** 53 | * @dev Sets a `value` amount of tokens as the allowance of `spender` over the 54 | * caller's tokens. 55 | * 56 | * Returns a boolean value indicating whether the operation succeeded. 57 | * 58 | * IMPORTANT: Beware that changing an allowance with this method brings the risk 59 | * that someone may use both the old and the new allowance by unfortunate 60 | * transaction ordering. One possible solution to mitigate this race 61 | * condition is to first reduce the spender's allowance to 0 and set the 62 | * desired value afterwards: 63 | * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 64 | * 65 | * Emits an {Approval} event. 66 | */ 67 | function approve(address spender, uint256 value) external returns (bool); 68 | 69 | /** 70 | * @dev Moves a `value` amount of tokens from `from` to `to` using the 71 | * allowance mechanism. `value` is then deducted from the caller's 72 | * allowance. 73 | * 74 | * Returns a boolean value indicating whether the operation succeeded. 75 | * 76 | * Emits a {Transfer} event. 77 | */ 78 | function transferFrom(address from, address to, uint256 value) external returns (bool); 79 | } -------------------------------------------------------------------------------- /smart-contracts/BatchETHSender.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | import "@openzeppelin/contracts/access/Ownable.sol"; 5 | 6 | contract BatchETHSender is Ownable { 7 | // Event to log successful transfers 8 | event TransferBatch( 9 | address indexed sender, 10 | address[] recipients, 11 | uint256 amountPerRecipient, 12 | uint256 timestamp 13 | ); 14 | 15 | // Event to log failed transfers 16 | event TransferFailed( 17 | address indexed recipient, 18 | uint256 amount, 19 | uint256 timestamp 20 | ); 21 | 22 | // Fallback function to accept ETH 23 | receive() external payable { } 24 | 25 | // Constructor sets the deployer as the owner 26 | constructor() Ownable(msg.sender) {} 27 | 28 | /** 29 | * @dev Batch transfer same amount of ETH to multiple addresses 30 | * @param recipients Array of recipient addresses 31 | * @param amountPerRecipient Amount to send to each recipient (in wei) 32 | */ 33 | function batchSendETH( 34 | address[] calldata recipients, 35 | uint256 amountPerRecipient 36 | ) external payable onlyOwner returns (bool) { 37 | // Input validation 38 | require(recipients.length > 0, "No recipients provided"); 39 | require(amountPerRecipient > 0, "Amount must be greater than 0"); 40 | 41 | // Calculate total required amount 42 | uint256 totalRequired = amountPerRecipient * recipients.length; 43 | require(msg.value >= totalRequired, "Insufficient ETH sent"); 44 | 45 | // Validate recipients 46 | for (uint256 i = 0; i < recipients.length; i++) { 47 | require(recipients[i] != address(0), "Invalid recipient address"); 48 | } 49 | 50 | // Process transfers 51 | for (uint256 i = 0; i < recipients.length; i++) { 52 | (bool success, ) = recipients[i].call{value: amountPerRecipient}(""); 53 | 54 | if (!success) { 55 | emit TransferFailed(recipients[i], amountPerRecipient, block.timestamp); 56 | } 57 | } 58 | 59 | // Emit successful batch transfer event 60 | emit TransferBatch(msg.sender, recipients, amountPerRecipient, block.timestamp); 61 | 62 | // Refund any excess ETH sent 63 | if (msg.value > totalRequired) { 64 | (bool refundSuccess, ) = msg.sender.call{value: msg.value - totalRequired}(""); 65 | require(refundSuccess, "Refund failed"); 66 | } 67 | 68 | return true; 69 | } 70 | 71 | /** 72 | * @dev Get contract's current balance 73 | * @return Current ETH balance in wei 74 | */ 75 | function getContractBalance() external view returns (uint256) { 76 | return address(this).balance; 77 | } 78 | 79 | /** 80 | * @dev Emergency withdrawal function for stuck ETH 81 | * Only owner can withdraw 82 | */ 83 | function withdraw() external onlyOwner { 84 | uint256 balance = address(this).balance; 85 | require(balance > 0, "No ETH to withdraw"); 86 | (bool success, ) = msg.sender.call{value: balance}(""); 87 | require(success, "Withdrawal failed"); 88 | } 89 | 90 | // Allow owner to transfer ETH directly to the contract if needed 91 | function deposit() external payable onlyOwner { 92 | require(msg.value > 0, "No ETH sent"); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /escrow-smart-contracts/TratokEmployeeEscrow.sol: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-License-Identifier: MIT 3 | 4 | This is the escrow smart contract for Tratok employee compensation of tokens. 5 | This immutable contract allows the public to see the team's commitment to honoring their no-sell clauses as well as full public transparency on all compensation. 6 | 7 | @version "1.0" 8 | @developer "Tratok Team" 9 | @date "15 December 2024" 10 | @thoughts "Bringing more accountability and transparency to the industry and setting an example of the right way to do things!" 11 | */ 12 | pragma solidity ^0.8.0; 13 | 14 | interface IERC20 { 15 | function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); 16 | function transfer(address recipient, uint256 amount) external returns (bool); 17 | function balanceOf(address account) external view returns (uint256); 18 | } 19 | 20 | contract TratokEmployeeEscrow { 21 | struct Escrow { 22 | address deliveryAddress; 23 | uint256 releaseTime; 24 | uint256 amount; 25 | bool released; 26 | } 27 | 28 | IERC20 public token; 29 | mapping(uint256 => Escrow) public escrows; 30 | uint256 public escrowCount; 31 | 32 | constructor() { 33 | token = IERC20(0x35bC519E9fe5F04053079e8a0BF2a876D95D2B33); 34 | } 35 | 36 | 37 | // Method to create each invidual escrow 38 | function deposit(address _deliveryAddress, uint256 _days, uint256 _amount) external { 39 | 40 | // Ensure the amount is greater than zero 41 | require(_amount > 0, "Amount must be greater than 0"); 42 | 43 | // Ensure the deposit has been successful 44 | require(token.transferFrom(msg.sender, address(this), _amount), "Transfer failed"); 45 | 46 | // Create the escrow 47 | escrows[escrowCount] = Escrow({ 48 | deliveryAddress: _deliveryAddress, 49 | releaseTime: block.timestamp + (_days * 1 days), 50 | amount: _amount, 51 | released: false 52 | }); 53 | 54 | // Add additional escrow count 55 | escrowCount++; 56 | } 57 | 58 | // Method to release the escrow. It can only be called when the relevant time has elapsed 59 | function release(uint256 escrowId) external { 60 | Escrow storage escrow = escrows[escrowId]; 61 | 62 | // Ensure escrow has not already been released 63 | require(!escrow.released, "Tokens already released"); 64 | 65 | // Ensure escrow time hold has passed 66 | require(block.timestamp >= escrow.releaseTime, "Tokens are still locked"); 67 | 68 | // Ensure that sufficient tokens exist for the release 69 | require(escrow.amount > 0, "No tokens to release"); 70 | 71 | // Transfer the tokens first 72 | require(token.transfer(escrow.deliveryAddress, escrow.amount), "Transfer failed"); 73 | 74 | // Mark as released only after the transfer is successful 75 | escrow.released = true; 76 | } 77 | 78 | // Method to show the overall TRAT balance of the contract 79 | function getBalance() external view returns (uint256) { 80 | return token.balanceOf(address(this)); 81 | } 82 | 83 | // Method to show escrow details for each individual escrow 84 | function getEscrowDetails(uint256 escrowId) external view returns (address, uint256, uint256, bool) { 85 | Escrow storage escrow = escrows[escrowId]; 86 | return (escrow.deliveryAddress, escrow.releaseTime, escrow.amount, escrow.released); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /Tratok-blockchain-bridge/ReentrancyGuard.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // OpenZeppelin Contracts (last updated v5.1.0) (utils/ReentrancyGuard.sol) 3 | 4 | pragma solidity ^0.8.20; 5 | 6 | /** 7 | * @dev Contract module that helps prevent reentrant calls to a function. 8 | * 9 | * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier 10 | * available, which can be applied to functions to make sure there are no nested 11 | * (reentrant) calls to them. 12 | * 13 | * Note that because there is a single `nonReentrant` guard, functions marked as 14 | * `nonReentrant` may not call one another. This can be worked around by making 15 | * those functions `private`, and then adding `external` `nonReentrant` entry 16 | * points to them. 17 | * 18 | * TIP: If EIP-1153 (transient storage) is available on the chain you're deploying at, 19 | * consider using {ReentrancyGuardTransient} instead. 20 | * 21 | * TIP: If you would like to learn more about reentrancy and alternative ways 22 | * to protect against it, check out our blog post 23 | * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. 24 | */ 25 | abstract contract ReentrancyGuard { 26 | // Booleans are more expensive than uint256 or any type that takes up a full 27 | // word because each write operation emits an extra SLOAD to first read the 28 | // slot's contents, replace the bits taken up by the boolean, and then write 29 | // back. This is the compiler's defense against contract upgrades and 30 | // pointer aliasing, and it cannot be disabled. 31 | 32 | // The values being non-zero value makes deployment a bit more expensive, 33 | // but in exchange the refund on every call to nonReentrant will be lower in 34 | // amount. Since refunds are capped to a percentage of the total 35 | // transaction's gas, it is best to keep them low in cases like this one, to 36 | // increase the likelihood of the full refund coming into effect. 37 | uint256 private constant NOT_ENTERED = 1; 38 | uint256 private constant ENTERED = 2; 39 | 40 | uint256 private _status; 41 | 42 | /** 43 | * @dev Unauthorized reentrant call. 44 | */ 45 | error ReentrancyGuardReentrantCall(); 46 | 47 | constructor() { 48 | _status = NOT_ENTERED; 49 | } 50 | 51 | /** 52 | * @dev Prevents a contract from calling itself, directly or indirectly. 53 | * Calling a `nonReentrant` function from another `nonReentrant` 54 | * function is not supported. It is possible to prevent this from happening 55 | * by making the `nonReentrant` function external, and making it call a 56 | * `private` function that does the actual work. 57 | */ 58 | modifier nonReentrant() { 59 | _nonReentrantBefore(); 60 | _; 61 | _nonReentrantAfter(); 62 | } 63 | 64 | function _nonReentrantBefore() private { 65 | // On the first call to nonReentrant, _status will be NOT_ENTERED 66 | if (_status == ENTERED) { 67 | revert ReentrancyGuardReentrantCall(); 68 | } 69 | 70 | // Any calls to nonReentrant after this point will fail 71 | _status = ENTERED; 72 | } 73 | 74 | function _nonReentrantAfter() private { 75 | // By storing the original value once again, a refund is triggered (see 76 | // https://eips.ethereum.org/EIPS/eip-2200) 77 | _status = NOT_ENTERED; 78 | } 79 | 80 | /** 81 | * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a 82 | * `nonReentrant` function in the call stack. 83 | */ 84 | function _reentrancyGuardEntered() internal view returns (bool) { 85 | return _status == ENTERED; 86 | } 87 | } -------------------------------------------------------------------------------- /escrow-smart-contracts/TratokPromotionEscrow.sol: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-License-Identifier: MIT 3 | 4 | This is the escrow smart contract for Tratok Promotion Program Participants. 5 | This immutable contract allows the public to see to keep a track of rewards distributed as well as provide verification and guarantees of receiving their awards in good faith. 6 | 7 | @version "1.0" 8 | @developer "Tratok Team" 9 | @date "19 December 2024" 10 | @thoughts "Once a Tratokian always a Tratokian!" 11 | */ 12 | 13 | pragma solidity ^0.8.0; 14 | 15 | interface IERC20 { 16 | function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); 17 | function transfer(address recipient, uint256 amount) external returns (bool); 18 | function balanceOf(address account) external view returns (uint256); 19 | } 20 | 21 | contract PromotionEscrow { 22 | struct Escrow { 23 | address deliveryAddress; 24 | uint256 releaseTime; 25 | uint256 amount; 26 | bool released; 27 | } 28 | 29 | IERC20 public token; 30 | mapping(uint256 => Escrow) public escrows; 31 | uint256 public escrowCount; 32 | uint256 public constant RELEASE_TIMESTAMP = 1743292800; // Fixed release timestamp for 30 March 2025 33 | 34 | /* 35 | * The constructor sets the Token for the escrow as Tratok, address: "0x35bC519E9fe5F04053079e8a0BF2a876D95D2B33". 36 | * 37 | */ 38 | constructor() { 39 | token = IERC20(0x35bC519E9fe5F04053079e8a0BF2a876D95D2B33); 40 | } 41 | 42 | /* 43 | * Method to create multiple escrows in one transaction. 44 | * This approach is used to not only save time but also significantly reduce gas costs. 45 | * "While testing the concept, creating 500 records in such a way saves >17,000,000 gas compared to individual escrow deposits" - Moses 46 | */ 47 | function deposit(address[] calldata _deliveryAddresses, uint256[] calldata _amounts) external { 48 | require(_deliveryAddresses.length == _amounts.length, "Arrays must be of equal length"); 49 | 50 | uint256 totalAmount = 0; 51 | for (uint256 i = 0; i < _amounts.length; i++) { 52 | require(_amounts[i] > 0, "Amount must be greater than 0"); 53 | totalAmount += _amounts[i]; 54 | } 55 | 56 | // Ensure the total deposit has been successful 57 | require(token.transferFrom(msg.sender, address(this), totalAmount), "Transfer failed"); 58 | 59 | for (uint256 i = 0; i < _deliveryAddresses.length; i++) { 60 | escrows[escrowCount] = Escrow({ 61 | deliveryAddress: _deliveryAddresses[i], 62 | releaseTime: RELEASE_TIMESTAMP, 63 | amount: _amounts[i], 64 | released: false 65 | }); 66 | 67 | escrowCount++; 68 | } 69 | } 70 | 71 | /* 72 | * Method to release all escrows at once. 73 | * This approach is used as it not only is more time efficient and cost efficient but also ensures all participants are rewarded at the same time for fairness. 74 | * "I asked the developmer to ensure anyone could call this function once the time period elapses. I wonder if the public will be faster than us." - Mohammed 75 | */ 76 | function releaseAll() external { 77 | require(block.timestamp >= RELEASE_TIMESTAMP, "Tokens are still locked"); 78 | 79 | for (uint256 i = 0; i < escrowCount; i++) { 80 | Escrow storage escrow = escrows[i]; 81 | if (!escrow.released && escrow.amount > 0) { 82 | // Transfer the tokens 83 | require(token.transfer(escrow.deliveryAddress, escrow.amount), "Transfer failed"); 84 | // Mark as released 85 | escrow.released = true; 86 | } 87 | } 88 | } 89 | 90 | // Method to show the overall TRAT balance of the contract 91 | function getBalance() external view returns (uint256) { 92 | return token.balanceOf(address(this)); 93 | } 94 | 95 | // Method to show escrow details for each individual escrow 96 | function getEscrowDetails(uint256 escrowId) external view returns (address, uint256, uint256, bool) { 97 | Escrow storage escrow = escrows[escrowId]; 98 | return (escrow.deliveryAddress, escrow.releaseTime, escrow.amount, escrow.released); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /Tratok-blockchain-bridge/MultiSigWallet.sol: -------------------------------------------------------------------------------- 1 | /// SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | import "./ReentrancyGuard.sol"; 5 | 6 | contract MultiSigWallet is ReentrancyGuard { 7 | address[] public owners; 8 | uint256 public required; 9 | uint256 public transactionCount; 10 | mapping(uint256 => Transaction) public transactions; 11 | mapping(uint256 => mapping(address => bool)) public confirmations; 12 | 13 | struct Transaction { 14 | address destination; 15 | uint256 value; 16 | bytes data; 17 | bool executed; 18 | } 19 | 20 | event Confirmation(address indexed sender, uint256 indexed transactionId); 21 | event Revocation(address indexed sender, uint256 indexed transactionId); 22 | event Submission(uint256 indexed transactionId); 23 | event Execution(uint256 indexed transactionId); 24 | event ExecutionFailure(uint256 indexed transactionId); 25 | event Deposit(address indexed sender, uint256 value); 26 | event OwnerAddition(address indexed owner); 27 | event OwnerRemoval(address indexed owner); 28 | event RequirementChange(uint256 required); 29 | 30 | modifier onlyOwner() { 31 | require(isOwner(msg.sender), "Only owners can call this function"); 32 | _; 33 | } 34 | 35 | modifier validRequirement(uint256 ownerCount, uint256 _required) { 36 | require(ownerCount > 0 && _required > 0 && _required <= ownerCount, "Invalid requirement"); 37 | _; 38 | } 39 | 40 | constructor(address[] memory _owners, uint256 _required) validRequirement(_owners.length, _required) { 41 | for (uint256 i = 0; i < _owners.length; i++) { 42 | require(!isOwner(_owners[i]) && _owners[i] != address(0), "Invalid owner"); 43 | owners.push(_owners[i]); 44 | } 45 | required = _required; 46 | } 47 | 48 | function isOwner(address _addr) public view returns (bool) { 49 | for (uint256 i = 0; i < owners.length; i++) { 50 | if (owners[i] == _addr) { 51 | return true; 52 | } 53 | } 54 | return false; 55 | } 56 | 57 | function submitTransaction(address destination, uint256 value, bytes memory data) public onlyOwner returns (uint256) { 58 | uint256 transactionId = addTransaction(destination, value, data); 59 | confirmTransaction(transactionId); 60 | return transactionId; 61 | } 62 | 63 | function confirmTransaction(uint256 transactionId) public onlyOwner { 64 | require(transactions[transactionId].destination != address(0), "Transaction does not exist"); 65 | require(!confirmations[transactionId][msg.sender], "Transaction already confirmed by this owner"); 66 | 67 | confirmations[transactionId][msg.sender] = true; 68 | emit Confirmation(msg.sender, transactionId); 69 | 70 | executeTransaction(transactionId); 71 | } 72 | 73 | function addTransaction(address destination, uint256 value, bytes memory data) internal returns (uint256) { 74 | uint256 transactionId = transactionCount; 75 | transactions[transactionId] = Transaction({ 76 | destination: destination, 77 | value: value, 78 | data: data, 79 | executed: false 80 | }); 81 | transactionCount += 1; 82 | emit Submission(transactionId); 83 | return transactionId; 84 | } 85 | 86 | // Use nonReentrant to prevent reentrancy attacks 87 | function executeTransaction(uint256 transactionId) public nonReentrant { 88 | require(!transactions[transactionId].executed, "Transaction already executed"); 89 | Transaction storage t = transactions[transactionId]; 90 | 91 | if (isConfirmed(transactionId)) { 92 | t.executed = true; 93 | (bool success, ) = t.destination.call{value: t.value}(t.data); 94 | if (success) { 95 | emit Execution(transactionId); 96 | } else { 97 | emit ExecutionFailure(transactionId); 98 | t.executed = false; 99 | } 100 | } 101 | } 102 | 103 | // Improved isConfirmed to ensure correct counting of confirmations 104 | function isConfirmed(uint256 transactionId) public view returns (bool) { 105 | uint256 count = 0; 106 | for (uint256 i = 0; i < owners.length; i++) { 107 | if (confirmations[transactionId][owners[i]]) { 108 | count += 1; 109 | if (count >= required) { 110 | return true; 111 | } 112 | } 113 | } 114 | return false; 115 | } 116 | 117 | receive() external payable { 118 | emit Deposit(msg.sender, msg.value); 119 | } 120 | 121 | function encodeCall(address contractAddress, bytes4 functionSignature, bytes memory params) internal pure returns (bytes memory) { 122 | return abi.encodeWithSelector(functionSignature, params); 123 | } 124 | 125 | function mintTokens(address to, uint256 amount) public onlyOwner { 126 | bytes memory data = encodeCall(address(this), bytes4(keccak256("mint(address,uint256)")), abi.encode(to, amount)); 127 | submitTransaction(address(this), 0, data); 128 | } 129 | 130 | function unlockTokens(address bridge, address user, uint256 amount) public onlyOwner { 131 | bytes memory data = encodeCall(bridge, bytes4(keccak256("unlockTokens(address,uint256)")), abi.encode(user, amount)); 132 | submitTransaction(bridge, 0, data); 133 | } 134 | 135 | // Owner Management Functions 136 | 137 | /** 138 | * @dev Adds a new owner to the wallet. 139 | * @param owner Address of the new owner. 140 | */ 141 | function addOwner(address owner) public onlyOwner { 142 | require(!isOwner(owner), "Owner already exists"); 143 | require(owner != address(0), "Invalid owner address"); 144 | require(owners.length + 1 > required, "Cannot add owner if it would make the requirement invalid"); 145 | 146 | owners.push(owner); 147 | emit OwnerAddition(owner); 148 | } 149 | 150 | /** 151 | * @dev Removes an owner from the wallet. 152 | * @param owner Address of the owner to remove. 153 | */ 154 | function removeOwner(address owner) public onlyOwner { 155 | require(isOwner(owner), "Not an owner"); 156 | require(owners.length - 1 >= required, "Cannot remove owner if it would make the requirement invalid"); 157 | 158 | for (uint256 i = 0; i < owners.length; i++) { 159 | if (owners[i] == owner) { 160 | owners[i] = owners[owners.length - 1]; 161 | owners.pop(); 162 | emit OwnerRemoval(owner); 163 | return; 164 | } 165 | } 166 | revert("Owner not found"); 167 | } 168 | 169 | /** 170 | * @dev Changes the number of required confirmations. 171 | * @param _required New number of confirmations required. 172 | */ 173 | function changeRequirement(uint256 _required) public onlyOwner { 174 | require(_required > 0 && _required <= owners.length, "Invalid requirement"); 175 | required = _required; 176 | emit RequirementChange(_required); 177 | } 178 | } -------------------------------------------------------------------------------- /smart-contracts/tratokv1.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^ 0.4 .4; 2 | 3 | /* 4 | This is the smart contract for the ERC 20 standard Tratok token. 5 | During development of the smart contract, active attention was paid to make the contract as simple as possible. 6 | As the majority of functions are simple addition and subtraction of existing balances, we have been able to make the contract very lightweight. 7 | This has the added advantage of reducing gas costs and ensuring that transaction fees remain low. 8 | The smart contract has been made publically available, keeping with the team's philosophy of transparency. 9 | 10 | @version "1.0" 11 | @developer "Tratok Team" 12 | @date "12 February 2017" 13 | @thoughts "207 lines that can change the travel and tourism industry!. Good luck!" 14 | */ 15 | 16 | /* 17 | * Use of the SafeMath Library prevents malicious input. For security consideration, the 18 | * smart contaract makes use of .add() and .sub() rather than += and -= 19 | */ 20 | 21 | library SafeMath { 22 | 23 | //Ensures that b is greater than a to handle negatives. 24 | function sub(uint256 a, uint256 b) internal returns (uint256) { 25 | assert(b <= a); 26 | return a - b; 27 | } 28 | 29 | //Ensures that the sum of two values is greater than the intial value. 30 | function add(uint256 a, uint256 b) internal returns (uint256) { 31 | uint256 c = a + b; 32 | assert(c >= a); 33 | return c; 34 | } 35 | } 36 | 37 | /* 38 | * ERC20 Standard will be used 39 | * see https://github.com/ethereum/EIPs/issues/20 40 | */ 41 | 42 | contract ERC20 { 43 | //the total supply of tokens 44 | uint public totalSupply; 45 | 46 | //@return Returns the total amount of Tratok tokens in existence. The amount remains capped at the pre-created 100 Billion. 47 | function totalSupply() constant returns(uint256 supply){} 48 | 49 | /* 50 | @param _owner The address of the wallet which needs to be queried for the amount of Tratok held. 51 | @return Returns the balance of Tratok tokens for the relevant address. 52 | */ 53 | function balanceOf(address who) constant returns(uint); 54 | 55 | /* 56 | The transfer function which takes the address of the recipient and the amount of Tratok needed to be sent and complete the transfer 57 | @param _to The address of the recipient (usually a "service provider") who will receive the Tratok. 58 | @param _value The amount of Tratok that needs to be transferred. 59 | @return Returns a boolean value to verify the transaction has succeeded or failed. 60 | */ 61 | function transfer(address to, uint value) returns(bool ok); 62 | 63 | /* 64 | This function will, conditional of being approved by the holder, send a determined amount of tokens to a specified address 65 | @param _from The address of the Tratok sender. 66 | @param _to The address of the Tratok recipient. 67 | @param _value The volume (amount of Tratok which will be sent). 68 | @return Returns a boolean value to verify the transaction has succeeded or failed. 69 | */ 70 | function transferFrom(address from, address to, uint value) returns(bool ok); 71 | 72 | /* 73 | This function approves the transaction and costs 74 | @param _spender The address of the account which is able to transfer the tokens 75 | @param _value The amount of wei to be approved for transfer 76 | @return Whether the approval was successful or not 77 | */ 78 | function approve(address spender, uint value) returns(bool ok); 79 | 80 | /* 81 | This function determines how many Tratok remain and how many can be spent. 82 | @param _owner The address of the account owning the Tratok tokens 83 | @param _spender The address of the account which is authorized to spend the Tratok tokens 84 | @return Amount of Tratok tokens which remain available and therefore, which can be spent 85 | */ 86 | function allowance(address owner, address spender) constant returns(uint); 87 | 88 | 89 | event Transfer(address indexed from, address indexed to, uint value); 90 | event Approval(address indexed owner, address indexed spender, uint value); 91 | 92 | } 93 | 94 | /* 95 | *This is a basic contract held by one owner and prevents function execution if attempts to run are made by anyone other than the owner of the contract 96 | */ 97 | 98 | contract Ownable { 99 | address public owner; 100 | 101 | function Ownable() { 102 | owner = msg.sender; 103 | } 104 | 105 | modifier onlyOwner() { 106 | if (msg.sender != owner) { 107 | throw; 108 | } 109 | _; 110 | } 111 | 112 | function transferOwnership(address newOwner) onlyOwner { 113 | if (newOwner != address(0)) { 114 | owner = newOwner; 115 | } 116 | } 117 | 118 | } 119 | 120 | contract StandardToken is ERC20, Ownable { 121 | using SafeMath for uint256; 122 | function transfer(address _to, uint256 _value) returns(bool success) { 123 | if (balances[msg.sender] >= _value && _value > 0) { 124 | balances[msg.sender] = balances[msg.sender].sub(_value); 125 | balances[_to] = balances[_to].add(_value); 126 | Transfer(msg.sender, _to, _value); 127 | return true; 128 | } else { 129 | return false; 130 | } 131 | } 132 | 133 | function transferFrom(address _from, address _to, uint256 _value) returns(bool success) { 134 | if (balances[_from] >= _value && allowed[_from][msg.sender] >= _value && _value > 0) { 135 | balances[_to] = balances[_to].add(_value); 136 | balances[_from] = balances[_from].sub(_value); 137 | allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value); 138 | Transfer(_from, _to, _value); 139 | return true; 140 | } else { 141 | return false; 142 | } 143 | } 144 | 145 | function balanceOf(address _owner) constant returns(uint256 balance) { 146 | return balances[_owner]; 147 | } 148 | 149 | function approve(address _spender, uint256 _value) returns(bool success) { 150 | allowed[msg.sender][_spender] = _value; 151 | Approval(msg.sender, _spender, _value); 152 | return true; 153 | } 154 | 155 | function allowance(address _owner, address _spender) constant returns(uint256 remaining) { 156 | return allowed[_owner][_spender]; 157 | } 158 | 159 | mapping(address => uint256) balances; 160 | mapping(address => mapping(address => uint256)) allowed; 161 | uint256 public totalSupply; 162 | } 163 | 164 | contract Tratok is StandardToken { 165 | 166 | function() { 167 | throw; 168 | } 169 | 170 | /* 171 | * The public variables of the token. Inclduing the name, the symbol and the number of decimals. 172 | */ 173 | string public name; 174 | uint8 public decimals; 175 | string public symbol; 176 | string public version = 'H1.0'; 177 | 178 | /* 179 | * Declaring the customized details of the token. The token will be called Tratok, with a total supply of 100 billion tokens. 180 | * It will feature five decimal places and have the symbol TRAT. 181 | */ 182 | 183 | function Tratok() { 184 | 185 | //we will create 100 Billion Coins and send them to the creating wallet. 186 | balances[msg.sender] = 10000000000000000; 187 | totalSupply = 10000000000000000; 188 | name = "Tratok"; 189 | decimals = 5; 190 | symbol = "TRAT"; 191 | } 192 | 193 | /* 194 | *Approve and enact the contract. 195 | * 196 | */ 197 | function approveAndCall(address _spender, uint256 _value, bytes _extraData) returns(bool success) { 198 | allowed[msg.sender][_spender] = _value; 199 | Approval(msg.sender, _spender, _value); 200 | 201 | //If the call fails, result to "vanilla" approval. 202 | if (!_spender.call(bytes4(bytes32(sha3("receiveApproval(address,uint256,address,bytes)"))), msg.sender, _value, this, _extraData)) { 203 | throw; 204 | } 205 | return true; 206 | } 207 | } 208 | -------------------------------------------------------------------------------- /Tratok-blockchain-bridge/TratokETHBridge.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | /* 5 | * Explanation: 6 | * 7 | * This is the smart contract used as a bridge for migrating Tratok (TRAT) from the Ethereum 8 | * blockchain to the BNB blockchain and vice versa. 9 | * 10 | * Methodology: 11 | * 12 | * The contract is initialized with the address of the Tratok token (TRAT), allowing it to interact 13 | * with the existing token. 14 | * It features a locking functionality so users can lock their TRAT tokens by calling the lockTokens 15 | * function, which transfers the specified amount of tokens from the user's address to the contract. 16 | * The contract then emits a TokensLocked event whenever tokens are locked, which is monitored by 17 | * Tratok's off-chain oracle to trigger the minting of BEP20 tokens on BNB at the desired address of 18 | * of the user. 19 | * 20 | * Fail safe: 21 | * 22 | * The admin (the address that deployed the contract) can withdraw any locked tokens if necessary. 23 | * In case of a malfunction or unexpected issue with the contract, the admin can withdraw tokens to 24 | * prevent loss or misuse. This feature acts as a safety net, allowing the admin to respond quickly to 25 | * emergencies. 26 | * 27 | * Risks: 28 | * 29 | * Users may fall victim to phishing attacks where malicious actors create fake interfaces or contracts 30 | * that mimic the legitimate locking contract. This can lead to users inadvertently sending funds to the 31 | * wrong address or interacting with a fraudulent contract. This can be mitigated by using the official 32 | * bridge portal. https://bridge.tratok.com 33 | * 34 | * The contract grants significant powers to the admin, including the ability to unlock tokens and withdraw 35 | * ETH fees. If the admin's private key is compromised, an attacker could gain control over the contract, 36 | * potentially draining funds or manipulating token unlocks. This is mitigated through best security 37 | * practices including making the admin wallet a Multi-Signature Wallet which requires multiple private 38 | * keys to authorize critical actions, such as unlocking tokens or withdrawing ETH fees. By distributing 39 | * control among several trusted parties, the risk of a single compromised key leading to fund loss is 40 | * significantly reduced. In addition in case of a key being compromised, it permisions can be revoked mitigating any damage. 41 | * 42 | * Sustainability: 43 | * 44 | * To ensure sustainability of the bridge and prevent abuse the contract collects a fee every time a migration from 45 | * the Ethereum blockchain to BNB blockchain is performed. This fee can be changed to reflect network 46 | * congestion via the setEthFee method. 47 | * 48 | * @version "1.2" 49 | * @developer "Tratok Team" 50 | * @date "12 May 2025" 51 | * @thoughts "The Worlds Travel Token Needs To Be On Every Global Blockchain!" 52 | */ 53 | 54 | import "./IERC20.sol"; 55 | import "./MultiSigWallet.sol"; 56 | 57 | contract TratokBNBBridge { 58 | IERC20 public token; 59 | MultiSigWallet public multiSigWallet; 60 | uint256 public ethFee; 61 | uint256 public tokensLocked; 62 | 63 | event TokensLocked(address indexed user, uint256 amount); 64 | event TokensUnlocked(address indexed user, uint256 amount); 65 | event FeeUpdated(uint256 newFee); 66 | event AdminWithdrawn(uint256 amount); 67 | event ETHWithdrawn(address indexed recipient, uint256 amount); 68 | 69 | constructor(address[] memory owners, uint256 requiredSignatures) { 70 | // Set the address as the Tratok Token: "0x35bC519E9fe5F04053079e8a0BF2a876D95D2B33" 71 | token = IERC20(0x35bC519E9fe5F04053079e8a0BF2a876D95D2B33); 72 | 73 | // Create a new MultiSigWallet within the constructor 74 | multiSigWallet = new MultiSigWallet(owners, requiredSignatures); 75 | } 76 | 77 | /* 78 | * Function to lock TRAT tokens in the contract. This method is called when someone wishes to migrate Tratok (TRAT) 79 | * from the Ethereum blockchain to the BNB blockchain. Locking the tokens and removing them from supply before minting 80 | * an equal amount of tokens on the BNB blockchain ensures the circulating supply remains unchanged. 81 | */ 82 | 83 | function lockTokens(uint256 amount) external payable { 84 | // Ensure the amount is positive 85 | require(amount > 0, "TRAT amount must be greater than zero"); 86 | 87 | // Check if the user has sent enough ETH to cover the fee 88 | require(msg.value >= ethFee, "Insufficient ETH sent to cover the migration fee"); 89 | 90 | // Transfer TRAT tokens from the user to the contract 91 | require(token.transferFrom(msg.sender, address(this), amount), "Failed to transfer TRAT from user to contract"); 92 | tokensLocked += amount; 93 | 94 | // Emit an event indicating tokens have been locked 95 | emit TokensLocked(msg.sender, amount); 96 | 97 | // If the user sent more than the fee, refund the excess 98 | if (msg.value > ethFee) { 99 | (bool success, ) = payable(msg.sender).call{value: msg.value - ethFee}(""); 100 | require(success, "Failed to refund excess ETH to user"); 101 | } 102 | } 103 | 104 | /* 105 | * Function to unlock TRAT tokens and release them from the contract. This method is called when 106 | * someone wishes to migrate Tratok (TRAT) from the BNB blockchain to the Ethereum blockchain. 107 | * The TRAT on BNB is burned beforehand in order to ensure that the circulating supply remains 108 | * the same. 109 | */ 110 | function unlockTokens(address user, uint256 amount) external { 111 | require(msg.sender == address(multiSigWallet), "Only the admin (MultiSigWallet) can unlock tokens"); 112 | require(tokensLocked >= amount, "Not enough locked tokens in contract to unlock"); 113 | 114 | // Transfer tokens to the user 115 | require(token.transfer(user, amount), "Failed to transfer unlocked TRAT to user"); 116 | tokensLocked -= amount; 117 | 118 | emit TokensUnlocked(user, amount); 119 | } 120 | 121 | /* 122 | * This function allows the admin to withdraw any locked TRAT tokens from the contract. 123 | * It checks that the caller is the admin and transfers the specified amount of tokens 124 | * to the admin's address. This is an important function to ensure tokens are not lost from circulation 125 | * in the event of bridge failure or accidental calling of lockTokens function by the public. 126 | */ 127 | function withdrawTokens(uint256 amount) external { 128 | // Ensure only admin can withdraw locked tokens 129 | require(msg.sender == address(multiSigWallet), "Only the admin (MultiSigWallet) can withdraw tokens"); 130 | 131 | // Transfer tokens to admin 132 | require(token.transfer(address(multiSigWallet), amount), "Failed to transfer tokens to admin"); 133 | emit AdminWithdrawn(amount); 134 | } 135 | 136 | // Function for the admin to withdraw any ETH collected as fees 137 | function withdrawETH(address payable recipient) external { 138 | require(msg.sender == address(multiSigWallet), "Only the admin (MultiSigWallet) can withdraw ETH"); 139 | require(recipient != address(0), "Invalid recipient address"); 140 | uint256 balance = address(this).balance; 141 | require(balance > 0, "No ETH available to withdraw"); 142 | (bool success, ) = recipient.call{value: balance}(""); 143 | require(success, "Failed to send ETH to recipient"); 144 | emit ETHWithdrawn(recipient, balance); 145 | } 146 | 147 | // Function to set a new ETH fee (only callable by admin) 148 | function setEthFee(uint256 newFee) external { 149 | require(msg.sender == address(multiSigWallet), "Only admin can set fee"); 150 | ethFee = newFee; 151 | emit FeeUpdated(newFee); 152 | } 153 | 154 | // Function to get the current ETH fee 155 | function getEthFee() external view returns (uint256) { 156 | return ethFee; 157 | } 158 | 159 | // Function to check the contract's ETH balance 160 | function checkETHBalance() external view returns (uint256) { 161 | return address(this).balance; 162 | } 163 | 164 | // Allow contract to receive ETH 165 | receive() external payable {} 166 | } 167 | -------------------------------------------------------------------------------- /smart-contracts/tratok_current.sol: -------------------------------------------------------------------------------- 1 | /** 2 | *Submitted for verification at Etherscan.io on 2024-08-18 3 | */ 4 | 5 | // SPDX-License-Identifier: MIT 6 | pragma solidity ^ 0.8.26; 7 | 8 | /* 9 | This is the fourth-generation smart contract for the ERC 20 standard Tratok token. 10 | During the development of the smart contract, active attention was paid to make the contract as simple as possible. 11 | As the majority of functions are simple addition and subtraction of existing balances, we have been able to make the contract very lightweight. 12 | This has the added advantage of reducing gas costs and ensuring that transaction fees remain low. 13 | The smart contract has been made publically available, keeping with the team's philosophy of transparency. 14 | This is an update on the third generation smart contract which can be found at 0xe225aca29524bb65fd82c79a9602f3b4f9c6fe3f. 15 | The contract has been updated to in response to adhering to best practices, increasing security and paying attention to community wishes. 16 | 17 | @version "1.3" 18 | @developer "Tratok Team" 19 | @date "8 August 2024" 20 | @thoughts "As always we will evolve at the forefront and strive to serve the interests of our users" 21 | */ 22 | 23 | /* 24 | * Use of the SafeMath Library prevents malicious input. For security consideration, the 25 | * smart contract makes use of .add() and .sub() rather than += and -= 26 | */ 27 | 28 | 29 | library SafeMath { 30 | // Ensures that b is less than or equal to a to handle negatives. 31 | function sub(uint256 a, uint256 b) internal pure returns (uint256) { 32 | require(b <= a, "Subtraction overflow"); 33 | return a - b; 34 | } 35 | 36 | // Ensures that the sum of two values does not overflow. 37 | function add(uint256 a, uint256 b) internal pure returns (uint256) { 38 | uint256 c = a + b; 39 | require(c >= a, "Addition overflow"); 40 | return c; 41 | } 42 | } 43 | 44 | 45 | abstract contract ERC20 { 46 | //the total supply of tokens 47 | 48 | //@return Returns the total amount of Tratok tokens in existence. The amount remains capped at the pre-created 100 Billion. 49 | function totalSupply() public view virtual returns (uint256); 50 | 51 | /* 52 | @param account The address of the wallet which needs to be queried for the amount of Tratok held. 53 | @return Returns the balance of Tratok tokens for the relevant address. 54 | */ 55 | function balanceOf(address account) public view virtual returns (uint256); 56 | 57 | /* 58 | The transfer function which takes the address of the recipient and the amount of Tratok needed to be sent and complete the transfer 59 | @param recepient The address of the recipient (usually a "service provider") who will receive the Tratok. 60 | @param amount The amount of Tratok that needs to be transferred. 61 | @return Returns a boolean value to verify the transaction has succeeded or failed. 62 | */ 63 | function transfer(address recipient, uint256 amount) external virtual returns (bool); 64 | 65 | /* 66 | This function will, conditional of being approved by the holder, send a determined amount of tokens to a specified address 67 | @param sender The address of the Tratok sender. 68 | @param recepient The address of the Tratok recipient. 69 | @param amount The volume (amount of Tratok which will be sent). 70 | @return Returns a boolean value to verify the transaction has succeeded or failed. 71 | */ 72 | function transferFrom(address sender, address recipient, uint256 amount) external virtual returns (bool); 73 | 74 | /* 75 | This function approves the transaction and costs 76 | @param spender The address of the account which is able to transfer the tokens 77 | @param amount The amount of wei to be approved for transfer 78 | @return Whether the approval was successful or not 79 | */ 80 | function approve(address spender, uint256 amount) external virtual returns (bool); 81 | 82 | /* 83 | This function determines how many Tratok remain and how many can be spent. 84 | @param owner The address of the account owning the Tratok tokens 85 | @param spender The address of the account which is authorized to spend the Tratok tokens 86 | @return Amount of Tratok tokens which remain available and therefore, which can be spent 87 | */ 88 | function allowance(address owner, address spender) public view virtual returns (uint256); 89 | 90 | event Transfer(address indexed from, address indexed to, uint256 value); 91 | event Approval(address indexed owner, address indexed spender, uint256 value); 92 | 93 | } 94 | 95 | /* 96 | *This is a basic contract held by one owner and prevents function execution if attempts to run are made by anyone other than the owner of the contract 97 | */ 98 | 99 | contract Ownable { 100 | address public _owner; 101 | 102 | event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); 103 | 104 | constructor() { 105 | _owner = msg.sender; 106 | } 107 | 108 | modifier onlyOwner() { 109 | require(msg.sender == _owner, "Caller is not the owner"); 110 | _; 111 | } 112 | 113 | function transferOwnership(address newOwner) external onlyOwner { 114 | require(newOwner != address(0), "New owner is the zero address"); 115 | emit OwnershipTransferred(_owner, newOwner); 116 | _owner = newOwner; 117 | } 118 | } 119 | 120 | 121 | contract StandardToken is ERC20, Ownable { 122 | using SafeMath for uint256; 123 | 124 | mapping(address => uint256) public _balances; 125 | mapping(address => mapping(address => uint256)) private _allowed; 126 | uint256 public _totalSupply; 127 | 128 | function transfer(address _to, uint256 _value) override external returns (bool success) { 129 | require(_value > 0, "Transfer value must be greater than 0"); 130 | require(_balances[msg.sender] >= _value, "Insufficient balance"); 131 | 132 | _balances[msg.sender] = _balances[msg.sender].sub(_value); 133 | _balances[_to] = _balances[_to].add(_value); 134 | emit Transfer(msg.sender, _to, _value); 135 | return true; 136 | } 137 | 138 | function transferFrom(address _from, address _to, uint256 _value) override external returns (bool success) { 139 | require(_value > 0, "Transfer value must be greater than 0"); 140 | require(_balances[_from] >= _value, "Insufficient balance"); 141 | require(_allowed[_from][msg.sender] >= _value, "Allowance exceeded"); 142 | 143 | _balances[_to] = _balances[_to].add(_value); 144 | _balances[_from] = _balances[_from].sub(_value); 145 | _allowed[_from][msg.sender] = _allowed[_from][msg.sender].sub(_value); 146 | emit Transfer(_from, _to, _value); 147 | return true; 148 | } 149 | 150 | function balanceOf(address _owner) public view virtual override returns (uint256) { 151 | return _balances[_owner]; 152 | } 153 | 154 | function approve(address _spender, uint256 _value) override external returns (bool success) { 155 | require(_value == 0 || _allowed[msg.sender][_spender] == 0, "Reset allowance to zero before changing it"); 156 | _allowed[msg.sender][_spender] = _value; 157 | emit Approval(msg.sender, _spender, _value); 158 | return true; 159 | } 160 | 161 | function allowance(address _owner, address _spender) public view virtual override returns (uint256) { 162 | return _allowed[_owner][_spender]; 163 | } 164 | 165 | function totalSupply() public view virtual override returns (uint256) { 166 | return _totalSupply; 167 | } 168 | } 169 | 170 | contract Tratok is StandardToken { 171 | string public name = "Tratok"; 172 | string public symbol = "TRAT"; 173 | uint8 public decimals = 5; 174 | 175 | event Initialized(uint256 totalSupply, address owner); 176 | 177 | constructor() { 178 | _totalSupply = 100000000000*10**decimals; // 10^5 to represent 5 decimals 179 | _balances[msg.sender] = _totalSupply; 180 | emit Initialized(_totalSupply, msg.sender); 181 | } 182 | 183 | fallback() external payable { 184 | revert("Your request does not match any function signature."); 185 | } 186 | 187 | receive() external payable { 188 | revert("Direct payments are not accepted."); 189 | } 190 | } 191 | -------------------------------------------------------------------------------- /smart-contracts/tratokv2.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^ 0.4.4; 2 | 3 | /* 4 | This is the smart contract for the ERC 20 standard Tratok token. 5 | During development of the smart contract, active attention was paid to make the contract as simple as possible. 6 | As the majority of functions are simple addition and subtraction of existing balances, we have been able to make the contract very lightweight. 7 | This has the added advantage of reducing gas costs and ensuring that transaction fees remain low. 8 | The smart contract has been made publically available, keeping with the team's philosophy of transparency. 9 | This is an update on the original smart contract which can be found at 0xDaaab43c2Df2588980826e3C8d46828FC0b44bFe. 10 | The contract has been updated to match a change in project philosophy and enhance distribution and widespread adoption of the token via free airdrops. 11 | 12 | @version "1.1" 13 | @developer "Tratok Team" 14 | @date "22 September 2018" 15 | @thoughts "227 lines that can change the travel and tourism industry! Good luck!" 16 | */ 17 | 18 | /* 19 | * Use of the SafeMath Library prevents malicious input. For security consideration, the 20 | * smart contaract makes use of .add() and .sub() rather than += and -= 21 | */ 22 | 23 | library SafeMath { 24 | 25 | //Ensures that b is greater than a to handle negatives. 26 | function sub(uint256 a, uint256 b) internal returns (uint256) { 27 | assert(b <= a); 28 | return a - b; 29 | } 30 | 31 | //Ensures that the sum of two values is greater than the intial value. 32 | function add(uint256 a, uint256 b) internal returns (uint256) { 33 | uint256 c = a + b; 34 | assert(c >= a); 35 | return c; 36 | } 37 | } 38 | 39 | /* 40 | * ERC20 Standard will be used 41 | * see https://github.com/ethereum/EIPs/issues/20 42 | */ 43 | 44 | contract ERC20 { 45 | //the total supply of tokens 46 | uint public totalSupply; 47 | 48 | //@return Returns the total amount of Tratok tokens in existence. The amount remains capped at the pre-created 100 Billion. 49 | function totalSupply() constant returns(uint256 supply){} 50 | 51 | /* 52 | @param _owner The address of the wallet which needs to be queried for the amount of Tratok held. 53 | @return Returns the balance of Tratok tokens for the relevant address. 54 | */ 55 | function balanceOf(address who) constant returns(uint); 56 | 57 | /* 58 | The transfer function which takes the address of the recipient and the amount of Tratok needed to be sent and complete the transfer 59 | @param _to The address of the recipient (usually a "service provider") who will receive the Tratok. 60 | @param _value The amount of Tratok that needs to be transferred. 61 | @return Returns a boolean value to verify the transaction has succeeded or failed. 62 | */ 63 | function transfer(address to, uint value) returns(bool ok); 64 | 65 | /* 66 | This function will, conditional of being approved by the holder, send a determined amount of tokens to a specified address 67 | @param _from The address of the Tratok sender. 68 | @param _to The address of the Tratok recipient. 69 | @param _value The volume (amount of Tratok which will be sent). 70 | @return Returns a boolean value to verify the transaction has succeeded or failed. 71 | */ 72 | function transferFrom(address from, address to, uint value) returns(bool ok); 73 | 74 | /* 75 | This function approves the transaction and costs 76 | @param _spender The address of the account which is able to transfer the tokens 77 | @param _value The amount of wei to be approved for transfer 78 | @return Whether the approval was successful or not 79 | */ 80 | function approve(address spender, uint value) returns(bool ok); 81 | 82 | /* 83 | This function determines how many Tratok remain and how many can be spent. 84 | @param _owner The address of the account owning the Tratok tokens 85 | @param _spender The address of the account which is authorized to spend the Tratok tokens 86 | @return Amount of Tratok tokens which remain available and therefore, which can be spent 87 | */ 88 | function allowance(address owner, address spender) constant returns(uint); 89 | 90 | 91 | event Transfer(address indexed from, address indexed to, uint value); 92 | event Approval(address indexed owner, address indexed spender, uint value); 93 | 94 | } 95 | 96 | /* 97 | *This is a basic contract held by one owner and prevents function execution if attempts to run are made by anyone other than the owner of the contract 98 | */ 99 | 100 | contract Ownable { 101 | address public owner; 102 | 103 | function Ownable() { 104 | owner = msg.sender; 105 | } 106 | 107 | modifier onlyOwner() { 108 | if (msg.sender != owner) { 109 | throw; 110 | } 111 | _; 112 | } 113 | 114 | function transferOwnership(address newOwner) onlyOwner { 115 | if (newOwner != address(0)) { 116 | owner = newOwner; 117 | } 118 | } 119 | 120 | } 121 | 122 | contract StandardToken is ERC20, Ownable { 123 | using SafeMath for uint256; 124 | function transfer(address _to, uint256 _value) returns(bool success) { 125 | if (balances[msg.sender] >= _value && _value > 0) { 126 | balances[msg.sender] = balances[msg.sender].sub(_value); 127 | balances[_to] = balances[_to].add(_value); 128 | Transfer(msg.sender, _to, _value); 129 | return true; 130 | } else { 131 | return false; 132 | } 133 | } 134 | 135 | function transferFrom(address _from, address _to, uint256 _value) returns(bool success) { 136 | if (balances[_from] >= _value && allowed[_from][msg.sender] >= _value && _value > 0) { 137 | balances[_to] = balances[_to].add(_value); 138 | balances[_from] = balances[_from].sub(_value); 139 | allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value); 140 | Transfer(_from, _to, _value); 141 | return true; 142 | } else { 143 | return false; 144 | } 145 | } 146 | 147 | function balanceOf(address _owner) constant returns(uint256 balance) { 148 | return balances[_owner]; 149 | } 150 | 151 | function approve(address _spender, uint256 _value) returns(bool success) { 152 | allowed[msg.sender][_spender] = _value; 153 | Approval(msg.sender, _spender, _value); 154 | return true; 155 | } 156 | 157 | function allowance(address _owner, address _spender) constant returns(uint256 remaining) { 158 | return allowed[_owner][_spender]; 159 | } 160 | 161 | /* 162 | This function determines distributes tratok to multiple addresses. 163 | @param _destinations The address of the accounts which will be sent Tratok tokens. 164 | @param _values The amount of the Tratok tokens to be sent. 165 | @return The number of loop cycles 166 | */ 167 | 168 | function distributeTratok(address[] _destinations, uint256[] _values) 169 | returns (uint256) { 170 | uint256 i = 0; 171 | while (i < _destinations.length) { 172 | transfer(_destinations[i], _values[i]); 173 | i += 1; 174 | } 175 | return(i); 176 | } 177 | 178 | 179 | mapping(address => uint256) balances; 180 | mapping(address => mapping(address => uint256)) allowed; 181 | uint256 public totalSupply; 182 | } 183 | 184 | contract Tratok is StandardToken { 185 | 186 | function() { 187 | throw; 188 | } 189 | 190 | /* 191 | * The public variables of the token. Inclduing the name, the symbol and the number of decimals. 192 | */ 193 | string public name; 194 | uint8 public decimals; 195 | string public symbol; 196 | string public version = 'H1.0'; 197 | 198 | /* 199 | * Declaring the customized details of the token. The token will be called Tratok, with a total supply of 100 billion tokens. 200 | * It will feature five decimal places and have the symbol TRAT. 201 | */ 202 | 203 | function Tratok() { 204 | 205 | //we will create 100 Billion Coins and send them to the creating wallet. 206 | balances[msg.sender] = 10000000000000000; 207 | totalSupply = 10000000000000000; 208 | name = "Tratok"; 209 | decimals = 5; 210 | symbol = "TRAT"; 211 | } 212 | 213 | /* 214 | *Approve and enact the contract. 215 | * 216 | */ 217 | function approveAndCall(address _spender, uint256 _value, bytes _extraData) returns(bool success) { 218 | allowed[msg.sender][_spender] = _value; 219 | Approval(msg.sender, _spender, _value); 220 | 221 | //If the call fails, result to "vanilla" approval. 222 | if (!_spender.call(bytes4(bytes32(sha3("receiveApproval(address,uint256,address,bytes)"))), msg.sender, _value, this, _extraData)) { 223 | throw; 224 | } 225 | return true; 226 | } 227 | } 228 | -------------------------------------------------------------------------------- /Tratok-blockchain-bridge/TratokBNB.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | /* 5 | * Explanation: 6 | * 7 | * This is the smart contract used as a bridge for migrating Tratok (TRAT) from the BNB 8 | * blockchain to the Ethereum blockchain and vice versa. 9 | * 10 | * Methodology: 11 | * 12 | * The contract features a minting functionality to mint TRAT for a user on the BNB whenever they 13 | * migrate Tratok (TRAT) tokens from the Ethereum blockchain. The contract also features a 14 | * burn function for when users wish to migrate their tokens from the BNB blockchain to the Ethereum 15 | * blockchain. All events are monitored by Tratok's off-chain oracle to ensure circulations supply 16 | * remains unchanged. 17 | * 18 | * 19 | * Risks: 20 | * 21 | * Users may fall victim to phishing attacks where malicious actors create fake interfaces or contracts 22 | * that mimic the legitimate locking contract. This can lead to users inadvertently sending funds to the 23 | * wrong address or interacting with a fraudulent contract. This can be mitigated by using the official 24 | * bridge portal. https://bridge.tratok.com 25 | * 26 | * The contract grants significant powers to the admin, including the ability to mint new tokens and withdraw 27 | * BNB fees. If the admin's private key is compromised, an attacker could gain control over the contract, 28 | * potentially draining funds or manipulating token unlocks. This is mitigated through best security 29 | * practices including making the admin wallet a Multi-Signature Wallet which requires multiple private 30 | * keys to authorize critical actions, such as unlocking tokens or withdrawing BNB fees. By distributing 31 | * control among several trusted parties, the risk of a single compromised key leading to fund loss is 32 | * significantly reduced. In the unlikely event that a key is compromised, its permissions may be revoked by the other 33 | * owners. 34 | * 35 | * Sustainability: 36 | * 37 | * To ensure sustainability of the bridge and prevent abuse, the contract collects a fee every time a migration from 38 | * the BSC blockchain to Ethereum blockchain is performed. This fee can be changed to reflect network 39 | * congestion via the setBNBFee method. 40 | * 41 | * @version "1.2" 42 | * @developer "Tratok Team" 43 | * @date "12 May 2025" 44 | * @thoughts "The Worlds Travel Token Needs To Be On Every Global Blockchain!" 45 | */ 46 | 47 | 48 | import "./MultiSigWallet.sol"; 49 | 50 | contract TratokBNB { 51 | string public name; 52 | string public symbol; 53 | uint8 public decimals; 54 | uint256 public totalSupply; 55 | 56 | mapping(address => uint256) public balanceOf; 57 | mapping(address => mapping(address => uint256)) public allowance; 58 | 59 | address public owner; 60 | 61 | // Multi-signature wallet is used to enhance security 62 | MultiSigWallet public multiSigWallet; 63 | 64 | // Maximum supply (in wei) set at 100,000,000,000 with 5 decimals 65 | uint256 public constant MAX_SUPPLY = 100_000_000_000 * 10**5; 66 | 67 | // 5 decimal places set to be consistent 68 | uint8 public constant DECIMALS = 5; 69 | 70 | // Event declaration for burning tokens 71 | event TokensBurned(address indexed user, uint256 amount); 72 | 73 | // Fee for burning tokens in BNB 74 | uint256 public burnFee; 75 | 76 | // Total collected fees in BNB 77 | uint256 public totalFeesCollected; 78 | 79 | event Transfer(address indexed from, address indexed to, uint256 value); 80 | event Approval(address indexed owner, address indexed spender, uint256 value); 81 | event Mint(address indexed to, uint256 value); 82 | event Burn(address indexed from, uint256 value); 83 | event BurnFeeUpdated(uint256 newFee); 84 | event FeesWithdrawn(address indexed destination, uint256 amount); 85 | 86 | modifier onlyOwner() { 87 | require(msg.sender == owner, "Not the contract owner"); 88 | _; 89 | } 90 | 91 | constructor(address[] memory owners, uint256 requiredSignatures) { 92 | name = "Tratok"; 93 | symbol = "TRAT"; 94 | decimals = DECIMALS; 95 | totalSupply = 0; // Initialize total supply to zero 96 | owner = msg.sender; // Set the contract deployer as the owner 97 | 98 | // Initialize the multi-signature wallet 99 | multiSigWallet = new MultiSigWallet(owners, requiredSignatures); 100 | burnFee = 0; // Initialize burn fee to zero 101 | } 102 | 103 | function transfer(address _to, uint256 _value) public returns (bool success) { 104 | require(_to != address(0), "Invalid address"); 105 | require(balanceOf[msg.sender] >= _value, "Insufficient balance"); 106 | 107 | balanceOf[msg.sender] -= _value; 108 | balanceOf[_to] += _value; 109 | emit Transfer(msg.sender, _to, _value); 110 | return true; 111 | } 112 | 113 | function approve(address _spender, uint256 _value) public returns (bool success) { 114 | allowance[msg.sender][_spender] = _value; 115 | emit Approval(msg.sender, _spender, _value); 116 | return true; 117 | } 118 | 119 | function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) { 120 | require(_from != address(0), "Invalid address"); 121 | require(_to != address(0), "Invalid address"); 122 | require(balanceOf[_from] >= _value, "Insufficient balance"); 123 | require(allowance[_from][msg.sender] >= _value, "Allowance exceeded"); 124 | 125 | balanceOf[_from] -= _value; 126 | balanceOf[_to] += _value; 127 | allowance[_from][msg.sender] -= _value; 128 | emit Transfer(_from, _to, _value); 129 | return true; 130 | } 131 | 132 | /** 133 | * @dev Mints new tokens to the specified address. 134 | * @param to The address to receive the newly minted tokens. 135 | * @param amount The amount of tokens to mint. 136 | */ 137 | function mint(address to, uint256 amount) public { 138 | require(msg.sender == address(multiSigWallet), "Only multi-signature wallet can mint tokens"); 139 | require(totalSupply + amount <= MAX_SUPPLY, "Minting exceeds max supply"); 140 | 141 | // Update the balance and total supply 142 | balanceOf[to] += amount; 143 | totalSupply += amount; 144 | 145 | // Emit Transfer event for minting 146 | emit Transfer(address(0), to, amount); 147 | emit Mint(to, amount); 148 | } 149 | 150 | /** 151 | * @dev Allows users to burn their own tokens so they can be migrated to Ethereum blockchain. 152 | * @param amount The amount of tokens to burn (in wei). 153 | */ 154 | function burn(uint256 amount) public payable { 155 | require(amount > 0, "Amount must be greater than 0"); 156 | require(msg.value >= burnFee, "Insufficient BNB sent for burn fee"); 157 | require(amount <= balanceOf[msg.sender], "Insufficient TRAT balance to burn"); 158 | 159 | // Update the balance and total supply 160 | balanceOf[msg.sender] -= amount; 161 | totalSupply -= amount; 162 | 163 | // Emit Transfer event for burning 164 | emit Transfer(msg.sender, address(0), amount); 165 | emit Burn(msg.sender, amount); 166 | 167 | // Collect the burn fee 168 | totalFeesCollected += msg.value; 169 | 170 | // Emit event on burn 171 | emit TokensBurned(msg.sender, amount); 172 | } 173 | 174 | /** 175 | * @dev Set the burn fee in BNB. 176 | * @param newFee The new burn fee (in wei). 177 | */ 178 | function setBurnFee(uint256 newFee) public { 179 | require(msg.sender == address(multiSigWallet), "Only multi-signature wallet can set burn fee"); 180 | burnFee = newFee; 181 | emit BurnFeeUpdated(newFee); // Added event for updating burn fee 182 | } 183 | 184 | /** 185 | * @dev Withdraw collected BNB fees to a specified destination address. 186 | * @param destination The address to receive the withdrawn fees. 187 | */ 188 | function withdrawFees(address destination) public { 189 | require(msg.sender == address(multiSigWallet), "Only multi-signature wallet can withdraw fees"); 190 | require(destination != address(0), "Invalid destination address"); 191 | require(destination != address(this), "Cannot send to self"); 192 | 193 | uint256 amount = totalFeesCollected; 194 | require(amount > 0, "No fees to withdraw"); 195 | 196 | totalFeesCollected = 0; // Reset the fee counter 197 | (bool success, ) = destination.call{value: amount}(""); 198 | require(success, "Transfer failed"); 199 | 200 | emit FeesWithdrawn(destination, amount); 201 | } 202 | 203 | 204 | /** 205 | * @dev Check the total fees collected in BNB. 206 | * @return The total fees collected in BNB. 207 | */ 208 | function checkTotalFeesCollected() public view returns (uint256) { 209 | return totalFeesCollected; 210 | } 211 | 212 | // Fallback function to receive BNB 213 | receive() external payable {} 214 | } 215 | --------------------------------------------------------------------------------