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 }