github.com/aidoskuneen/adk-node@v0.0.0-20220315131952-2e32567cb7f4/adkgo-GENESIS/contracts/ADKToken.sol (about)

     1      pragma solidity >0.8.4;
     2  
     3  import "contracts/ADKTransactions.sol";
     4  import "contracts/AGSClaim.sol";
     5  
     6  contract ADKToken {
     7  
     8      // ADKGO Genesis Contract for ADK / Migration Contract / Migration Snapshot
     9      //
    10      // This contract handles the ERC20 interface as well as the AZ9 total ADK balances
    11      // 
    12      // The ADKToken Contract is part of the migration engine allowing users to migrate from AZ9 Mesh and ERC20 ADK to the
    13      // new native ADK coin
    14      //
    15      // Note: this contract facilitates a ONE-WAY direction transfer from AZ9 --> ERC20 ADK and then from ERC20 ADK --> Native ADK  
    16      //
    17      uint256 public totalSupply;
    18        
    19      uint256 constant private MAX_UINT256 = 2**256 - 1;
    20      
    21      mapping (address => uint256) public balances;      // balances and mesh-balances are always identical, just different representation of the account 
    22      
    23      mapping (address => address) public linked_list_all_balances; // a linked ring with all addresses that have a balance, with the ADKTransactionsContract as the root element
    24      mapping (address => address) linked_list_all_balances_reverse; // a reversed linked ring with all addresses that have a balance
    25      
    26      mapping (address => mapping (address => uint256)) public allowed;
    27      
    28      mapping (address => string) public known_addresses;
    29      
    30      string public name;     // Aidos Kuneen ADK
    31      uint8 public decimals;  // 8
    32      string public symbol;   // ADK
    33      
    34      address public adkgo_genesis_address;  // the 'mesh owner', holds all token still inside the ADK Mesh (if not in circulation as wADK)
    35      
    36      ADKTransactions public ADKTransactionsContract; // the contract that validates MESH transactions
    37      AGSClaim public AGSClaimContract; // contract to claim airdropped AGS
    38      // CONSTRUCTOR
    39      constructor() {
    40          
    41          // build Genesis contract structure
    42          adkgo_genesis_address = msg.sender;
    43          AGSClaimContract = new AGSClaim(adkgo_genesis_address, address(this));
    44          ADKTransactionsContract = new ADKTransactions(adkgo_genesis_address, address(this));
    45          
    46          name = "ADK"; //_tokenName;                               // Set the name for display purposes
    47          decimals = 8; //_decimalUnits;                            // Amount of decimals for display purposes (8 for ADK)
    48          symbol = "\u24B6"; // _tokenSymbol;                       // Set the symbol for display purposes
    49          //balances[msg.sender] = 2500000000000000;//_initialAmount; // Give the mesh address all initial tokens
    50          //totalSupply = 2500000000000000;//_initialAmount;          // 2500000000000000 ADK
    51          balances[msg.sender] = 0;//_initialAmount; // not required any more
    52          totalSupply = 0;//_initialAmount;         // not required any more
    53          
    54          // prepare the linked list
    55          linked_list_all_balances[address(ADKTransactionsContract)] = address(ADKTransactionsContract);
    56          linked_list_all_balances_reverse[address(ADKTransactionsContract)] = address(ADKTransactionsContract);
    57          
    58      }
    59  
    60      // this updates the ring of all balances (ADK ERC20, not ADKTransactionsContract) that hold a value
    61      function UpdateBalanceRing(address _addr) internal {
    62          if (_addr == address(ADKTransactionsContract)) return; // do nothing on ADKTransactionsContract
    63          bool address_in_ring = linked_list_all_balances[_addr] != address(0);
    64          
    65          if (balances[_addr] == 0){ // if balance is 0, remove from the ring.
    66              if (address_in_ring){ //it exists
    67                  address _next  = linked_list_all_balances[_addr];
    68                  address _prev  = linked_list_all_balances_reverse[_addr];
    69                  linked_list_all_balances[_prev] = _next; // remove _addr
    70                  linked_list_all_balances_reverse[_next] = _prev;  // remove _addr
    71                  linked_list_all_balances[_addr] = address(0);  // set _addr mapping to 0
    72                  linked_list_all_balances_reverse[_addr] = address(0);  // set _addr mapping to 0
    73              }
    74          }
    75          else { // check if already in ring, then do nothing
    76              if ( ! address_in_ring){ // if it doesnt exist, we add it to the ring after the ADKTransactionsContract (first element))
    77                  address _next = linked_list_all_balances[address(ADKTransactionsContract)];
    78                  linked_list_all_balances[address(ADKTransactionsContract)] = _addr; // insert forward
    79                  linked_list_all_balances[_addr] = _next;
    80                  
    81                  linked_list_all_balances_reverse[_next] = _addr; // insert backwards
    82                  linked_list_all_balances_reverse[_addr] = address(ADKTransactionsContract);
    83              }
    84          }
    85      }
    86  
    87      // ERC20 ADK events
    88      
    89      // solhint-disable-next-line no-simple-event-func-name
    90      event Transfer(address indexed _from, address indexed _to, uint256 _value);
    91      event Approval(address indexed _owner, address indexed _spender, uint256 _value);
    92      
    93      //AZ9Transfer is for transactions from/to the mesh. As there is no direct from/to relationship,
    94      //   there is no from/to counterpart, just a transaction positive or negative.
    95      event AZ9Transfer(string indexed _meshaddr, address indexed _addr, int256 _value);
    96      
    97      // Standard ERC20 transfer Function
    98      function transfer(address _to, uint256 _value) public returns (bool success) {
    99          // require(balances[msg.sender] >= _value);
   100          // require(address(this) != _to); // prevent accidental send of tokens to the contract itself
   101          // balances[msg.sender] -= _value;
   102          // balances[_to] += _value;
   103          
   104          // // now we notify the receiving contract (if it exists)
   105          // // Note: This is to allow other smart contracts to 'react' to receiving ADK token.
   106          
   107          // require(notifyReceiver(msg.sender, _to, _value), "CALLED CONTRACT (notifyReceiver) REVERTED EXECUTION.");
   108          
   109          // UpdateBalanceRing(msg.sender); // update ring of addresses with balances as needed
   110          // UpdateBalanceRing(_to); // update ring of addresses with balances as needed
   111          
   112          // emit Transfer(msg.sender, _to, _value); //solhint-disable-line indent, no-unused-vars
   113          // return true;
   114          require(false, "function not implemented"); //don't need ERC20 version any more
   115      }
   116  
   117      // Standard ERC20 transferFrom Function
   118      function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) {
   119          // uint256 vallowance = allowed[_from][msg.sender];
   120          // require(balances[_from] >= _value && vallowance >= _value);
   121          // balances[_to] += _value;
   122          // balances[_from] -= _value;
   123          // if (vallowance < MAX_UINT256) {
   124          //     allowed[_from][msg.sender] -= _value;
   125          // }
   126          // // now we notify the receiving contract (if it exists)
   127          // // Note: This is to allow other smart contracts to 'react' to receiving ADK token.
   128         
   129          // require(notifyReceiver(_from, _to, _value), "CALLED CONTRACT (notifyReceiver) REVERTED.");
   130          
   131          // UpdateBalanceRing(msg.sender); // update ring of addresses with balances as needed
   132          // UpdateBalanceRing(_to); // update ring of addresses with balances as needed
   133          
   134          // emit Transfer(_from, _to, _value); //solhint-disable-line indent, no-unused-vars
   135          // return true;
   136           require(false, "function not implemented"); //don't need ERC20 version any more
   137      }
   138      
   139      // Standard ERC20 approve Function
   140      function approve(address _spender, uint256 _value) public returns (bool success) {
   141          // allowed[msg.sender][_spender] = _value;
   142          // emit Approval(msg.sender, _spender, _value); //solhint-disable-line indent, no-unused-vars
   143          // return true;
   144           require(false, "function not implemented"); //don't need ERC20 version any more
   145      }
   146  
   147      // Standard ERC20 balanceOf Function
   148      function balanceOf(address _owner) public view returns (uint256 balance) {
   149          return balances[_owner];
   150      }
   151  
   152       // Standard ERC20 allowance Function
   153      function allowance(address _owner, address _spender) public view returns (uint256 remaining) {
   154          return allowed[_owner][_spender];
   155      }
   156      
   157      /// END DEFAULT ERC20 FUNCTIONS
   158      
   159       // notifyReceiver: to notify contracts that received tokens via standard ERC20 transactions,
   160       //                 this allows ERC transfer triggered smart contract operations
   161       //
   162       // note the GAS is limited here to  10000 gas to prevent spam
   163       //
   164       function notifyReceiver(address _from, address _to, uint256 _value) internal returns (bool) {
   165            (bool success, bytes memory data) = _to.call{value: 0, gas: 10000}(
   166                      abi.encodeWithSignature("ADKERC20TransactionNotify(address,address,uint256)", _from, _to, _value)
   167              );
   168            return success;
   169       }
   170          
   171      
   172      // MESH TRANSACTION FUNCTIONS, CAN ONLY BE CALLED BY THE ADKTransaction Contract
   173      // Note: these are one-sided transaction as the ADK Transaction contract handles these individually, ensuring they total 0 across bundles
   174      // and there can be a combination of 1-n FROM and 1-m TO addresses
   175  
   176      function meshTransaction(string memory _meshaddr, int256 _value) public onlyADKTransactionContract requireValidADKAddress(_meshaddr) {
   177          
   178          address addr = AZ9_TO_ADDR(_meshaddr); // convert an AZ9 address to an 'address' address
   179          
   180          known_addresses[addr] = _meshaddr; // store known mapping
   181          
   182          require(int(balances[addr]) + _value >= 0, "Critical: Invalid transaction, insufficient amount");
   183          
   184          balances[addr] = uint(int(balances[addr]) + _value); // update balance
   185          //
   186          UpdateBalanceRing(addr); // update ring of addresses with balances as needed
   187          //
   188          emit AZ9Transfer(_meshaddr, addr, _value); //solhint-disable-line indent, no-unused-vars
   189      }
   190      
   191      
   192      event GENESISTransaction(string indexed _meshaddr, address indexed _addr, int256 _value);
   193      
   194  
   195      // balanceOf Function for ADK style addresses
   196      //
   197      // Note: uses 81 char addresses (no checksum!)
   198      function AZ9balanceOf(string memory _adkAddr) public view returns (uint256 balance) {
   199          return balances[AZ9_TO_ADDR(_adkAddr)];
   200      }
   201  
   202      // performs a genesis transaction, i.e. load initial Snapshot balances for Mesh AZ9 balances
   203      
   204      function genesisTransaction(string memory _meshaddr, int256 _value) public onlyGenesis requireValidADKAddress(_meshaddr) {
   205          address addr = AZ9_TO_ADDR(_meshaddr);
   206          known_addresses[addr] = _meshaddr; // store known mapping
   207          balances[addr] = uint(int(balances[addr]) + _value);
   208          // sync with main balances
   209          emit GENESISTransaction(_meshaddr, addr, _value); //solhint-disable-line indent, no-unused-vars
   210      }
   211      
   212      function registerAddress(string memory _meshaddr) public requireValidADKAddress(_meshaddr) {
   213          address addr = AZ9_TO_ADDR(_meshaddr);
   214          known_addresses[addr] = _meshaddr; // store known mapping
   215      }
   216      
   217      ////////////////////////////////////////////////////////
   218      // MODIFIERS
   219  
   220      modifier onlyGenesis {
   221          require(msg.sender == adkgo_genesis_address,"NOT OWNER");
   222          _;
   223      }
   224      
   225      modifier onlyADKTransactionContract {
   226          require(msg.sender == address(ADKTransactionsContract), "NOT ADK CONTRACT");
   227          _;
   228      }
   229      
   230      // Check if an address only contains 9A-Z, and is 81 char long
   231      modifier requireValidADKAddress (string memory _adk_address) {
   232          bool valid = true;
   233          bytes memory adkBytes = bytes (_adk_address);
   234          require(adkBytes.length == 81); //address without checksum
   235          
   236          for (uint i = 0; i < adkBytes.length; i++) {
   237              if ( 
   238                  ! (
   239                      uint8(adkBytes[i]) == 57 //9
   240                       || (uint8(adkBytes[i]) >= 65 && uint8(adkBytes[i]) <= 90) //A-Z
   241                    )
   242                 ) valid = false;
   243          }
   244          require (valid,"INVALID ADK ADDRESS");
   245          _;
   246      } 
   247       
   248      // CONVERTER functions to translate from AZ9 addressses (Mesh Format) to 0x style Addresses
   249      
   250      // encode a 0x type address in a 9AZ format. This is needed e.g. when sending from the original ADK wallet 
   251      // to a 0x type address (as ADK Token)
   252      
   253      function ADDR_TO_AZ9 (address ethAddr) public pure returns(string memory) {
   254           return BADDR_TO_AZ9(abi.encodePacked(ethAddr));
   255      }
   256      
   257       // byte version of ADDR_TO_AZ9 / helper function
   258      function BADDR_TO_AZ9 (bytes memory ethAddr) public pure returns(string memory) {
   259           bytes memory alphabet = "GHIJKLMNOPABCDEF"; // really only the first 16 char used...
   260                                                                  // A-F remains A-F,  0-9 becomes GHI...
   261           require(ethAddr.length == 20); //20 bytes / an 0x address 
   262      
   263           bytes memory str = new bytes(81);
   264           string memory header = "ZEROXADDRESS99";
   265           bytes memory header_b = bytes(header);
   266           for (uint i = 0; i < header_b.length; i++) { // len 13
   267                str[i] = header_b[i];
   268           }
   269           
   270           for (uint i = 7; i < 27; i++) {//first 40 chars (20 but double)
   271               str[i*2+1] = alphabet[uint(uint8(ethAddr[i-7] & 0x0f))]; // first hex char of set of 2
   272               str[i*2] = alphabet[uint(uint8(ethAddr[i-7] >> 4))];     // second hex char of set of 2
   273           }
   274           for (uint i = 54; i < 81; i++) { // rest 9s
   275               str[i] = 0x39; // 0x39 = "9"
   276           }
   277           return string(str);
   278      }
   279      
   280      // convert AZ9 string to 0x Address:
   281      //    uses 2-way format if it is a ZEROXADDRESS9 (meaning its actually a 0x address encoded as 0x address, so its 2 way convertible)
   282      //    Otherwise, we are using a 1-way keccak hash, which is used to store the actual address balance
   283      
   284      function AZ9_TO_ADDR (string memory adkString) public pure requireValidADKAddress(adkString) returns(address) {
   285          // 2-way conversion for ZEROXADDRESS9 addresses, and one-way conversions for others
   286          string memory header = "ZEROXADDRESS99";
   287          bytes memory header_b = bytes(header);
   288          bytes memory adkString_b = bytes(adkString);
   289          bool twoWay = true;
   290          
   291          bytes memory str = new bytes(20); //2*40 hex char plus leading 0x
   292           
   293          // check header for 2-WAY ID
   294          for (uint i = 0; twoWay && i < header_b.length; i++) { // len 13
   295                if (adkString_b[i] != header_b[i]) twoWay = false;
   296          }
   297          
   298          if (twoWay){ // found header flag, now validate remainder
   299              // check trailing 999s
   300               for (uint i = 7; i < 27; i++) {//first 40 chars have to be between 'A' and 'P'
   301                   require(adkString_b[i*2+1] >= 0x41 && adkString_b[i*2+1] <= 0x50,"MALFORMED 0x AZ9 ADDRESS"); // 0x39 = "9"
   302                   require(adkString_b[i*2] >= 0x41 && adkString_b[i*2] <= 0x50,"MALFORMED 0x AZ9 ADDRESS"); // 0x39 = "9"
   303                   //  translate
   304                   uint8 low;
   305                   uint8 high;
   306                   if (adkString_b[i*2+1] <= 0x46){ // A-F
   307                      low = uint8(adkString_b[i*2+1]) - 65 + 10; // A=10 B=11 etc...
   308                   } else { // G-P  0-9
   309                      low = uint8(adkString_b[i*2+1]) - 71; // G=0, H=1,....
   310                   }
   311                   if (adkString_b[i*2] <= 0x46){ // A-F
   312                      high = uint8(adkString_b[i*2]) - 65 + 10; // A=10 B=11 etc...
   313                   } else { // G-P  0-9
   314                      high = uint8(adkString_b[i*2]) - 71; // G=0, H=1,....
   315                   }
   316                   str[i-7] = bytes1(high * 16 + low); // High+Low Hex Char 
   317               }
   318               // check trailing 999s
   319               for (uint i = 54; i < 81; i++) {//first 40 chars (20 but double)
   320                   require(adkString_b[i] == 0x39,"MALFORMED 0x AZ9 ADDRESS"); // 0x39 = "9"
   321               }
   322              //
   323              return utilBytesToAddress(str);
   324              //
   325          } else { // not a dedicated 0x Address, so 1-way translate
   326              //
   327              return utilBytesToAddress(keccak256(adkString_b));
   328              //
   329          }
   330      }
   331      
   332      // helper function just to show AGS balance (note not ADK)
   333      function AGSBalanceOf (address _addr) public view returns (uint256 balance) {
   334          return _addr.balance;
   335      }
   336      
   337       // utilBytesToAddress: Helper function to convert 20 bytes to a properly formated Ethereum address
   338      
   339      function utilBytesToAddress(bytes memory bys) private pure returns (address addr) {
   340          require(bys.length == 20);
   341          assembly {
   342            addr := mload(add(bys,20))
   343          } 
   344      }
   345      
   346      function utilBytesToAddress(bytes32 bys) private pure returns (address addr) {
   347          bytes memory b = new bytes(20);
   348          for (uint i = 0; i < 20; i++) {
   349              b[i] = bys[i];
   350          }
   351          return utilBytesToAddress(b);
   352      }
   353      
   354  }