github.com/aidoskuneen/adk-node@v0.0.0-20220315131952-2e32567cb7f4/adkgo-GENESIS/contracts/ADKTransactions.sol (about) 1 // SPDX-License-Identifier: GPL-3.0 2 pragma solidity >0.8.4; 3 4 // ADKTransactions Contract for ADKGO - requires CURL Extended Version of EVM/AVM 5 //import "contracts/AGSClaim.sol"; 6 7 interface ADKTokenInterface { 8 function AZ9balanceOf(string memory _adkAddr) external view returns (uint256 balance); 9 function meshTransaction(string memory _meshaddr, int256 _value) external; 10 function AZ9_TO_ADDR (string memory adkString) external pure returns(address); 11 } 12 13 // Implementation of the ADK Mesh Structure and Signature Validation Genesis Contract 14 15 contract ADKTransactions { 16 17 address public ADKTokenAddress; // Holds the address of the ADK Genesis Contract managing balances 18 address public adkgo_genesis_address; // Contract genesis address 19 20 constructor( 21 address _genesis_account, 22 address _ADKTokenContract 23 ){ 24 // DEPLOY MAIN ADK CONTRACT 25 ADKTokenAddress = _ADKTokenContract; // The ADK Token Contract 26 adkgo_genesis_address = _genesis_account; 27 ClientProofOfWorkRequirement = 15; // PoW effort required (must be multiple of 3) 28 createGenesisTransaction(); 29 } 30 31 // Create the initial genesis transaction, for all "9" address 32 bool genesisCreated = false; 33 function createGenesisTransaction() internal { 34 // BEGIN Create genesis transaction 35 require(!genesisCreated); 36 genesisCreated = true; 37 baseTransactionHash = "999999999999999999999999999999999999999999999999999999999999999999999999999999999"; 38 bytes memory baseT = new bytes(2673); 39 for (uint i = 0; i < 2673; i++) 40 baseT[i] = 0x39; // 0x39 = "9" 41 baseTransaction = string(baseT); // thats now 2673 "9" = the Genesis transaction 42 bytes32 transactionHashSha3 = keccak256(bytes(baseTransactionHash)); 43 transactions[transactionHashSha3] = baseTransaction; 44 transaction_hashes[transactionHashSha3] = baseTransactionHash; 45 meshTip = transactionHashSha3; 46 transaction_trunk[transactionHashSha3] = transactionHashSha3; 47 transaction_branch[transactionHashSha3] = transactionHashSha3; 48 tx_count = 0; 49 // END Create genesis transaction 50 } 51 52 53 mapping(bytes32 => string) public transactions; // all stored and confirmed transactions, indexed by their keccak hash 54 mapping(bytes32 => string) public transaction_hashes; // all stored and confirmed transaction hashes, indexed by their keccak hash 55 56 mapping(bytes32 => bool) public spent_addresses; // store addresses that have been spent from before. Can be used by clients to avoid sending to already used AZ9 addresses 57 58 mapping(bytes32 => bytes32) public transactionhash_by_address; // stores sha3(transactionhash) by sha3(address), increment by 1 for each further transaction 59 // replaces events as this is faster 60 mapping(bytes32 => bytes32) public transactionhash_by_bundle; // stores sha3(transactionhash) by sha3(bundle), increment by 1 for each further transaction 61 // replaces events as this is faster 62 mapping(bytes32 => uint32) public transactionhash_by_address_count; 63 mapping(bytes32 => uint32) public transactionhash_by_bundle_count; 64 65 mapping(uint256 => bytes32) public transaction_indexed_by_seq; // transaction sha3 indexed by their sequence/occurence 66 mapping(bytes32 => uint256) public transaction_index; // transaction sha3 indexed by their sequence/occurence (reversed) 67 uint256 public tx_count; 68 69 // mesh structure 70 string baseTransaction; // always all '9' 71 string baseTransactionHash; // always all '9' 72 73 mapping(bytes32 => bytes32) public transaction_trunk; // transactions info indexed by their keccak hash: trunk 74 mapping(bytes32 => bytes32) public transaction_branch; // transactions info indexed by their keccak hash: branch 75 76 bytes32 public meshTip; // the highest tip in the mesh 77 78 uint256 public ClientProofOfWorkRequirement; 79 80 // mesh indexing 81 event transactions_by_bundle(bytes32 indexed bundleSHA3, bytes32 transactionSHA3); // logs transactions per bundle, tighly packed bytes32 keccak hashes of transactions 82 event transactions_by_address(bytes32 indexed addressSHA3, bytes32 transactionSHA3); // logs transactions per address, tighly packed bytes32 keccak hashes of transactions 83 84 // testBundleBalances are used to ensure that a transaction bundle does not cause any balances to go negative 85 mapping(string => int256) private testBundleBalances; // before and after balance computations these are always 0; 86 // testBundleBalances are used to ensure that a transaction bundle does not cause any balances to go negative 87 mapping(uint256 => bytes32) private tmpSha3TransactionHashes; // temp array to hold current transaction hashes for structure check; 88 89 // Get AZ9 balance wrapper function, fetches ADK balance from ADK Token Genesis contract 90 function GetAZ9balanceOf(string memory _adkAddr) public view returns (uint256 balance){ 91 return ADKTokenInterface(ADKTokenAddress).AZ9balanceOf(_adkAddr); // pass through 92 } 93 94 95 // PostTransactions: This is the main entry point used by clients to submit full transaction bundles. 96 // It requires an entire bundle of a transaction, in the correct sequence, and with PoW completed 97 98 // This function checks for the minimum POW, valid signatures, valid bundle hashes, sufficient balances 99 100 // If all is ok, the transfer is executed as soon as it is mined (PoA/PoS - depending on the stage) 101 102 bool mutex_PostTransactions = false; // mutex to prevent reentry 103 function PostTransactions(string memory transactiondata) public mod_requireAZ9(transactiondata) returns(string memory) { 104 105 // // Check mutex 106 // require (!mutex_PostTransactions,"reentry prevented!"); 107 // mutex_PostTransactions = true; // prevent reentry exploits 108 109 // bytes memory b_trytes = bytes(transactiondata); // Load transaction AZ9 string into bytes 110 // require(b_trytes.length % 2673 == 0 && b_trytes.length > 0 ,"Invalid transaction(s) length"); 111 // uint16 cnt_transactions = uint16(b_trytes.length / 2673); // count number of included individual transactions 112 113 // bytes memory all_essential_parts = new bytes(cnt_transactions*162); // each essential is 162 char long, all essentials make the bundle hash 114 115 // int totalBundleValue = 0; // has to be 0 (i.e. input and output values have to net 0) 116 // int lastIndex = -1; // initialize 117 // string memory s_bundle = ""; // initialize 118 // // process each transaction one by one 119 // for (uint32 transaction_idx = 0; transaction_idx < cnt_transactions; transaction_idx++){ 120 121 // TransactionInfoStruct memory tinfo; // will hold all key transaction data (also used to avoid stack errors due to too many variables) 122 // tinfo.offset = transaction_idx * 2673; // offset of each transaction in the entire string 123 124 // tinfo.data = substring(transactiondata,tinfo.offset , tinfo.offset + 2673); // extract the current transaction 125 // tinfo.trans_hash = bytes(CurlHashOP(tinfo.data)); // Call the Hash Operation in order to get the transaction hash 126 127 // // Validate PoW 128 // // force the last X digits to be 0 (client POW); // 129 130 // for ( uint checkIdx = 0; checkIdx < ClientProofOfWorkRequirement/3; checkIdx ++ ){ 131 // uint byte_index = 80 - checkIdx; // 80,79,78,.. integer division to get byte position to check 132 // // note we only check full bytes, not by trits. So difficulty can be e.g. ... , 9, 12, 15, 18, 21 ... 133 // require(tinfo.trans_hash[byte_index] == 0x39, // 0x39 = "9", 134 // "TRANSACTION POW NOT COMPLETED" 135 // ); 136 // } 137 138 // // Transaction Hash Handling 139 // tinfo.transactionSHA3 = keccak256(tinfo.trans_hash); // get keccak hash of transaction hash for indexing 140 // require(bytes(transactions[tinfo.transactionSHA3]).length == 0 ,"TRANSACTION ALREADY PROCESSED"); 141 // transactions[tinfo.transactionSHA3] = string(tinfo.data); // store transaction 142 // transaction_hashes[tinfo.transactionSHA3] = string(tinfo.trans_hash); // store transaction Hash 143 // tx_count++; 144 // transaction_indexed_by_seq[tx_count] = tinfo.transactionSHA3; 145 // transaction_index[tinfo.transactionSHA3] = tx_count; 146 147 // // Trunk + Branch Handling 148 // // Build mesh structure: trunk and branch, just store for now, check later 149 // transaction_trunk[tinfo.transactionSHA3] = keccak256(subbytes(b_trytes,uint32(tinfo.offset+2430),uint32(tinfo.offset+2430+81))); 150 // transaction_branch[tinfo.transactionSHA3] = keccak256(subbytes(b_trytes,uint32(tinfo.offset+2511),uint32(tinfo.offset+2511+81))); 151 152 // tmpSha3TransactionHashes[transaction_idx] = tinfo.transactionSHA3; // store for later consistency check 153 154 // // record highest mesh tip 155 // if (transaction_idx ==0) { 156 // meshTip = tinfo.transactionSHA3; // becomes highest mesh tip 157 // } 158 159 // // Bundle Hash: recurd current transaction essential parts for later bundle hash generation 160 161 // for (uint16 idx = 0; idx < 162; idx++){ // get essential parts for bunlde hash calculation 162 // all_essential_parts[(transaction_idx*162) + idx] = b_trytes[tinfo.offset + 2187 + idx]; 163 // } 164 165 // // Transaction Address Value Handling 166 167 // tinfo.s_address = substring(tinfo.data,2187,2268); // get current transaction address 168 // testBundleBalances[tinfo.s_address] = 0; // set ot 0 for now, we will use this later to check sufficient balance availability 169 170 // // Cummulative bundle value calculation up to current transaction (must be 0 after all transactions loaded, i.e. input total = output total) 171 // tinfo.transactionValue = TryteToIntValue(subbytes(b_trytes,tinfo.offset+2268,tinfo.offset+2279)); 172 // totalBundleValue += tinfo.transactionValue; 173 174 // // just some additional checks, can never be too careful 175 // require(tinfo.transactionValue >= -2500000000000000,"transaction value too low"); 176 // require(tinfo.transactionValue <= 2500000000000000,"transaction value too high"); 177 // require(totalBundleValue >= -2500000000000000,"bundle cummulative transaction value too low"); 178 // require(totalBundleValue <= 2500000000000000,"bundle cummulative transaction value too high"); 179 180 // // Validate transaction index - current and total index (ensure transaction is in correct sequence) 181 182 // // check transaction indices 183 // tinfo.b_lastIndex = subbytes(b_trytes,tinfo.offset+2340,tinfo.offset+2349); 184 // tinfo.b_bundle = subbytes(b_trytes,tinfo.offset+2349,tinfo.offset+2349+81); 185 186 // if (transaction_idx==0){ 187 // s_bundle = string(tinfo.b_bundle); 188 // lastIndex = TryteToIntValue(tinfo.b_lastIndex); 189 // } 190 // else { 191 // require(TryteToIntValue(tinfo.b_lastIndex) == lastIndex,"lastIndex not consistent"); // last index has to be the same across all transactions 192 // require(compareStrings(s_bundle, string(tinfo.b_bundle)),"bundle not consistent"); // bundle has to be the same across all transactions 193 // } 194 195 // tinfo.b_currentIndex = subbytes(b_trytes,tinfo.offset+2331,tinfo.offset+2340); 196 // tinfo.currentIndex = TryteToIntValue(tinfo.b_currentIndex); 197 198 // require(transaction_idx == uint(tinfo.currentIndex), "transaction sequence invalid"); // transaction number has to match index 199 200 // if (transaction_idx == cnt_transactions - 1){ 201 // require(transaction_idx == uint(lastIndex), "last transaction != lastIndex"); // transaction number has to match lastIndex for last transaction 202 // } 203 204 // // SIGNATURE VALIDATIONS FOR SPENDING TRANSACTIONS /////////////////////// 205 // // Check signature for spending transactions 206 207 // if (tinfo.transactionValue < 0){ // only need to check signatures for spending transactions 208 209 // // Note: adkgo requires Signature Level 2, meaning the signature is spread across 2 transactions 210 211 // // the last transaction can't be a spending transaction, as each spending transaction has one more 0 value signature transaction 212 // require (transaction_idx < uint(lastIndex),"missing 2nd signature"); // there must be at least one more transaction 213 214 // tinfo.sig2_address = substring(transactiondata,tinfo.offset+2673+2187,tinfo.offset+2673+2268); 215 // tinfo.sig2_value = TryteToIntValue(subbytes(b_trytes,tinfo.offset+2673+2268,tinfo.offset+2673+2279)); 216 217 // require (compareStrings(tinfo.s_address, tinfo.sig2_address),"2nd signature has invalid address"); // there must be at least one more transaction 218 // require (tinfo.sig2_value==0,"2nd signature is not 0 value"); 219 220 // tinfo.sigA = substring(transactiondata,tinfo.offset+0,tinfo.offset+2187); 221 // tinfo.sigB = substring(transactiondata,tinfo.offset+2673,tinfo.offset+2673+2187); 222 223 // // Validate Signature 224 // require( CurlValidateSignature(tinfo.s_address, 225 // concat(tinfo.sigA,tinfo.sigB), 226 // s_bundle), 227 // "INVALID SIGNATURE"); 228 // // 229 // spent_addresses[keccak256(bytes(tinfo.sig2_address))] = true; 230 // } 231 232 // emit EventLogInt(tinfo.s_address, tinfo.transactionValue); 233 234 // //log for faster retrieval later, also used by "find_transactions" 235 // bytes32 bundleSHA3 = keccak256(tinfo.b_bundle); 236 // bytes32 addressSHA3 = keccak256(bytes(tinfo.s_address)); 237 238 // emit transactions_by_bundle(bundleSHA3, tinfo.transactionSHA3); // logs transactions per bundle, tighly packed bytes32 keccak hashes of transactions 239 // emit transactions_by_address(addressSHA3, tinfo.transactionSHA3); // logs transactions per address, tighly packed bytes32 keccak hashes of transactions 240 241 // // we also log in contract data, not just events, as that is faster for retrieval, and allows fast sync. Cost more storage though, 242 // // but you know... the things we accept for better performance... 243 // StoreTransactionsByAddress(addressSHA3, tinfo.transactionSHA3); 244 // StoreTransactionsByBundle(bundleSHA3, tinfo.transactionSHA3); 245 246 247 // } // END LOOP THROUGH ALL TRANSACTIONS 248 249 // // perform further overall checks: 250 251 // // Check trunk/branch strucutre solid 252 // // process each transaction hash we have seen in the bundle 253 // for (uint32 transaction_idx = 0; transaction_idx < cnt_transactions; transaction_idx++){ 254 // TransactionInfoStruct memory tcheck; 255 // tcheck.transactionSHA3 = tmpSha3TransactionHashes[transaction_idx] ; 256 // tcheck.transactionTrunkSHA3 = transaction_trunk[tcheck.transactionSHA3]; 257 // tcheck.transactionBranchSHA3 = transaction_branch[tcheck.transactionSHA3]; 258 // require(bytes(transactions[tcheck.transactionTrunkSHA3]).length != 0 ,"TRUNK TRANSACTION DOES NOT EXIST"); 259 // require(bytes(transactions[tcheck.transactionBranchSHA3]).length != 0 ,"BRANCH TRANSACTION DOES NOT EXIST"); 260 // } 261 262 // assert(totalBundleValue==0); // totalBundleValue must be 0 across the bundle; 263 264 // // compute and check BUNDLE HASH: calculated bundle hash must match the actual bundle trytes stored in each transaction 265 266 // string memory s_hash = CurlHashOP(string(all_essential_parts)); 267 // require (compareStrings(s_bundle,s_hash),"CALCULATED BUNDLE DIFFERS"); 268 269 // // if we are here, the bundle itself is valid. Now we have to check if there are enough balances available on the spending addresses 270 // ValidateBalancesAndTransact(transactiondata); 271 272 // // AND NOW, as the final step, we call ADKTransactionNotify on each receiving Contract 273 274 // // Note: this is done last, to prevent reentry hacks, and we use CALL so we dont revert if the 275 // // target is not a contract: The low-level functions call, delegatecall and staticcall return true as their first return value if the account called is non-existent, as part of the design of the EVM. 276 277 // // note the GAS is limited here to 10000 gas to prevent spam 278 279 // for (uint32 transaction_idx = 0; transaction_idx < cnt_transactions; transaction_idx++){ 280 // TransactionInfoStruct memory tinfo2; 281 // tinfo2.offset = transaction_idx * 2673; 282 // tinfo2.transactionValue = TryteToIntValue(subbytes(b_trytes,tinfo2.offset+2268,tinfo2.offset+2279)); 283 // if (tinfo2.transactionValue > 0){// only call for positive transactions 284 // tinfo2.s_address = substring(transactiondata,tinfo2.offset+2187,tinfo2.offset+2268); 285 // tinfo2.sigA = substring(transactiondata,tinfo2.offset+0,tinfo2.offset+2187); 286 287 // // the following calls the receiveing contract notification function (if it exists) 288 // address _addr = ADKTokenInterface(ADKTokenAddress).AZ9_TO_ADDR(tinfo2.s_address); // get the target address 289 // (bool success, bytes memory data) = _addr.call{value: 0, gas: 10000 }( 290 // abi.encodeWithSignature("ADKMeshTransactionNotify(string,int256)", tinfo2.sigA, tinfo2.transactionValue) 291 // ); 292 // require (success, "CALLED CONTRACT (ADKTransactionNotify) REVERTED."); 293 // } 294 // } 295 296 // mutex_PostTransactions = false; // end reentry check 297 // return s_hash; // bundle hash 298 require(false, "function not implemented"); //don't need ERC20 version any more 299 } 300 // 301 // ValidateBalancesAndTransact - internal function that checks balances (sufficient balance) and performs the actual transfer 302 // 303 bool mutex2 = false; 304 function ValidateBalancesAndTransact(string memory transactiondata) internal returns (bool){ 305 306 // require (!mutex2, "mutex check failed on ValidateBalancesAndTransact"); 307 // mutex2 = true; 308 309 // //check transaction data once again, and then loop through all transactions. 310 // // NOTE: at this point all signatures have already been validated. 311 312 // bytes memory b_trytes = bytes(transactiondata); 313 // require(b_trytes.length % 2673 == 0 && b_trytes.length > 0 ,"Invalid transaction(s) length"); 314 // uint16 cnt_transactions = uint16(b_trytes.length / 2673); 315 316 // int total = 0; 317 318 // // first calculate totals per address (in case the same address appears more than once in the bundle) 319 // for (uint32 transaction_idx = 0; transaction_idx < cnt_transactions; transaction_idx++){ // loop through all transactions once 320 // uint32 offset = transaction_idx * 2673; // offset of current transaction 321 // string memory s_address = substring(transactiondata,uint32(offset+2187),uint32(offset+2268)); 322 // int value = TryteToIntValue(subbytes(b_trytes,offset+2268,offset+2279)); 323 // total += value; 324 // testBundleBalances[s_address] += value; // store it as temporary virtual balance (this entry was set to 0 initially in PostTransactions() ) 325 // } 326 // assert(total==0); // we did that before already, but doesnt hurt to check again... 327 328 // // now check if actual current TOTAL balance for each SPENDING address is sufficient 329 // for (uint32 transaction_idx2 = 0; transaction_idx2 < cnt_transactions; transaction_idx2++){ // loop through all transactions once again, but know we know each address' final total aready 330 // uint32 offset = transaction_idx2 * 2673; // offset of current transaction 331 // string memory s_address = substring(transactiondata,uint32(offset+2187),uint32(offset+2268)); 332 333 // int availableBalance = int(GetAZ9balanceOf(s_address)); // get this from current ADK balance 334 335 // // after the bundle values are applied on each address, the new balance must be >= 0 336 // require(availableBalance + testBundleBalances[s_address] >= 0, "INSUFFICIENT BALANCE"); 337 338 // // PERFORM VALUE TRANSACTION. Note: ADKTokenContract.meshTransaction can only be called by this Transfer Contract 339 // if (testBundleBalances[s_address]!= 0){ // transaction is positive or negative, thus will update the address balance 340 // ADKTokenInterface(ADKTokenAddress).meshTransaction(s_address, testBundleBalances[s_address]); 341 // } 342 343 // testBundleBalances[s_address] = 0; // reset to 0 now as we have done the TRANSACTION 344 // } 345 // mutex2 = false; // end reentry check 346 // return true; 347 require(false, "function not implemented"); //don't need ERC20 version any more 348 } 349 350 // 351 // Stores transaction hases by address, but depending on the number of tx we increment the SHA hash 352 // 353 function StoreTransactionsByAddress(bytes32 addressSHA3, bytes32 transactionSHA3) internal { 354 uint32 cntAddrTx = transactionhash_by_address_count[addressSHA3]; 355 bytes32 addressSHA3_incl_cnt = bytes32(uint256(addressSHA3)+cntAddrTx); 356 transactionhash_by_address[addressSHA3_incl_cnt] = transactionSHA3; 357 cntAddrTx++; 358 transactionhash_by_address_count[addressSHA3] = cntAddrTx; 359 } 360 // 361 // Stores transaction hases by address, but depending on the number of tx we increment the SHA hash 362 // 363 function StoreTransactionsByBundle(bytes32 bundleSHA3, bytes32 transactionSHA3) internal { 364 uint32 cntBundleTx = transactionhash_by_bundle_count[bundleSHA3]; 365 bytes32 bundleSHA3_incl_cnt = bytes32(uint256(bundleSHA3)+cntBundleTx); 366 transactionhash_by_bundle[bundleSHA3_incl_cnt] = transactionSHA3; 367 cntBundleTx++; 368 transactionhash_by_bundle_count[bundleSHA3] = cntBundleTx; 369 } 370 // 371 // helper function view GetTxByAddress 372 function GetTxByAddress(string memory addressString, uint256 numTx) public view returns (string memory) { 373 bytes32 addr_b = keccak256(bytes(addressString)); 374 addr_b = bytes32(uint256(addr_b)+numTx); 375 bytes32 txHash = transactionhash_by_address[addr_b]; 376 if (txHash == 0x000000000000000000000000000000000000000000000000) return ""; 377 return transaction_hashes[txHash]; 378 } 379 380 // 381 // helper function view GetTxByAddress 382 function GetTxByBundle(string memory bundleString, uint256 numTx) public view returns (string memory) { 383 bytes32 bundle_b = keccak256(bytes(bundleString)); 384 bundle_b = bytes32(uint256(bundle_b)+numTx); 385 bytes32 txHash = transactionhash_by_bundle[bundle_b]; 386 if (txHash == 0x000000000000000000000000000000000000000000000000) return ""; 387 return transaction_hashes[txHash]; 388 } 389 390 // Transaction Struct, mainly used to avoid stack issues 391 struct TransactionInfoStruct { 392 string s_address; 393 string data; // transaction data 394 int transactionValue; 395 string sig2_address; 396 int sig2_value; 397 string sigA; 398 string sigB; 399 bytes b_lastIndex; 400 bytes b_bundle; 401 bytes b_currentIndex; 402 int currentIndex; 403 uint32 offset; 404 bytes32 transactionSHA3; // KECCAK hash of transactionSHA3 405 bytes trans_hash; // CURL hash of transaction 406 bytes32 transactionTrunkSHA3; 407 bytes32 transactionBranchSHA3; 408 } 409 410 411 // HELPER FUNCTIONS 412 413 // Allows for upgrade of the ADK Token Contract while in Genesis Mode 414 function ADM_SetADKTokenContract (address _newContract) public onlyGenesis { 415 ADKTokenAddress = _newContract; 416 } 417 418 // Allows for upgrade of the ADK Genesis Address 419 // and will be used to force-lock the contract by setting to 0x00000000[..] so no further updates are possible 420 function ADM_SetGenesisAddress (address _genesisAddress) public onlyGenesis { 421 adkgo_genesis_address = _genesisAddress; 422 } 423 424 // Allows Tip adjustment while in Genesis Mode 425 function ADM_SetTip (bytes32 _newTip) public onlyGenesis { 426 meshTip = _newTip; 427 } 428 429 // Allows Difficulty adjustment while in Genesis Mode 430 function ADM_SetDifficulty (uint256 _ClientProofOfWorkRequirement) public onlyGenesis { 431 ClientProofOfWorkRequirement = _ClientProofOfWorkRequirement; 432 } 433 434 // Allows data migration from old ADK node while in Genesis Mode 435 function ADM_LoadTransactionsUnchecked (string memory _transaction) public mod_requireAZ9(_transaction) onlyGenesis { 436 bytes memory b_trytes = bytes(_transaction); 437 require(bytes(_transaction).length == 2673,"INVALID TRANSACTION LENGTH"); 438 TransactionInfoStruct memory tinfo; 439 tinfo.data = _transaction; 440 tinfo.trans_hash = bytes(CurlHashOP(tinfo.data)); // Call the Hash Operation in order to get the transaction hash 441 tinfo.transactionSHA3 = keccak256(tinfo.trans_hash); 442 transactions[tinfo.transactionSHA3] = string(tinfo.data); // store transaction 443 transaction_hashes[tinfo.transactionSHA3] = string(tinfo.trans_hash); // store transaction hash 444 445 tinfo.transactionTrunkSHA3 = keccak256(subbytes(b_trytes,uint32(2430),uint32(2430+81))); 446 tinfo.transactionBranchSHA3 = keccak256(subbytes(b_trytes,uint32(2511),uint32(2511+81))); 447 448 // store trunk and branch 449 transaction_trunk[tinfo.transactionSHA3] = tinfo.transactionTrunkSHA3; 450 transaction_branch[tinfo.transactionSHA3] = tinfo.transactionBranchSHA3; 451 452 tinfo.s_address = substring(tinfo.data,2187,2268); 453 tinfo.b_bundle = subbytes(b_trytes,2349,2349+81); 454 455 //log for faster retrieval later 456 bytes32 addrSHA3 = keccak256(bytes(tinfo.s_address)); 457 bytes32 bundSHA3 = keccak256(bytes(tinfo.b_bundle)); 458 459 emit transactions_by_bundle(bundSHA3, tinfo.transactionSHA3); // logs transactions per bundle, tighly packed bytes32 keccak hashes of transactions 460 emit transactions_by_address(addrSHA3, tinfo.transactionSHA3); // logs transactions per address, tighly packed bytes32 keccak hashes of transactions 461 StoreTransactionsByBundle(bundSHA3, tinfo.transactionSHA3); 462 StoreTransactionsByAddress(addrSHA3, tinfo.transactionSHA3); 463 } 464 465 // Allows for initial load of Balances while in Genesis Mode 466 function ADM_LoadADKBalances (string memory _address, int _value) public onlyGenesis { 467 ADKTokenInterface(ADKTokenAddress).meshTransaction(_address, _value); 468 } 469 // Allows for initial load of Balances while in Genesis Mode/ bulk mode for speedup 470 function ADM_LoadADKBalancesBulk (string memory _addresses, 471 int _value1, 472 int _value2, 473 int _value3, 474 int _value4, 475 int _value5, 476 int _value6, 477 int _value7, 478 int _value8, 479 int _value9, 480 int _value10 481 ) public onlyGenesis { 482 uint32 pos = 0; 483 require (bytes(_addresses).length == 81 * 10 , "String must contain 10 addresses without checksum for bulk processing"); 484 ADKTokenInterface(ADKTokenAddress).meshTransaction(substring(_addresses,pos,pos+81), _value1); pos+= 81; 485 ADKTokenInterface(ADKTokenAddress).meshTransaction(substring(_addresses,pos,pos+81), _value2); pos+= 81; 486 ADKTokenInterface(ADKTokenAddress).meshTransaction(substring(_addresses,pos,pos+81), _value3); pos+= 81; 487 ADKTokenInterface(ADKTokenAddress).meshTransaction(substring(_addresses,pos,pos+81), _value4); pos+= 81; 488 ADKTokenInterface(ADKTokenAddress).meshTransaction(substring(_addresses,pos,pos+81), _value5); pos+= 81; 489 ADKTokenInterface(ADKTokenAddress).meshTransaction(substring(_addresses,pos,pos+81), _value6); pos+= 81; 490 ADKTokenInterface(ADKTokenAddress).meshTransaction(substring(_addresses,pos,pos+81), _value7); pos+= 81; 491 ADKTokenInterface(ADKTokenAddress).meshTransaction(substring(_addresses,pos,pos+81), _value8); pos+= 81; 492 ADKTokenInterface(ADKTokenAddress).meshTransaction(substring(_addresses,pos,pos+81), _value9); pos+= 81; 493 ADKTokenInterface(ADKTokenAddress).meshTransaction(substring(_addresses,pos,pos+81), _value10); 494 } 495 496 // Events (Logging) 497 event EventLogString(string indexed info, string strdata); 498 event EventLogInt(string indexed info, int intdata); 499 event EventLogUInt(string indexed info, uint uintdata); 500 501 // 502 // Additional helper functions / tools 503 504 // Convert a single tryte to 3 trits 505 function TryteToTrits (uint16 test) public pure returns (int16[3] memory){ 506 // TO DO use modulo instead. 507 if (test == 57)return [int16(0),int16(0),int16(0)]; // 9 // special case 508 require(test >= 65 && test <= 90,"INVALID TRYTE"); 509 uint16 base = test + 3; // 68 is the base, that perfectly matches the modulo so that e.g. 65 becomes 1/0/0 510 return [ 511 int16(base % 3)-1, 512 int16((base/3) % 3)-1, 513 int16((base/9) % 3)-1 514 ]; 515 } 516 517 // Convert value-trytes to actual values 518 function TryteToIntValue(bytes memory data) public pure returns (int) { 519 int ret = 0; 520 521 for (uint i = data.length; i > 0; i--) { // have to use >0 and then -1 because otherwise uint becomes negative and transaction reverts 522 int16[3] memory trits = TryteToTrits(uint8(data[i-1])); 523 ret = ret * 3 + trits[2]; 524 ret = ret * 3 + trits[1]; 525 ret = ret * 3 + trits[0]; 526 } 527 return ret; 528 } 529 530 // Checks if two strings are identical 531 function compareStrings(string memory a, string memory b) internal pure returns (bool) { 532 return (keccak256(abi.encodePacked((a))) == keccak256(abi.encodePacked((b)))); 533 } 534 535 // CurlHashOP - calculates a CURL hash for a given Tryte string 536 function CurlHashOP(string memory str) public pure returns (string memory){ 537 538 bytes memory pdata = bytes(string(abi.encodePacked("{CURL}", "HASH", bytes1(0x00), bytes1(0x00), str))); 539 bytes32 r1 = keccak256(pdata); 540 pdata[10] = 0x20; // next 32 chars 541 bytes32 r2 = keccak256(pdata); 542 pdata[10] = 0x40; // next 32 chars 543 bytes32 r3 = keccak256(pdata); 544 545 bytes memory ret = new bytes(81); 546 547 for (uint i = 0; i< 32; i++){ // 0-64 548 ret[i] = r1[i]; 549 ret[32+i] = r2[i]; 550 } 551 for (uint i = 0; i < 17; i++){ // 64-81 552 ret[64+i] = r3[i]; 553 } 554 555 return string(ret); 556 } 557 558 // Calls the ADK (gadk) Signature Validation Routine via the overloaded keccak function 559 560 function CurlValidateSignature(string memory addr, string memory signature, string memory bundle) internal pure returns (bool){ 561 562 bytes memory pdata = bytes(string(abi.encodePacked("{CURL}", "VALSIG", addr,signature,bundle))); 563 bytes32 result = keccak256(pdata); 564 565 return uint(result)==0; // must be 0, only then the signature is valid 566 } 567 568 // substring helper function 569 function substring(string memory str, uint32 startIndex, uint32 endIndex) internal pure returns (string memory ) { 570 bytes memory strBytes = bytes(str); 571 bytes memory result = new bytes(endIndex-startIndex); 572 for(uint32 i = startIndex; i < endIndex; i++) { 573 result[i-startIndex] = strBytes[i]; 574 } 575 return string(result); 576 } 577 578 // subbytes helper function 579 function subbytes(bytes memory strBytes, uint startIndex, uint endIndex) internal pure returns (bytes memory ) { 580 bytes memory result = new bytes(endIndex-startIndex); 581 for(uint i = startIndex; i < endIndex; i++) { 582 result[i-startIndex] = strBytes[i]; 583 } 584 return result; 585 } 586 587 // concat (strings) helper function 588 function concat(string memory a, string memory b) internal pure returns (string memory) { 589 return string(abi.encodePacked(a, b,"","","")); 590 } 591 592 // 593 // Modifiers ///////////////////////////////////////////////// 594 // 595 596 modifier mod_requireAZ9 (string memory _adk_string) { 597 bytes memory adkBytes = bytes (_adk_string); 598 require(adkBytes.length >= 1 ); 599 600 bool valid = true; 601 for (uint i = 0; i < adkBytes.length; i++) { 602 if ( 603 ! ( 604 uint8(adkBytes[i]) == 57 //9 605 || (uint8(adkBytes[i]) >= 65 && uint8(adkBytes[i]) <= 90) //A-Z 606 ) 607 ) valid = false; 608 } 609 require (valid, "INVALID TRYTES"); 610 _; 611 } 612 613 // MODIFIERS 614 615 modifier onlyGenesis { 616 require(msg.sender == adkgo_genesis_address, "NOT AUTHORIZED"); 617 _; 618 } 619 620 }