diff --git a/heliades-scripts/index.js b/heliades-scripts/index.js index f9f38516..78c61498 100644 --- a/heliades-scripts/index.js +++ b/heliades-scripts/index.js @@ -26,7 +26,10 @@ const abi = [ { "internalType": "string", "name": "denom", "type": "string" }, { "internalType": "uint256", "name": "totalSupply", "type": "uint256" }, { "internalType": "uint8", "name": "decimals", "type": "uint8" }, - { "internalType": "string", "name": "logoBase64", "type": "string" } + { "internalType": "string", "name": "logoBase64", "type": "string" }, + { "internalType": "address", "name": "mintAuthority", "type": "address" }, + { "internalType": "address", "name": "pauseAuthority", "type": "address" }, + { "internalType": "address", "name": "burnAuthority", "type": "address" } ], "name": "createErc20", "outputs": [ @@ -37,6 +40,8 @@ const abi = [ } ]; + + const delegateAbi = [ { "inputs": [ @@ -188,23 +193,38 @@ const contract = new ethers.Contract(PRECOMPILE_CONTRACT_ADDRESS, abi, wallet); const tokenName = 'BTC2'; const tokenSymbol = 'BTC2'; const tokenDenom = 'uBTC222'; // denomination of one unit of the token -const tokenTotalSupply = ethers.parseUnits('100', 18); +const tokenTotalSupply = ethers.parseUnits('1000', 18); const tokenDecimals = 18; -async function create(){ - try { - console.log('Création du token ERC20...'); - - const tx = await contract.createErc20(tokenName, tokenSymbol, tokenDenom, tokenTotalSupply, tokenDecimals, ""); - console.log('Transaction envoyée, hash :', tx.hash); +const mintAuthority = "0x0000000000000000000000000000000000000000"; // address(0) = non-mintable +const pauseAuthority = "0x0000000000000000000000000000000000000000"; // address(0) = non-pausable +const burnAuthority = "0x0000000000000000000000000000000000000000"; // address(0) = no special burn authority - const receipt = await tx.wait(); - console.log('Transaction confirmée dans le bloc :', receipt.blockNumber); - - console.log("Contract address :", receipt.logs[0].data); +async function create() { + try { + console.log('Creating ERC20 token...'); + + // Updated call with 9 parameters instead of 6 + const tx = await contract.createErc20( + tokenName, + tokenSymbol, + tokenDenom, + tokenTotalSupply, + tokenDecimals, + "", // logoBase64 + mintAuthority, // NEW: Who can mint (address(0) = nobody) + pauseAuthority, // NEW: Who can pause (address(0) = nobody) + burnAuthority // NEW: Who can burn (address(0) = nobody) + ); + + console.log('Transaction sent, hash:', tx.hash); + const receipt = await tx.wait(); + console.log('Transaction confirmed in block:', receipt.blockNumber); + console.log("Contract address:", receipt.logs[0].data); + } catch (error) { - console.error('Une erreur est survenue :', error); + console.error('An error occurred:', error); } } @@ -718,12 +738,12 @@ async function uploadLogo() { async function main() { // await createCronCallBackData(); - await createCron(); + //await createCron(); // await getEvents(); // await getEventsCronCancelled(); // await cancelCron(); // await getEventsEVMCallScheduled(); - // await create(); + await create(); //await fetch(); // await delegate(); // await addNewConsensusProposal(); diff --git a/helios-chain/contracts/solidity/ERC20MinterBurnerDecimals.json b/helios-chain/contracts/solidity/ERC20MinterBurnerDecimals.json index 7e1c5bd8..ddb5d8cc 100644 --- a/helios-chain/contracts/solidity/ERC20MinterBurnerDecimals.json +++ b/helios-chain/contracts/solidity/ERC20MinterBurnerDecimals.json @@ -19,6 +19,26 @@ "internalType": "uint8", "name": "decimals_", "type": "uint8" + }, + { + "internalType": "address", + "name": "initialOwner", + "type": "address" + }, + { + "internalType": "address", + "name": "mintAuthority", + "type": "address" + }, + { + "internalType": "address", + "name": "pauseAuthority", + "type": "address" + }, + { + "internalType": "address", + "name": "burnAuthority", + "type": "address" } ], "stateMutability": "nonpayable", @@ -644,7 +664,7 @@ "inputs": [ { "internalType": "address", - "name": "to", + "name": "recipient", "type": "address" }, { @@ -668,12 +688,12 @@ "inputs": [ { "internalType": "address", - "name": "from", + "name": "sender", "type": "address" }, { "internalType": "address", - "name": "to", + "name": "recipient", "type": "address" }, { @@ -701,8 +721,8 @@ "type": "function" } ], - "bytecode": "0x60806040523480156200001157600080fd5b5060405162003c3638038062003c368339818101604052810190620000379190620005f6565b828281600590816200004a9190620008db565b5080600690816200005c9190620008db565b5050506000600760006101000a81548160ff0219169083151502179055506200009e6000801b620000926200017b60201b60201c565b6200018360201b60201c565b620000df7f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a6620000d36200017b60201b60201c565b6200018360201b60201c565b620001207f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a620001146200017b60201b60201c565b6200018360201b60201c565b620001617f3c11d16cbaffd01df69ce1c404f6340ee057498f5f00246190ea54220576a848620001556200017b60201b60201c565b6200018360201b60201c565b62000172816200019960201b60201c565b505050620009c2565b600033905090565b620001958282620001b760201b60201c565b5050565b80600760016101000a81548160ff021916908360ff16021790555050565b620001c98282620001f560201b60201c565b620001f08160016000858152602001908152602001600020620002e660201b90919060201c565b505050565b6200020782826200031e60201b60201c565b620002e257600160008084815260200190815260200160002060000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908315150217905550620002876200017b60201b60201c565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45b5050565b600062000316836000018373ffffffffffffffffffffffffffffffffffffffff1660001b6200038860201b60201c565b905092915050565b600080600084815260200190815260200160002060000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16905092915050565b60006200039c83836200040260201b60201c565b620003f7578260000182908060018154018082558091505060019003906000526020600020016000909190919091505582600001805490508360010160008481526020019081526020016000208190555060019050620003fc565b600090505b92915050565b600080836001016000848152602001908152602001600020541415905092915050565b6000604051905090565b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6200048e8262000443565b810181811067ffffffffffffffff82111715620004b057620004af62000454565b5b80604052505050565b6000620004c562000425565b9050620004d3828262000483565b919050565b600067ffffffffffffffff821115620004f657620004f562000454565b5b620005018262000443565b9050602081019050919050565b60005b838110156200052e57808201518184015260208101905062000511565b60008484015250505050565b6000620005516200054b84620004d8565b620004b9565b90508281526020810184848401111562000570576200056f6200043e565b5b6200057d8482856200050e565b509392505050565b600082601f8301126200059d576200059c62000439565b5b8151620005af8482602086016200053a565b91505092915050565b600060ff82169050919050565b620005d081620005b8565b8114620005dc57600080fd5b50565b600081519050620005f081620005c5565b92915050565b6000806000606084860312156200061257620006116200042f565b5b600084015167ffffffffffffffff81111562000633576200063262000434565b5b620006418682870162000585565b935050602084015167ffffffffffffffff81111562000665576200066462000434565b5b620006738682870162000585565b92505060406200068686828701620005df565b9150509250925092565b600081519050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b60006002820490506001821680620006e357607f821691505b602082108103620006f957620006f86200069b565b5b50919050565b60008190508160005260206000209050919050565b60006020601f8301049050919050565b600082821b905092915050565b600060088302620007637fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8262000724565b6200076f868362000724565b95508019841693508086168417925050509392505050565b6000819050919050565b6000819050919050565b6000620007bc620007b6620007b08462000787565b62000791565b62000787565b9050919050565b6000819050919050565b620007d8836200079b565b620007f0620007e782620007c3565b84845462000731565b825550505050565b600090565b62000807620007f8565b62000814818484620007cd565b505050565b5b818110156200083c5762000830600082620007fd565b6001810190506200081a565b5050565b601f8211156200088b576200085581620006ff565b620008608462000714565b8101602085101562000870578190505b620008886200087f8562000714565b83018262000819565b50505b505050565b600082821c905092915050565b6000620008b06000198460080262000890565b1980831691505092915050565b6000620008cb83836200089d565b9150826002028217905092915050565b620008e68262000690565b67ffffffffffffffff81111562000902576200090162000454565b5b6200090e8254620006ca565b6200091b82828562000840565b600060209050601f8311600181146200095357600084156200093e578287015190505b6200094a8582620008bd565b865550620009ba565b601f1984166200096386620006ff565b60005b828110156200098d5784890151825560018201915060208501945060208101905062000966565b86831015620009ad5784890151620009a9601f8916826200089d565b8355505b6001600288020188555050505b505050505050565b61326480620009d26000396000f3fe608060405234801561001057600080fd5b50600436106101da5760003560e01c80635c975abb11610104578063a217fddf116100a2578063d539139311610071578063d53913931461057d578063d547741f1461059b578063dd62ed3e146105b7578063e63ab1e9146105e7576101da565b8063a217fddf146104cf578063a457c2d7146104ed578063a9059cbb1461051d578063ca15c8731461054d576101da565b80638456cb59116100de5780638456cb59146104475780639010d07c1461045157806391d148541461048157806395d89b41146104b1576101da565b80635c975abb146103dd57806370a08231146103fb57806379cc67901461042b576101da565b8063282c51f31161017c578063395093511161014b578063395093511461036b5780633f4ba83a1461039b57806340c10f19146103a557806342966c68146103c1576101da565b8063282c51f3146102f75780632f2ff15d14610315578063313ce5671461033157806336568abe1461034f576101da565b806318160ddd116101b857806318160ddd1461025d5780631cf2c7e21461027b57806323b872dd14610297578063248a9ca3146102c7576101da565b806301ffc9a7146101df57806306fdde031461020f578063095ea7b31461022d575b600080fd5b6101f960048036038101906101f491906120ab565b610605565b60405161020691906120f3565b60405180910390f35b61021761067f565b604051610224919061219e565b60405180910390f35b61024760048036038101906102429190612254565b610711565b60405161025491906120f3565b60405180910390f35b610265610734565b60405161027291906122a3565b60405180910390f35b61029560048036038101906102909190612254565b61073e565b005b6102b160048036038101906102ac91906122be565b6107bc565b6040516102be91906120f3565b60405180910390f35b6102e160048036038101906102dc9190612347565b6107eb565b6040516102ee9190612383565b60405180910390f35b6102ff61080a565b60405161030c9190612383565b60405180910390f35b61032f600480360381019061032a919061239e565b61082e565b005b61033961084f565b60405161034691906123fa565b60405180910390f35b6103696004803603810190610364919061239e565b610866565b005b61038560048036038101906103809190612254565b6108e9565b60405161039291906120f3565b60405180910390f35b6103a3610920565b005b6103bf60048036038101906103ba9190612254565b61099a565b005b6103db60048036038101906103d69190612415565b610a18565b005b6103e5610a2c565b6040516103f291906120f3565b60405180910390f35b61041560048036038101906104109190612442565b610a43565b60405161042291906122a3565b60405180910390f35b61044560048036038101906104409190612254565b610a8c565b005b61044f610aac565b005b61046b6004803603810190610466919061246f565b610b26565b60405161047891906124be565b60405180910390f35b61049b6004803603810190610496919061239e565b610b55565b6040516104a891906120f3565b60405180910390f35b6104b9610bbf565b6040516104c6919061219e565b60405180910390f35b6104d7610c51565b6040516104e49190612383565b60405180910390f35b61050760048036038101906105029190612254565b610c58565b60405161051491906120f3565b60405180910390f35b61053760048036038101906105329190612254565b610ccf565b60405161054491906120f3565b60405180910390f35b61056760048036038101906105629190612347565b610cf2565b60405161057491906122a3565b60405180910390f35b610585610d16565b6040516105929190612383565b60405180910390f35b6105b560048036038101906105b0919061239e565b610d3a565b005b6105d160048036038101906105cc91906124d9565b610d5b565b6040516105de91906122a3565b60405180910390f35b6105ef610de2565b6040516105fc9190612383565b60405180910390f35b60007f5a05180f000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161480610678575061067782610e06565b5b9050919050565b60606005805461068e90612548565b80601f01602080910402602001604051908101604052809291908181526020018280546106ba90612548565b80156107075780601f106106dc57610100808354040283529160200191610707565b820191906000526020600020905b8154815290600101906020018083116106ea57829003601f168201915b5050505050905090565b60008061071c610e80565b9050610729818585610e88565b600191505092915050565b6000600454905090565b61076f7f3c11d16cbaffd01df69ce1c404f6340ee057498f5f00246190ea54220576a84861076a610e80565b610b55565b6107ae576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107a5906125eb565b60405180910390fd5b6107b88282611051565b5050565b6000806107c7610e80565b90506107d4858285611220565b6107df8585856112ac565b60019150509392505050565b6000806000838152602001908152602001600020600101549050919050565b7f3c11d16cbaffd01df69ce1c404f6340ee057498f5f00246190ea54220576a84881565b610837826107eb565b61084081611525565b61084a8383611539565b505050565b6000600760019054906101000a900460ff16905090565b61086e610e80565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16146108db576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108d29061267d565b60405180910390fd5b6108e5828261156d565b5050565b6000806108f4610e80565b90506109158185856109068589610d5b565b61091091906126cc565b610e88565b600191505092915050565b6109517f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a61094c610e80565b610b55565b610990576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161098790612772565b60405180910390fd5b6109986115a1565b565b6109cb7f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a66109c6610e80565b610b55565b610a0a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a0190612804565b60405180910390fd5b610a148282611604565b5050565b610a29610a23610e80565b82611051565b50565b6000600760009054906101000a900460ff16905090565b6000600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b610a9e82610a98610e80565b83611220565b610aa88282611051565b5050565b610add7f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a610ad8610e80565b610b55565b610b1c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b1390612896565b60405180910390fd5b610b2461175b565b565b6000610b4d82600160008681526020019081526020016000206117be90919063ffffffff16565b905092915050565b600080600084815260200190815260200160002060000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16905092915050565b606060068054610bce90612548565b80601f0160208091040260200160405190810160405280929190818152602001828054610bfa90612548565b8015610c475780601f10610c1c57610100808354040283529160200191610c47565b820191906000526020600020905b815481529060010190602001808311610c2a57829003601f168201915b5050505050905090565b6000801b81565b600080610c63610e80565b90506000610c718286610d5b565b905083811015610cb6576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610cad90612928565b60405180910390fd5b610cc38286868403610e88565b60019250505092915050565b600080610cda610e80565b9050610ce78185856112ac565b600191505092915050565b6000610d0f600160008481526020019081526020016000206117d8565b9050919050565b7f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a681565b610d43826107eb565b610d4c81611525565b610d56838361156d565b505050565b6000600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905092915050565b7f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a81565b60007f7965db0b000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161480610e795750610e78826117ed565b5b9050919050565b600033905090565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603610ef7576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610eee906129ba565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610f66576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f5d90612a4c565b60405180910390fd5b80600360008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258360405161104491906122a3565b60405180910390a3505050565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036110c0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016110b790612ade565b60405180910390fd5b6110cc82600083611857565b6000600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905081811015611153576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161114a90612b70565b60405180910390fd5b818103600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555081600460008282540392505081905550600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8460405161120791906122a3565b60405180910390a361121b83600084611867565b505050565b600061122c8484610d5b565b90507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146112a65781811015611298576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161128f90612bdc565b60405180910390fd5b6112a58484848403610e88565b5b50505050565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff160361131b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161131290612c6e565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff160361138a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161138190612d00565b60405180910390fd5b611395838383611857565b6000600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490508181101561141c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161141390612d92565b60405180910390fd5b818103600260008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555081600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8460405161150c91906122a3565b60405180910390a361151f848484611867565b50505050565b61153681611531610e80565b61186c565b50565b61154382826118f1565b61156881600160008581526020019081526020016000206119d190919063ffffffff16565b505050565b6115778282611a01565b61159c8160016000858152602001908152602001600020611ae290919063ffffffff16565b505050565b6115a9611b12565b6000600760006101000a81548160ff0219169083151502179055507f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa6115ed610e80565b6040516115fa91906124be565b60405180910390a1565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603611673576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161166a90612dfe565b60405180910390fd5b61167f60008383611857565b806004600082825461169191906126cc565b9250508190555080600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508173ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8360405161174391906122a3565b60405180910390a361175760008383611867565b5050565b611763611b5b565b6001600760006101000a81548160ff0219169083151502179055507f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586117a7610e80565b6040516117b491906124be565b60405180910390a1565b60006117cd8360000183611ba5565b60001c905092915050565b60006117e682600001611bd0565b9050919050565b60007f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b611862838383611be1565b505050565b505050565b6118768282610b55565b6118ed5761188381611c39565b6118918360001c6020611c66565b6040516020016118a2929190612ef2565b6040516020818303038152906040526040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016118e4919061219e565b60405180910390fd5b5050565b6118fb8282610b55565b6119cd57600160008084815260200190815260200160002060000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908315150217905550611972610e80565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45b5050565b60006119f9836000018373ffffffffffffffffffffffffffffffffffffffff1660001b611ea2565b905092915050565b611a0b8282610b55565b15611ade57600080600084815260200190815260200160002060000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908315150217905550611a83610e80565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16837ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b60405160405180910390a45b5050565b6000611b0a836000018373ffffffffffffffffffffffffffffffffffffffff1660001b611f12565b905092915050565b611b1a610a2c565b611b59576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611b5090612f78565b60405180910390fd5b565b611b63610a2c565b15611ba3576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611b9a90612fe4565b60405180910390fd5b565b6000826000018281548110611bbd57611bbc613004565b5b9060005260206000200154905092915050565b600081600001805490509050919050565b611bec838383612026565b611bf4610a2c565b15611c34576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611c2b906130a5565b60405180910390fd5b505050565b6060611c5f8273ffffffffffffffffffffffffffffffffffffffff16601460ff16611c66565b9050919050565b606060006002836002611c7991906130c5565b611c8391906126cc565b67ffffffffffffffff811115611c9c57611c9b613107565b5b6040519080825280601f01601f191660200182016040528015611cce5781602001600182028036833780820191505090505b5090507f300000000000000000000000000000000000000000000000000000000000000081600081518110611d0657611d05613004565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053507f780000000000000000000000000000000000000000000000000000000000000081600181518110611d6a57611d69613004565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060006001846002611daa91906130c5565b611db491906126cc565b90505b6001811115611e54577f3031323334353637383961626364656600000000000000000000000000000000600f861660108110611df657611df5613004565b5b1a60f81b828281518110611e0d57611e0c613004565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350600485901c945080611e4d90613136565b9050611db7565b5060008414611e98576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611e8f906131ab565b60405180910390fd5b8091505092915050565b6000611eae838361202b565b611f07578260000182908060018154018082558091505060019003906000526020600020016000909190919091505582600001805490508360010160008481526020019081526020016000208190555060019050611f0c565b600090505b92915050565b6000808360010160008481526020019081526020016000205490506000811461201a576000600182611f4491906131cb565b9050600060018660000180549050611f5c91906131cb565b9050818114611fcb576000866000018281548110611f7d57611f7c613004565b5b9060005260206000200154905080876000018481548110611fa157611fa0613004565b5b90600052602060002001819055508387600101600083815260200190815260200160002081905550505b85600001805480611fdf57611fde6131ff565b5b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050612020565b60009150505b92915050565b505050565b600080836001016000848152602001908152602001600020541415905092915050565b600080fd5b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b61208881612053565b811461209357600080fd5b50565b6000813590506120a58161207f565b92915050565b6000602082840312156120c1576120c061204e565b5b60006120cf84828501612096565b91505092915050565b60008115159050919050565b6120ed816120d8565b82525050565b600060208201905061210860008301846120e4565b92915050565b600081519050919050565b600082825260208201905092915050565b60005b8381101561214857808201518184015260208101905061212d565b60008484015250505050565b6000601f19601f8301169050919050565b60006121708261210e565b61217a8185612119565b935061218a81856020860161212a565b61219381612154565b840191505092915050565b600060208201905081810360008301526121b88184612165565b905092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006121eb826121c0565b9050919050565b6121fb816121e0565b811461220657600080fd5b50565b600081359050612218816121f2565b92915050565b6000819050919050565b6122318161221e565b811461223c57600080fd5b50565b60008135905061224e81612228565b92915050565b6000806040838503121561226b5761226a61204e565b5b600061227985828601612209565b925050602061228a8582860161223f565b9150509250929050565b61229d8161221e565b82525050565b60006020820190506122b86000830184612294565b92915050565b6000806000606084860312156122d7576122d661204e565b5b60006122e586828701612209565b93505060206122f686828701612209565b92505060406123078682870161223f565b9150509250925092565b6000819050919050565b61232481612311565b811461232f57600080fd5b50565b6000813590506123418161231b565b92915050565b60006020828403121561235d5761235c61204e565b5b600061236b84828501612332565b91505092915050565b61237d81612311565b82525050565b60006020820190506123986000830184612374565b92915050565b600080604083850312156123b5576123b461204e565b5b60006123c385828601612332565b92505060206123d485828601612209565b9150509250929050565b600060ff82169050919050565b6123f4816123de565b82525050565b600060208201905061240f60008301846123eb565b92915050565b60006020828403121561242b5761242a61204e565b5b60006124398482850161223f565b91505092915050565b6000602082840312156124585761245761204e565b5b600061246684828501612209565b91505092915050565b600080604083850312156124865761248561204e565b5b600061249485828601612332565b92505060206124a58582860161223f565b9150509250929050565b6124b8816121e0565b82525050565b60006020820190506124d360008301846124af565b92915050565b600080604083850312156124f0576124ef61204e565b5b60006124fe85828601612209565b925050602061250f85828601612209565b9150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b6000600282049050600182168061256057607f821691505b60208210810361257357612572612519565b5b50919050565b7f45524332304d696e7465724275726e6572446563696d616c733a206d7573742060008201527f68617665206275726e657220726f6c6520746f206275726e0000000000000000602082015250565b60006125d5603883612119565b91506125e082612579565b604082019050919050565b60006020820190508181036000830152612604816125c8565b9050919050565b7f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560008201527f20726f6c657320666f722073656c660000000000000000000000000000000000602082015250565b6000612667602f83612119565b91506126728261260b565b604082019050919050565b600060208201905081810360008301526126968161265a565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006126d78261221e565b91506126e28361221e565b92508282019050808211156126fa576126f961269d565b5b92915050565b7f45524332304d696e7465724275726e6572446563696d616c733a206d7573742060008201527f686176652070617573657220726f6c6520746f20756e70617573650000000000602082015250565b600061275c603b83612119565b915061276782612700565b604082019050919050565b6000602082019050818103600083015261278b8161274f565b9050919050565b7f45524332304d696e7465724275726e6572446563696d616c733a206d7573742060008201527f68617665206d696e74657220726f6c6520746f206d696e740000000000000000602082015250565b60006127ee603883612119565b91506127f982612792565b604082019050919050565b6000602082019050818103600083015261281d816127e1565b9050919050565b7f45524332304d696e7465724275726e6572446563696d616c733a206d7573742060008201527f686176652070617573657220726f6c6520746f20706175736500000000000000602082015250565b6000612880603983612119565b915061288b82612824565b604082019050919050565b600060208201905081810360008301526128af81612873565b9050919050565b7f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f7760008201527f207a65726f000000000000000000000000000000000000000000000000000000602082015250565b6000612912602583612119565b915061291d826128b6565b604082019050919050565b6000602082019050818103600083015261294181612905565b9050919050565b7f45524332303a20617070726f76652066726f6d20746865207a65726f2061646460008201527f7265737300000000000000000000000000000000000000000000000000000000602082015250565b60006129a4602483612119565b91506129af82612948565b604082019050919050565b600060208201905081810360008301526129d381612997565b9050919050565b7f45524332303a20617070726f766520746f20746865207a65726f20616464726560008201527f7373000000000000000000000000000000000000000000000000000000000000602082015250565b6000612a36602283612119565b9150612a41826129da565b604082019050919050565b60006020820190508181036000830152612a6581612a29565b9050919050565b7f45524332303a206275726e2066726f6d20746865207a65726f2061646472657360008201527f7300000000000000000000000000000000000000000000000000000000000000602082015250565b6000612ac8602183612119565b9150612ad382612a6c565b604082019050919050565b60006020820190508181036000830152612af781612abb565b9050919050565b7f45524332303a206275726e20616d6f756e7420657863656564732062616c616e60008201527f6365000000000000000000000000000000000000000000000000000000000000602082015250565b6000612b5a602283612119565b9150612b6582612afe565b604082019050919050565b60006020820190508181036000830152612b8981612b4d565b9050919050565b7f45524332303a20696e73756666696369656e7420616c6c6f77616e6365000000600082015250565b6000612bc6601d83612119565b9150612bd182612b90565b602082019050919050565b60006020820190508181036000830152612bf581612bb9565b9050919050565b7f45524332303a207472616e736665722066726f6d20746865207a65726f20616460008201527f6472657373000000000000000000000000000000000000000000000000000000602082015250565b6000612c58602583612119565b9150612c6382612bfc565b604082019050919050565b60006020820190508181036000830152612c8781612c4b565b9050919050565b7f45524332303a207472616e7366657220746f20746865207a65726f206164647260008201527f6573730000000000000000000000000000000000000000000000000000000000602082015250565b6000612cea602383612119565b9150612cf582612c8e565b604082019050919050565b60006020820190508181036000830152612d1981612cdd565b9050919050565b7f45524332303a207472616e7366657220616d6f756e742065786365656473206260008201527f616c616e63650000000000000000000000000000000000000000000000000000602082015250565b6000612d7c602683612119565b9150612d8782612d20565b604082019050919050565b60006020820190508181036000830152612dab81612d6f565b9050919050565b7f45524332303a206d696e7420746f20746865207a65726f206164647265737300600082015250565b6000612de8601f83612119565b9150612df382612db2565b602082019050919050565b60006020820190508181036000830152612e1781612ddb565b9050919050565b600081905092915050565b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000600082015250565b6000612e5f601783612e1e565b9150612e6a82612e29565b601782019050919050565b6000612e808261210e565b612e8a8185612e1e565b9350612e9a81856020860161212a565b80840191505092915050565b7f206973206d697373696e6720726f6c6520000000000000000000000000000000600082015250565b6000612edc601183612e1e565b9150612ee782612ea6565b601182019050919050565b6000612efd82612e52565b9150612f098285612e75565b9150612f1482612ecf565b9150612f208284612e75565b91508190509392505050565b7f5061757361626c653a206e6f7420706175736564000000000000000000000000600082015250565b6000612f62601483612119565b9150612f6d82612f2c565b602082019050919050565b60006020820190508181036000830152612f9181612f55565b9050919050565b7f5061757361626c653a2070617573656400000000000000000000000000000000600082015250565b6000612fce601083612119565b9150612fd982612f98565b602082019050919050565b60006020820190508181036000830152612ffd81612fc1565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f45524332305061757361626c653a20746f6b656e207472616e7366657220776860008201527f696c652070617573656400000000000000000000000000000000000000000000602082015250565b600061308f602a83612119565b915061309a82613033565b604082019050919050565b600060208201905081810360008301526130be81613082565b9050919050565b60006130d08261221e565b91506130db8361221e565b92508282026130e98161221e565b91508282048414831517613100576130ff61269d565b5b5092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60006131418261221e565b9150600082036131545761315361269d565b5b600182039050919050565b7f537472696e67733a20686578206c656e67746820696e73756666696369656e74600082015250565b6000613195602083612119565b91506131a08261315f565b602082019050919050565b600060208201905081810360008301526131c481613188565b9050919050565b60006131d68261221e565b91506131e18361221e565b92508282039050818111156131f9576131f861269d565b5b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea264697066735822122085be590fcd27af24982116d9f60fa42a00c725b7ba15ba740f13e78af698fedf64736f6c63430008140033", - "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106101da5760003560e01c80635c975abb11610104578063a217fddf116100a2578063d539139311610071578063d53913931461057d578063d547741f1461059b578063dd62ed3e146105b7578063e63ab1e9146105e7576101da565b8063a217fddf146104cf578063a457c2d7146104ed578063a9059cbb1461051d578063ca15c8731461054d576101da565b80638456cb59116100de5780638456cb59146104475780639010d07c1461045157806391d148541461048157806395d89b41146104b1576101da565b80635c975abb146103dd57806370a08231146103fb57806379cc67901461042b576101da565b8063282c51f31161017c578063395093511161014b578063395093511461036b5780633f4ba83a1461039b57806340c10f19146103a557806342966c68146103c1576101da565b8063282c51f3146102f75780632f2ff15d14610315578063313ce5671461033157806336568abe1461034f576101da565b806318160ddd116101b857806318160ddd1461025d5780631cf2c7e21461027b57806323b872dd14610297578063248a9ca3146102c7576101da565b806301ffc9a7146101df57806306fdde031461020f578063095ea7b31461022d575b600080fd5b6101f960048036038101906101f491906120ab565b610605565b60405161020691906120f3565b60405180910390f35b61021761067f565b604051610224919061219e565b60405180910390f35b61024760048036038101906102429190612254565b610711565b60405161025491906120f3565b60405180910390f35b610265610734565b60405161027291906122a3565b60405180910390f35b61029560048036038101906102909190612254565b61073e565b005b6102b160048036038101906102ac91906122be565b6107bc565b6040516102be91906120f3565b60405180910390f35b6102e160048036038101906102dc9190612347565b6107eb565b6040516102ee9190612383565b60405180910390f35b6102ff61080a565b60405161030c9190612383565b60405180910390f35b61032f600480360381019061032a919061239e565b61082e565b005b61033961084f565b60405161034691906123fa565b60405180910390f35b6103696004803603810190610364919061239e565b610866565b005b61038560048036038101906103809190612254565b6108e9565b60405161039291906120f3565b60405180910390f35b6103a3610920565b005b6103bf60048036038101906103ba9190612254565b61099a565b005b6103db60048036038101906103d69190612415565b610a18565b005b6103e5610a2c565b6040516103f291906120f3565b60405180910390f35b61041560048036038101906104109190612442565b610a43565b60405161042291906122a3565b60405180910390f35b61044560048036038101906104409190612254565b610a8c565b005b61044f610aac565b005b61046b6004803603810190610466919061246f565b610b26565b60405161047891906124be565b60405180910390f35b61049b6004803603810190610496919061239e565b610b55565b6040516104a891906120f3565b60405180910390f35b6104b9610bbf565b6040516104c6919061219e565b60405180910390f35b6104d7610c51565b6040516104e49190612383565b60405180910390f35b61050760048036038101906105029190612254565b610c58565b60405161051491906120f3565b60405180910390f35b61053760048036038101906105329190612254565b610ccf565b60405161054491906120f3565b60405180910390f35b61056760048036038101906105629190612347565b610cf2565b60405161057491906122a3565b60405180910390f35b610585610d16565b6040516105929190612383565b60405180910390f35b6105b560048036038101906105b0919061239e565b610d3a565b005b6105d160048036038101906105cc91906124d9565b610d5b565b6040516105de91906122a3565b60405180910390f35b6105ef610de2565b6040516105fc9190612383565b60405180910390f35b60007f5a05180f000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161480610678575061067782610e06565b5b9050919050565b60606005805461068e90612548565b80601f01602080910402602001604051908101604052809291908181526020018280546106ba90612548565b80156107075780601f106106dc57610100808354040283529160200191610707565b820191906000526020600020905b8154815290600101906020018083116106ea57829003601f168201915b5050505050905090565b60008061071c610e80565b9050610729818585610e88565b600191505092915050565b6000600454905090565b61076f7f3c11d16cbaffd01df69ce1c404f6340ee057498f5f00246190ea54220576a84861076a610e80565b610b55565b6107ae576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107a5906125eb565b60405180910390fd5b6107b88282611051565b5050565b6000806107c7610e80565b90506107d4858285611220565b6107df8585856112ac565b60019150509392505050565b6000806000838152602001908152602001600020600101549050919050565b7f3c11d16cbaffd01df69ce1c404f6340ee057498f5f00246190ea54220576a84881565b610837826107eb565b61084081611525565b61084a8383611539565b505050565b6000600760019054906101000a900460ff16905090565b61086e610e80565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16146108db576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108d29061267d565b60405180910390fd5b6108e5828261156d565b5050565b6000806108f4610e80565b90506109158185856109068589610d5b565b61091091906126cc565b610e88565b600191505092915050565b6109517f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a61094c610e80565b610b55565b610990576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161098790612772565b60405180910390fd5b6109986115a1565b565b6109cb7f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a66109c6610e80565b610b55565b610a0a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a0190612804565b60405180910390fd5b610a148282611604565b5050565b610a29610a23610e80565b82611051565b50565b6000600760009054906101000a900460ff16905090565b6000600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b610a9e82610a98610e80565b83611220565b610aa88282611051565b5050565b610add7f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a610ad8610e80565b610b55565b610b1c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b1390612896565b60405180910390fd5b610b2461175b565b565b6000610b4d82600160008681526020019081526020016000206117be90919063ffffffff16565b905092915050565b600080600084815260200190815260200160002060000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16905092915050565b606060068054610bce90612548565b80601f0160208091040260200160405190810160405280929190818152602001828054610bfa90612548565b8015610c475780601f10610c1c57610100808354040283529160200191610c47565b820191906000526020600020905b815481529060010190602001808311610c2a57829003601f168201915b5050505050905090565b6000801b81565b600080610c63610e80565b90506000610c718286610d5b565b905083811015610cb6576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610cad90612928565b60405180910390fd5b610cc38286868403610e88565b60019250505092915050565b600080610cda610e80565b9050610ce78185856112ac565b600191505092915050565b6000610d0f600160008481526020019081526020016000206117d8565b9050919050565b7f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a681565b610d43826107eb565b610d4c81611525565b610d56838361156d565b505050565b6000600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905092915050565b7f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a81565b60007f7965db0b000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161480610e795750610e78826117ed565b5b9050919050565b600033905090565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603610ef7576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610eee906129ba565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610f66576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f5d90612a4c565b60405180910390fd5b80600360008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258360405161104491906122a3565b60405180910390a3505050565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036110c0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016110b790612ade565b60405180910390fd5b6110cc82600083611857565b6000600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905081811015611153576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161114a90612b70565b60405180910390fd5b818103600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555081600460008282540392505081905550600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8460405161120791906122a3565b60405180910390a361121b83600084611867565b505050565b600061122c8484610d5b565b90507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146112a65781811015611298576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161128f90612bdc565b60405180910390fd5b6112a58484848403610e88565b5b50505050565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff160361131b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161131290612c6e565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff160361138a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161138190612d00565b60405180910390fd5b611395838383611857565b6000600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490508181101561141c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161141390612d92565b60405180910390fd5b818103600260008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555081600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8460405161150c91906122a3565b60405180910390a361151f848484611867565b50505050565b61153681611531610e80565b61186c565b50565b61154382826118f1565b61156881600160008581526020019081526020016000206119d190919063ffffffff16565b505050565b6115778282611a01565b61159c8160016000858152602001908152602001600020611ae290919063ffffffff16565b505050565b6115a9611b12565b6000600760006101000a81548160ff0219169083151502179055507f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa6115ed610e80565b6040516115fa91906124be565b60405180910390a1565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603611673576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161166a90612dfe565b60405180910390fd5b61167f60008383611857565b806004600082825461169191906126cc565b9250508190555080600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508173ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8360405161174391906122a3565b60405180910390a361175760008383611867565b5050565b611763611b5b565b6001600760006101000a81548160ff0219169083151502179055507f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586117a7610e80565b6040516117b491906124be565b60405180910390a1565b60006117cd8360000183611ba5565b60001c905092915050565b60006117e682600001611bd0565b9050919050565b60007f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b611862838383611be1565b505050565b505050565b6118768282610b55565b6118ed5761188381611c39565b6118918360001c6020611c66565b6040516020016118a2929190612ef2565b6040516020818303038152906040526040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016118e4919061219e565b60405180910390fd5b5050565b6118fb8282610b55565b6119cd57600160008084815260200190815260200160002060000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908315150217905550611972610e80565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45b5050565b60006119f9836000018373ffffffffffffffffffffffffffffffffffffffff1660001b611ea2565b905092915050565b611a0b8282610b55565b15611ade57600080600084815260200190815260200160002060000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908315150217905550611a83610e80565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16837ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b60405160405180910390a45b5050565b6000611b0a836000018373ffffffffffffffffffffffffffffffffffffffff1660001b611f12565b905092915050565b611b1a610a2c565b611b59576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611b5090612f78565b60405180910390fd5b565b611b63610a2c565b15611ba3576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611b9a90612fe4565b60405180910390fd5b565b6000826000018281548110611bbd57611bbc613004565b5b9060005260206000200154905092915050565b600081600001805490509050919050565b611bec838383612026565b611bf4610a2c565b15611c34576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611c2b906130a5565b60405180910390fd5b505050565b6060611c5f8273ffffffffffffffffffffffffffffffffffffffff16601460ff16611c66565b9050919050565b606060006002836002611c7991906130c5565b611c8391906126cc565b67ffffffffffffffff811115611c9c57611c9b613107565b5b6040519080825280601f01601f191660200182016040528015611cce5781602001600182028036833780820191505090505b5090507f300000000000000000000000000000000000000000000000000000000000000081600081518110611d0657611d05613004565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053507f780000000000000000000000000000000000000000000000000000000000000081600181518110611d6a57611d69613004565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060006001846002611daa91906130c5565b611db491906126cc565b90505b6001811115611e54577f3031323334353637383961626364656600000000000000000000000000000000600f861660108110611df657611df5613004565b5b1a60f81b828281518110611e0d57611e0c613004565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350600485901c945080611e4d90613136565b9050611db7565b5060008414611e98576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611e8f906131ab565b60405180910390fd5b8091505092915050565b6000611eae838361202b565b611f07578260000182908060018154018082558091505060019003906000526020600020016000909190919091505582600001805490508360010160008481526020019081526020016000208190555060019050611f0c565b600090505b92915050565b6000808360010160008481526020019081526020016000205490506000811461201a576000600182611f4491906131cb565b9050600060018660000180549050611f5c91906131cb565b9050818114611fcb576000866000018281548110611f7d57611f7c613004565b5b9060005260206000200154905080876000018481548110611fa157611fa0613004565b5b90600052602060002001819055508387600101600083815260200190815260200160002081905550505b85600001805480611fdf57611fde6131ff565b5b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050612020565b60009150505b92915050565b505050565b600080836001016000848152602001908152602001600020541415905092915050565b600080fd5b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b61208881612053565b811461209357600080fd5b50565b6000813590506120a58161207f565b92915050565b6000602082840312156120c1576120c061204e565b5b60006120cf84828501612096565b91505092915050565b60008115159050919050565b6120ed816120d8565b82525050565b600060208201905061210860008301846120e4565b92915050565b600081519050919050565b600082825260208201905092915050565b60005b8381101561214857808201518184015260208101905061212d565b60008484015250505050565b6000601f19601f8301169050919050565b60006121708261210e565b61217a8185612119565b935061218a81856020860161212a565b61219381612154565b840191505092915050565b600060208201905081810360008301526121b88184612165565b905092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006121eb826121c0565b9050919050565b6121fb816121e0565b811461220657600080fd5b50565b600081359050612218816121f2565b92915050565b6000819050919050565b6122318161221e565b811461223c57600080fd5b50565b60008135905061224e81612228565b92915050565b6000806040838503121561226b5761226a61204e565b5b600061227985828601612209565b925050602061228a8582860161223f565b9150509250929050565b61229d8161221e565b82525050565b60006020820190506122b86000830184612294565b92915050565b6000806000606084860312156122d7576122d661204e565b5b60006122e586828701612209565b93505060206122f686828701612209565b92505060406123078682870161223f565b9150509250925092565b6000819050919050565b61232481612311565b811461232f57600080fd5b50565b6000813590506123418161231b565b92915050565b60006020828403121561235d5761235c61204e565b5b600061236b84828501612332565b91505092915050565b61237d81612311565b82525050565b60006020820190506123986000830184612374565b92915050565b600080604083850312156123b5576123b461204e565b5b60006123c385828601612332565b92505060206123d485828601612209565b9150509250929050565b600060ff82169050919050565b6123f4816123de565b82525050565b600060208201905061240f60008301846123eb565b92915050565b60006020828403121561242b5761242a61204e565b5b60006124398482850161223f565b91505092915050565b6000602082840312156124585761245761204e565b5b600061246684828501612209565b91505092915050565b600080604083850312156124865761248561204e565b5b600061249485828601612332565b92505060206124a58582860161223f565b9150509250929050565b6124b8816121e0565b82525050565b60006020820190506124d360008301846124af565b92915050565b600080604083850312156124f0576124ef61204e565b5b60006124fe85828601612209565b925050602061250f85828601612209565b9150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b6000600282049050600182168061256057607f821691505b60208210810361257357612572612519565b5b50919050565b7f45524332304d696e7465724275726e6572446563696d616c733a206d7573742060008201527f68617665206275726e657220726f6c6520746f206275726e0000000000000000602082015250565b60006125d5603883612119565b91506125e082612579565b604082019050919050565b60006020820190508181036000830152612604816125c8565b9050919050565b7f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560008201527f20726f6c657320666f722073656c660000000000000000000000000000000000602082015250565b6000612667602f83612119565b91506126728261260b565b604082019050919050565b600060208201905081810360008301526126968161265a565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006126d78261221e565b91506126e28361221e565b92508282019050808211156126fa576126f961269d565b5b92915050565b7f45524332304d696e7465724275726e6572446563696d616c733a206d7573742060008201527f686176652070617573657220726f6c6520746f20756e70617573650000000000602082015250565b600061275c603b83612119565b915061276782612700565b604082019050919050565b6000602082019050818103600083015261278b8161274f565b9050919050565b7f45524332304d696e7465724275726e6572446563696d616c733a206d7573742060008201527f68617665206d696e74657220726f6c6520746f206d696e740000000000000000602082015250565b60006127ee603883612119565b91506127f982612792565b604082019050919050565b6000602082019050818103600083015261281d816127e1565b9050919050565b7f45524332304d696e7465724275726e6572446563696d616c733a206d7573742060008201527f686176652070617573657220726f6c6520746f20706175736500000000000000602082015250565b6000612880603983612119565b915061288b82612824565b604082019050919050565b600060208201905081810360008301526128af81612873565b9050919050565b7f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f7760008201527f207a65726f000000000000000000000000000000000000000000000000000000602082015250565b6000612912602583612119565b915061291d826128b6565b604082019050919050565b6000602082019050818103600083015261294181612905565b9050919050565b7f45524332303a20617070726f76652066726f6d20746865207a65726f2061646460008201527f7265737300000000000000000000000000000000000000000000000000000000602082015250565b60006129a4602483612119565b91506129af82612948565b604082019050919050565b600060208201905081810360008301526129d381612997565b9050919050565b7f45524332303a20617070726f766520746f20746865207a65726f20616464726560008201527f7373000000000000000000000000000000000000000000000000000000000000602082015250565b6000612a36602283612119565b9150612a41826129da565b604082019050919050565b60006020820190508181036000830152612a6581612a29565b9050919050565b7f45524332303a206275726e2066726f6d20746865207a65726f2061646472657360008201527f7300000000000000000000000000000000000000000000000000000000000000602082015250565b6000612ac8602183612119565b9150612ad382612a6c565b604082019050919050565b60006020820190508181036000830152612af781612abb565b9050919050565b7f45524332303a206275726e20616d6f756e7420657863656564732062616c616e60008201527f6365000000000000000000000000000000000000000000000000000000000000602082015250565b6000612b5a602283612119565b9150612b6582612afe565b604082019050919050565b60006020820190508181036000830152612b8981612b4d565b9050919050565b7f45524332303a20696e73756666696369656e7420616c6c6f77616e6365000000600082015250565b6000612bc6601d83612119565b9150612bd182612b90565b602082019050919050565b60006020820190508181036000830152612bf581612bb9565b9050919050565b7f45524332303a207472616e736665722066726f6d20746865207a65726f20616460008201527f6472657373000000000000000000000000000000000000000000000000000000602082015250565b6000612c58602583612119565b9150612c6382612bfc565b604082019050919050565b60006020820190508181036000830152612c8781612c4b565b9050919050565b7f45524332303a207472616e7366657220746f20746865207a65726f206164647260008201527f6573730000000000000000000000000000000000000000000000000000000000602082015250565b6000612cea602383612119565b9150612cf582612c8e565b604082019050919050565b60006020820190508181036000830152612d1981612cdd565b9050919050565b7f45524332303a207472616e7366657220616d6f756e742065786365656473206260008201527f616c616e63650000000000000000000000000000000000000000000000000000602082015250565b6000612d7c602683612119565b9150612d8782612d20565b604082019050919050565b60006020820190508181036000830152612dab81612d6f565b9050919050565b7f45524332303a206d696e7420746f20746865207a65726f206164647265737300600082015250565b6000612de8601f83612119565b9150612df382612db2565b602082019050919050565b60006020820190508181036000830152612e1781612ddb565b9050919050565b600081905092915050565b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000600082015250565b6000612e5f601783612e1e565b9150612e6a82612e29565b601782019050919050565b6000612e808261210e565b612e8a8185612e1e565b9350612e9a81856020860161212a565b80840191505092915050565b7f206973206d697373696e6720726f6c6520000000000000000000000000000000600082015250565b6000612edc601183612e1e565b9150612ee782612ea6565b601182019050919050565b6000612efd82612e52565b9150612f098285612e75565b9150612f1482612ecf565b9150612f208284612e75565b91508190509392505050565b7f5061757361626c653a206e6f7420706175736564000000000000000000000000600082015250565b6000612f62601483612119565b9150612f6d82612f2c565b602082019050919050565b60006020820190508181036000830152612f9181612f55565b9050919050565b7f5061757361626c653a2070617573656400000000000000000000000000000000600082015250565b6000612fce601083612119565b9150612fd982612f98565b602082019050919050565b60006020820190508181036000830152612ffd81612fc1565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f45524332305061757361626c653a20746f6b656e207472616e7366657220776860008201527f696c652070617573656400000000000000000000000000000000000000000000602082015250565b600061308f602a83612119565b915061309a82613033565b604082019050919050565b600060208201905081810360008301526130be81613082565b9050919050565b60006130d08261221e565b91506130db8361221e565b92508282026130e98161221e565b91508282048414831517613100576130ff61269d565b5b5092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60006131418261221e565b9150600082036131545761315361269d565b5b600182039050919050565b7f537472696e67733a20686578206c656e67746820696e73756666696369656e74600082015250565b6000613195602083612119565b91506131a08261315f565b602082019050919050565b600060208201905081810360008301526131c481613188565b9050919050565b60006131d68261221e565b91506131e18361221e565b92508282039050818111156131f9576131f861269d565b5b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea264697066735822122085be590fcd27af24982116d9f60fa42a00c725b7ba15ba740f13e78af698fedf64736f6c63430008140033", + "bytecode": "0x60806040523480156200001157600080fd5b50604051620022573803806200225783398101604081905262000034916200045a565b8651879087906200004d906005906020850190620002ec565b50805162000063906006906020840190620002ec565b50506007805461ffff191661010060ff89160217905550620000876000856200015b565b6001600160a01b03831615620000b257620000b260008051602062002237833981519152846200015b565b6001600160a01b03821615620000ee57620000ee7f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a836200015b565b6001600160a01b038116156200012a576200012a7f3c11d16cbaffd01df69ce1c404f6340ee057498f5f00246190ea54220576a848826200015b565b6200014e60008051602062002237833981519152620001486200019e565b6200015b565b5050505050505062000577565b620001728282620001a260201b620009991760201c565b600082815260016020908152604090912062000199918390620009a3620001b2821b17901c565b505050565b3390565b620001ae8282620001d2565b5050565b6000620001c9836001600160a01b0384166200025c565b90505b92915050565b620001de8282620002ab565b620001ae576000828152602081815260408083206001600160a01b03851684529091529020805460ff19166001179055620002186200019e565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b60006200026a8383620002d4565b620002a257508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155620001cc565b506000620001cc565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b60009081526001919091016020526040902054151590565b828054620002fa9062000524565b90600052602060002090601f0160209004810192826200031e576000855562000369565b82601f106200033957805160ff191683800117855562000369565b8280016001018555821562000369579182015b82811115620003695782518255916020019190600101906200034c565b50620003779291506200037b565b5090565b5b808211156200037757600081556001016200037c565b80516001600160a01b0381168114620003aa57600080fd5b919050565b600082601f830112620003c0578081fd5b81516001600160401b0380821115620003dd57620003dd62000561565b6040516020601f8401601f191682018101838111838210171562000405576200040562000561565b60405283825285840181018710156200041c578485fd5b8492505b838310156200043f578583018101518284018201529182019162000420565b838311156200045057848185840101525b5095945050505050565b600080600080600080600060e0888a03121562000475578283fd5b87516001600160401b03808211156200048c578485fd5b6200049a8b838c01620003af565b985060208a0151915080821115620004b0578485fd5b50620004bf8a828b01620003af565b965050604088015160ff81168114620004d6578384fd5b9450620004e66060890162000392565b9350620004f66080890162000392565b92506200050660a0890162000392565b91506200051660c0890162000392565b905092959891949750929550565b6002810460018216806200053957607f821691505b602082108114156200055b57634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052604160045260246000fd5b611cb080620005876000396000f3fe608060405234801561001057600080fd5b50600436106101da5760003560e01c80635c975abb11610104578063a217fddf116100a2578063d539139311610071578063d5391393146103b6578063d547741f146103be578063dd62ed3e146103d1578063e63ab1e9146103e4576101da565b8063a217fddf14610375578063a457c2d71461037d578063a9059cbb14610390578063ca15c873146103a3576101da565b80638456cb59116100de5780638456cb59146103325780639010d07c1461033a57806391d148541461035a57806395d89b411461036d576101da565b80635c975abb1461030457806370a082311461030c57806379cc67901461031f576101da565b8063282c51f31161017c578063395093511161014b57806339509351146102c35780633f4ba83a146102d657806340c10f19146102de57806342966c68146102f1576101da565b8063282c51f3146102805780632f2ff15d14610288578063313ce5671461029b57806336568abe146102b0576101da565b806318160ddd116101b857806318160ddd146102305780631cf2c7e21461024557806323b872dd1461025a578063248a9ca31461026d576101da565b806301ffc9a7146101df57806306fdde0314610208578063095ea7b31461021d575b600080fd5b6101f26101ed366004611541565b6103ec565b6040516101ff91906115f2565b60405180910390f35b610210610419565b6040516101ff9190611606565b6101f261022b3660046114bd565b6104ab565b6102386104c9565b6040516101ff91906115fd565b6102586102533660046114bd565b6104cf565b005b6101f2610268366004611482565b61052e565b61023861027b3660046114e6565b6105be565b6102386105d3565b6102586102963660046114fe565b6105f7565b6102a361061e565b6040516101ff9190611b6a565b6102586102be3660046114fe565b61062c565b6101f26102d13660046114bd565b61064e565b6102586106a2565b6102586102ec3660046114bd565b6106f4565b6102586102ff3660046114e6565b610746565b6101f261075a565b61023861031a366004611436565b610763565b61025861032d3660046114bd565b61077e565b6102586107cc565b61034d610348366004611520565b61081c565b6040516101ff91906115de565b6101f26103683660046114fe565b61083b565b610210610864565b610238610873565b6101f261038b3660046114bd565b610878565b6101f261039e3660046114bd565b6108f1565b6102386103b13660046114e6565b610905565b61023861091c565b6102586103cc3660046114fe565b610940565b6102386103df366004611450565b61094a565b610238610975565b60006001600160e01b03198216635a05180f60e01b14806104115750610411826109b8565b90505b919050565b60606005805461042890611c09565b80601f016020809104026020016040519081016040528092919081815260200182805461045490611c09565b80156104a15780601f10610476576101008083540402835291602001916104a1565b820191906000526020600020905b81548152906001019060200180831161048457829003601f168201915b5050505050905090565b60006104bf6104b86109dd565b84846109e1565b5060015b92915050565b60045490565b6104fb7f3c11d16cbaffd01df69ce1c404f6340ee057498f5f00246190ea54220576a8486103686109dd565b6105205760405162461bcd60e51b815260040161051790611721565b60405180910390fd5b61052a8282610a95565b5050565b600061053b848484610b86565b6001600160a01b03841660009081526003602052604081208161055c6109dd565b6001600160a01b03166001600160a01b031681526020019081526020016000205490508281101561059f5760405162461bcd60e51b8152600401610517906118b4565b6105b3856105ab6109dd565b8584036109e1565b506001949350505050565b60009081526020819052604090206001015490565b7f3c11d16cbaffd01df69ce1c404f6340ee057498f5f00246190ea54220576a84881565b6106018282610cb0565b600082815260016020526040902061061990826109a3565b505050565b600754610100900460ff1690565b6106368282610cd4565b60008281526001602052604090206106199082610d16565b60006104bf61065b6109dd565b8484600360006106696109dd565b6001600160a01b03908116825260208083019390935260409182016000908120918b168152925290205461069d9190611b78565b6109e1565b6106ce7f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a6103686109dd565b6106ea5760405162461bcd60e51b815260040161051790611869565b6106f2610d2b565b565b6107207f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a66103686109dd565b61073c5760405162461bcd60e51b8152600401610517906117f4565b61052a8282610d99565b6107576107516109dd565b82610a95565b50565b60075460ff1690565b6001600160a01b031660009081526002602052604090205490565b600061078c836103df6109dd565b9050818110156107ae5760405162461bcd60e51b8152600401610517906118fc565b6107c2836107ba6109dd565b8484036109e1565b6106198383610a95565b6107f87f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a6103686109dd565b6108145760405162461bcd60e51b815260040161051790611940565b6106f2610e61565b60008281526001602052604081206108349083610ebc565b9392505050565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b60606006805461042890611c09565b600081565b600080600360006108876109dd565b6001600160a01b03908116825260208083019390935260409182016000908120918816815292529020549050828110156108d35760405162461bcd60e51b815260040161051790611a55565b6108e76108de6109dd565b858584036109e1565b5060019392505050565b60006104bf6108fe6109dd565b8484610b86565b600081815260016020526040812061041190610ec8565b7f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a681565b6106368282610ed3565b6001600160a01b03918216600090815260036020908152604080832093909416825291909152205490565b7f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a81565b61052a8282610ef2565b6000610834836001600160a01b038416610f77565b60006001600160e01b03198216637965db0b60e01b1480610411575061041182610fc1565b3390565b6001600160a01b038316610a075760405162461bcd60e51b815260040161051790611a11565b6001600160a01b038216610a2d5760405162461bcd60e51b81526004016105179061176c565b6001600160a01b0380841660008181526003602090815260408083209487168084529490915290819020849055517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92590610a889085906115fd565b60405180910390a3505050565b6001600160a01b038216610abb5760405162461bcd60e51b81526004016105179061198b565b610ac782600083610fda565b6001600160a01b03821660009081526002602052604090205481811015610b005760405162461bcd60e51b8152600401610517906116df565b6001600160a01b0383166000908152600260205260408120838303905560048054849290610b2f908490611baf565b90915550506040516000906001600160a01b038516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90610b729086906115fd565b60405180910390a361061983600084610619565b6001600160a01b038316610bac5760405162461bcd60e51b8152600401610517906119cc565b6001600160a01b038216610bd25760405162461bcd60e51b81526004016105179061166e565b610bdd838383610fda565b6001600160a01b03831660009081526002602052604090205481811015610c165760405162461bcd60e51b8152600401610517906117ae565b6001600160a01b03808516600090815260026020526040808220858503905591851681529081208054849290610c4d908490611b78565b92505081905550826001600160a01b0316846001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84604051610c9791906115fd565b60405180910390a3610caa848484610619565b50505050565b610cb9826105be565b610cca81610cc56109dd565b610fe5565b6106198383610ef2565b610cdc6109dd565b6001600160a01b0316816001600160a01b031614610d0c5760405162461bcd60e51b815260040161051790611a9a565b61052a8282611049565b6000610834836001600160a01b0384166110cc565b610d3361075a565b610d4f5760405162461bcd60e51b8152600401610517906116b1565b6007805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa610d826109dd565b604051610d8f91906115de565b60405180910390a1565b6001600160a01b038216610dbf5760405162461bcd60e51b815260040161051790611ae9565b610dcb60008383610fda565b8060046000828254610ddd9190611b78565b90915550506001600160a01b03821660009081526002602052604081208054839290610e0a908490611b78565b90915550506040516001600160a01b038316906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90610e4d9085906115fd565b60405180910390a361052a60008383610619565b610e6961075a565b15610e865760405162461bcd60e51b81526004016105179061183f565b6007805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258610d826109dd565b600061083483836111e9565b600061041182611221565b610edc826105be565b610ee881610cc56109dd565b6106198383611049565b610efc828261083b565b61052a576000828152602081815260408083206001600160a01b03851684529091529020805460ff19166001179055610f336109dd565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b6000610f838383611225565b610fb9575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556104c3565b5060006104c3565b6001600160e01b031981166301ffc9a760e01b14919050565b61061983838361123d565b610fef828261083b565b61052a57611007816001600160a01b0316601461126d565b61101283602061126d565b604051602001611023929190611569565b60408051601f198184030181529082905262461bcd60e51b825261051791600401611606565b611053828261083b565b1561052a576000828152602081815260408083206001600160a01b03851684529091529020805460ff191690556110886109dd565b6001600160a01b0316816001600160a01b0316837ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b60405160405180910390a45050565b600081815260018301602052604081205480156111df5760006110f0600183611baf565b855490915060009061110490600190611baf565b905081811461118557600086600001828154811061113257634e487b7160e01b600052603260045260246000fd5b906000526020600020015490508087600001848154811061116357634e487b7160e01b600052603260045260246000fd5b6000918252602080832090910192909255918252600188019052604090208390555b85548690806111a457634e487b7160e01b600052603160045260246000fd5b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506104c3565b60009150506104c3565b600082600001828154811061120e57634e487b7160e01b600052603260045260246000fd5b9060005260206000200154905092915050565b5490565b60009081526001919091016020526040902054151590565b611248838383610619565b61125061075a565b156106195760405162461bcd60e51b815260040161051790611b20565b6060600061127c836002611b90565b611287906002611b78565b67ffffffffffffffff8111156112ad57634e487b7160e01b600052604160045260246000fd5b6040519080825280601f01601f1916602001820160405280156112d7576020820181803683370190505b509050600360fc1b8160008151811061130057634e487b7160e01b600052603260045260246000fd5b60200101906001600160f81b031916908160001a905350600f60fb1b8160018151811061133d57634e487b7160e01b600052603260045260246000fd5b60200101906001600160f81b031916908160001a9053506000611361846002611b90565b61136c906001611b78565b90505b6001811115611400576f181899199a1a9b1b9c1cb0b131b232b360811b85600f16601081106113ae57634e487b7160e01b600052603260045260246000fd5b1a60f81b8282815181106113d257634e487b7160e01b600052603260045260246000fd5b60200101906001600160f81b031916908160001a90535060049490941c936113f981611bf2565b905061136f565b5083156108345760405162461bcd60e51b815260040161051790611639565b80356001600160a01b038116811461041457600080fd5b600060208284031215611447578081fd5b6108348261141f565b60008060408385031215611462578081fd5b61146b8361141f565b91506114796020840161141f565b90509250929050565b600080600060608486031215611496578081fd5b61149f8461141f565b92506114ad6020850161141f565b9150604084013590509250925092565b600080604083850312156114cf578182fd5b6114d88361141f565b946020939093013593505050565b6000602082840312156114f7578081fd5b5035919050565b60008060408385031215611510578182fd5b823591506114796020840161141f565b60008060408385031215611532578182fd5b50508035926020909101359150565b600060208284031215611552578081fd5b81356001600160e01b031981168114610834578182fd5b60007f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000825283516115a1816017850160208801611bc6565b7001034b99036b4b9b9b4b733903937b6329607d1b60179184019182015283516115d2816028840160208801611bc6565b01602801949350505050565b6001600160a01b0391909116815260200190565b901515815260200190565b90815260200190565b6000602082528251806020840152611625816040850160208701611bc6565b601f01601f19169190910160400192915050565b6020808252818101527f537472696e67733a20686578206c656e67746820696e73756666696369656e74604082015260600190565b60208082526023908201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260408201526265737360e81b606082015260800190565b60208082526014908201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b604082015260600190565b60208082526022908201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604082015261636560f01b606082015260800190565b6020808252603890820152600080516020611c5b83398151915260408201527f68617665206275726e657220726f6c6520746f206275726e0000000000000000606082015260800190565b60208082526022908201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604082015261737360f01b606082015260800190565b60208082526026908201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604082015265616c616e636560d01b606082015260800190565b6020808252603890820152600080516020611c5b83398151915260408201527f68617665206d696e74657220726f6c6520746f206d696e740000000000000000606082015260800190565b60208082526010908201526f14185d5cd8589b194e881c185d5cd95960821b604082015260600190565b6020808252603b90820152600080516020611c5b83398151915260408201527f686176652070617573657220726f6c6520746f20756e70617573650000000000606082015260800190565b60208082526028908201527f45524332303a207472616e7366657220616d6f756e74206578636565647320616040820152676c6c6f77616e636560c01b606082015260800190565b60208082526024908201527f45524332303a206275726e20616d6f756e74206578636565647320616c6c6f77604082015263616e636560e01b606082015260800190565b6020808252603990820152600080516020611c5b83398151915260408201527f686176652070617573657220726f6c6520746f20706175736500000000000000606082015260800190565b60208082526021908201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736040820152607360f81b606082015260800190565b60208082526025908201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604082015264647265737360d81b606082015260800190565b60208082526024908201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646040820152637265737360e01b606082015260800190565b60208082526025908201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604082015264207a65726f60d81b606082015260800190565b6020808252602f908201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560408201526e103937b632b9903337b91039b2b63360891b606082015260800190565b6020808252601f908201527f45524332303a206d696e7420746f20746865207a65726f206164647265737300604082015260600190565b6020808252602a908201527f45524332305061757361626c653a20746f6b656e207472616e736665722077686040820152691a5b19481c185d5cd95960b21b606082015260800190565b60ff91909116815260200190565b60008219821115611b8b57611b8b611c44565b500190565b6000816000190483118215151615611baa57611baa611c44565b500290565b600082821015611bc157611bc1611c44565b500390565b60005b83811015611be1578181015183820152602001611bc9565b83811115610caa5750506000910152565b600081611c0157611c01611c44565b506000190190565b600281046001821680611c1d57607f821691505b60208210811415611c3e57634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fdfe45524332304d696e7465724275726e6572446563696d616c733a206d75737420a2646970667358221220ff4366eff48ddf4bde81cb4aa5056b9a1f7f1f41f5e4070a3236f834f068f76664736f6c634300080000339f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a6", + "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106101da5760003560e01c80635c975abb11610104578063a217fddf116100a2578063d539139311610071578063d5391393146103b6578063d547741f146103be578063dd62ed3e146103d1578063e63ab1e9146103e4576101da565b8063a217fddf14610375578063a457c2d71461037d578063a9059cbb14610390578063ca15c873146103a3576101da565b80638456cb59116100de5780638456cb59146103325780639010d07c1461033a57806391d148541461035a57806395d89b411461036d576101da565b80635c975abb1461030457806370a082311461030c57806379cc67901461031f576101da565b8063282c51f31161017c578063395093511161014b57806339509351146102c35780633f4ba83a146102d657806340c10f19146102de57806342966c68146102f1576101da565b8063282c51f3146102805780632f2ff15d14610288578063313ce5671461029b57806336568abe146102b0576101da565b806318160ddd116101b857806318160ddd146102305780631cf2c7e21461024557806323b872dd1461025a578063248a9ca31461026d576101da565b806301ffc9a7146101df57806306fdde0314610208578063095ea7b31461021d575b600080fd5b6101f26101ed366004611541565b6103ec565b6040516101ff91906115f2565b60405180910390f35b610210610419565b6040516101ff9190611606565b6101f261022b3660046114bd565b6104ab565b6102386104c9565b6040516101ff91906115fd565b6102586102533660046114bd565b6104cf565b005b6101f2610268366004611482565b61052e565b61023861027b3660046114e6565b6105be565b6102386105d3565b6102586102963660046114fe565b6105f7565b6102a361061e565b6040516101ff9190611b6a565b6102586102be3660046114fe565b61062c565b6101f26102d13660046114bd565b61064e565b6102586106a2565b6102586102ec3660046114bd565b6106f4565b6102586102ff3660046114e6565b610746565b6101f261075a565b61023861031a366004611436565b610763565b61025861032d3660046114bd565b61077e565b6102586107cc565b61034d610348366004611520565b61081c565b6040516101ff91906115de565b6101f26103683660046114fe565b61083b565b610210610864565b610238610873565b6101f261038b3660046114bd565b610878565b6101f261039e3660046114bd565b6108f1565b6102386103b13660046114e6565b610905565b61023861091c565b6102586103cc3660046114fe565b610940565b6102386103df366004611450565b61094a565b610238610975565b60006001600160e01b03198216635a05180f60e01b14806104115750610411826109b8565b90505b919050565b60606005805461042890611c09565b80601f016020809104026020016040519081016040528092919081815260200182805461045490611c09565b80156104a15780601f10610476576101008083540402835291602001916104a1565b820191906000526020600020905b81548152906001019060200180831161048457829003601f168201915b5050505050905090565b60006104bf6104b86109dd565b84846109e1565b5060015b92915050565b60045490565b6104fb7f3c11d16cbaffd01df69ce1c404f6340ee057498f5f00246190ea54220576a8486103686109dd565b6105205760405162461bcd60e51b815260040161051790611721565b60405180910390fd5b61052a8282610a95565b5050565b600061053b848484610b86565b6001600160a01b03841660009081526003602052604081208161055c6109dd565b6001600160a01b03166001600160a01b031681526020019081526020016000205490508281101561059f5760405162461bcd60e51b8152600401610517906118b4565b6105b3856105ab6109dd565b8584036109e1565b506001949350505050565b60009081526020819052604090206001015490565b7f3c11d16cbaffd01df69ce1c404f6340ee057498f5f00246190ea54220576a84881565b6106018282610cb0565b600082815260016020526040902061061990826109a3565b505050565b600754610100900460ff1690565b6106368282610cd4565b60008281526001602052604090206106199082610d16565b60006104bf61065b6109dd565b8484600360006106696109dd565b6001600160a01b03908116825260208083019390935260409182016000908120918b168152925290205461069d9190611b78565b6109e1565b6106ce7f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a6103686109dd565b6106ea5760405162461bcd60e51b815260040161051790611869565b6106f2610d2b565b565b6107207f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a66103686109dd565b61073c5760405162461bcd60e51b8152600401610517906117f4565b61052a8282610d99565b6107576107516109dd565b82610a95565b50565b60075460ff1690565b6001600160a01b031660009081526002602052604090205490565b600061078c836103df6109dd565b9050818110156107ae5760405162461bcd60e51b8152600401610517906118fc565b6107c2836107ba6109dd565b8484036109e1565b6106198383610a95565b6107f87f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a6103686109dd565b6108145760405162461bcd60e51b815260040161051790611940565b6106f2610e61565b60008281526001602052604081206108349083610ebc565b9392505050565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b60606006805461042890611c09565b600081565b600080600360006108876109dd565b6001600160a01b03908116825260208083019390935260409182016000908120918816815292529020549050828110156108d35760405162461bcd60e51b815260040161051790611a55565b6108e76108de6109dd565b858584036109e1565b5060019392505050565b60006104bf6108fe6109dd565b8484610b86565b600081815260016020526040812061041190610ec8565b7f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a681565b6106368282610ed3565b6001600160a01b03918216600090815260036020908152604080832093909416825291909152205490565b7f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a81565b61052a8282610ef2565b6000610834836001600160a01b038416610f77565b60006001600160e01b03198216637965db0b60e01b1480610411575061041182610fc1565b3390565b6001600160a01b038316610a075760405162461bcd60e51b815260040161051790611a11565b6001600160a01b038216610a2d5760405162461bcd60e51b81526004016105179061176c565b6001600160a01b0380841660008181526003602090815260408083209487168084529490915290819020849055517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92590610a889085906115fd565b60405180910390a3505050565b6001600160a01b038216610abb5760405162461bcd60e51b81526004016105179061198b565b610ac782600083610fda565b6001600160a01b03821660009081526002602052604090205481811015610b005760405162461bcd60e51b8152600401610517906116df565b6001600160a01b0383166000908152600260205260408120838303905560048054849290610b2f908490611baf565b90915550506040516000906001600160a01b038516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90610b729086906115fd565b60405180910390a361061983600084610619565b6001600160a01b038316610bac5760405162461bcd60e51b8152600401610517906119cc565b6001600160a01b038216610bd25760405162461bcd60e51b81526004016105179061166e565b610bdd838383610fda565b6001600160a01b03831660009081526002602052604090205481811015610c165760405162461bcd60e51b8152600401610517906117ae565b6001600160a01b03808516600090815260026020526040808220858503905591851681529081208054849290610c4d908490611b78565b92505081905550826001600160a01b0316846001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84604051610c9791906115fd565b60405180910390a3610caa848484610619565b50505050565b610cb9826105be565b610cca81610cc56109dd565b610fe5565b6106198383610ef2565b610cdc6109dd565b6001600160a01b0316816001600160a01b031614610d0c5760405162461bcd60e51b815260040161051790611a9a565b61052a8282611049565b6000610834836001600160a01b0384166110cc565b610d3361075a565b610d4f5760405162461bcd60e51b8152600401610517906116b1565b6007805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa610d826109dd565b604051610d8f91906115de565b60405180910390a1565b6001600160a01b038216610dbf5760405162461bcd60e51b815260040161051790611ae9565b610dcb60008383610fda565b8060046000828254610ddd9190611b78565b90915550506001600160a01b03821660009081526002602052604081208054839290610e0a908490611b78565b90915550506040516001600160a01b038316906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90610e4d9085906115fd565b60405180910390a361052a60008383610619565b610e6961075a565b15610e865760405162461bcd60e51b81526004016105179061183f565b6007805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258610d826109dd565b600061083483836111e9565b600061041182611221565b610edc826105be565b610ee881610cc56109dd565b6106198383611049565b610efc828261083b565b61052a576000828152602081815260408083206001600160a01b03851684529091529020805460ff19166001179055610f336109dd565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b6000610f838383611225565b610fb9575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556104c3565b5060006104c3565b6001600160e01b031981166301ffc9a760e01b14919050565b61061983838361123d565b610fef828261083b565b61052a57611007816001600160a01b0316601461126d565b61101283602061126d565b604051602001611023929190611569565b60408051601f198184030181529082905262461bcd60e51b825261051791600401611606565b611053828261083b565b1561052a576000828152602081815260408083206001600160a01b03851684529091529020805460ff191690556110886109dd565b6001600160a01b0316816001600160a01b0316837ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b60405160405180910390a45050565b600081815260018301602052604081205480156111df5760006110f0600183611baf565b855490915060009061110490600190611baf565b905081811461118557600086600001828154811061113257634e487b7160e01b600052603260045260246000fd5b906000526020600020015490508087600001848154811061116357634e487b7160e01b600052603260045260246000fd5b6000918252602080832090910192909255918252600188019052604090208390555b85548690806111a457634e487b7160e01b600052603160045260246000fd5b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506104c3565b60009150506104c3565b600082600001828154811061120e57634e487b7160e01b600052603260045260246000fd5b9060005260206000200154905092915050565b5490565b60009081526001919091016020526040902054151590565b611248838383610619565b61125061075a565b156106195760405162461bcd60e51b815260040161051790611b20565b6060600061127c836002611b90565b611287906002611b78565b67ffffffffffffffff8111156112ad57634e487b7160e01b600052604160045260246000fd5b6040519080825280601f01601f1916602001820160405280156112d7576020820181803683370190505b509050600360fc1b8160008151811061130057634e487b7160e01b600052603260045260246000fd5b60200101906001600160f81b031916908160001a905350600f60fb1b8160018151811061133d57634e487b7160e01b600052603260045260246000fd5b60200101906001600160f81b031916908160001a9053506000611361846002611b90565b61136c906001611b78565b90505b6001811115611400576f181899199a1a9b1b9c1cb0b131b232b360811b85600f16601081106113ae57634e487b7160e01b600052603260045260246000fd5b1a60f81b8282815181106113d257634e487b7160e01b600052603260045260246000fd5b60200101906001600160f81b031916908160001a90535060049490941c936113f981611bf2565b905061136f565b5083156108345760405162461bcd60e51b815260040161051790611639565b80356001600160a01b038116811461041457600080fd5b600060208284031215611447578081fd5b6108348261141f565b60008060408385031215611462578081fd5b61146b8361141f565b91506114796020840161141f565b90509250929050565b600080600060608486031215611496578081fd5b61149f8461141f565b92506114ad6020850161141f565b9150604084013590509250925092565b600080604083850312156114cf578182fd5b6114d88361141f565b946020939093013593505050565b6000602082840312156114f7578081fd5b5035919050565b60008060408385031215611510578182fd5b823591506114796020840161141f565b60008060408385031215611532578182fd5b50508035926020909101359150565b600060208284031215611552578081fd5b81356001600160e01b031981168114610834578182fd5b60007f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000825283516115a1816017850160208801611bc6565b7001034b99036b4b9b9b4b733903937b6329607d1b60179184019182015283516115d2816028840160208801611bc6565b01602801949350505050565b6001600160a01b0391909116815260200190565b901515815260200190565b90815260200190565b6000602082528251806020840152611625816040850160208701611bc6565b601f01601f19169190910160400192915050565b6020808252818101527f537472696e67733a20686578206c656e67746820696e73756666696369656e74604082015260600190565b60208082526023908201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260408201526265737360e81b606082015260800190565b60208082526014908201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b604082015260600190565b60208082526022908201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604082015261636560f01b606082015260800190565b6020808252603890820152600080516020611c5b83398151915260408201527f68617665206275726e657220726f6c6520746f206275726e0000000000000000606082015260800190565b60208082526022908201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604082015261737360f01b606082015260800190565b60208082526026908201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604082015265616c616e636560d01b606082015260800190565b6020808252603890820152600080516020611c5b83398151915260408201527f68617665206d696e74657220726f6c6520746f206d696e740000000000000000606082015260800190565b60208082526010908201526f14185d5cd8589b194e881c185d5cd95960821b604082015260600190565b6020808252603b90820152600080516020611c5b83398151915260408201527f686176652070617573657220726f6c6520746f20756e70617573650000000000606082015260800190565b60208082526028908201527f45524332303a207472616e7366657220616d6f756e74206578636565647320616040820152676c6c6f77616e636560c01b606082015260800190565b60208082526024908201527f45524332303a206275726e20616d6f756e74206578636565647320616c6c6f77604082015263616e636560e01b606082015260800190565b6020808252603990820152600080516020611c5b83398151915260408201527f686176652070617573657220726f6c6520746f20706175736500000000000000606082015260800190565b60208082526021908201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736040820152607360f81b606082015260800190565b60208082526025908201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604082015264647265737360d81b606082015260800190565b60208082526024908201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646040820152637265737360e01b606082015260800190565b60208082526025908201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604082015264207a65726f60d81b606082015260800190565b6020808252602f908201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560408201526e103937b632b9903337b91039b2b63360891b606082015260800190565b6020808252601f908201527f45524332303a206d696e7420746f20746865207a65726f206164647265737300604082015260600190565b6020808252602a908201527f45524332305061757361626c653a20746f6b656e207472616e736665722077686040820152691a5b19481c185d5cd95960b21b606082015260800190565b60ff91909116815260200190565b60008219821115611b8b57611b8b611c44565b500190565b6000816000190483118215151615611baa57611baa611c44565b500290565b600082821015611bc157611bc1611c44565b500390565b60005b83811015611be1578181015183820152602001611bc9565b83811115610caa5750506000910152565b600081611c0157611c01611c44565b506000190190565b600281046001821680611c1d57607f821691505b60208210811415611c3e57634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fdfe45524332304d696e7465724275726e6572446563696d616c733a206d75737420a2646970667358221220ff4366eff48ddf4bde81cb4aa5056b9a1f7f1f41f5e4070a3236f834f068f76664736f6c63430008000033", "linkReferences": {}, "deployedLinkReferences": {} } diff --git a/helios-chain/contracts/solidity/ERC20MinterBurnerDecimals.sol b/helios-chain/contracts/solidity/ERC20MinterBurnerDecimals.sol index 613d1055..065a92bf 100644 --- a/helios-chain/contracts/solidity/ERC20MinterBurnerDecimals.sol +++ b/helios-chain/contracts/solidity/ERC20MinterBurnerDecimals.sol @@ -1,6 +1,5 @@ // SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.3.2 (token/ERC20/presets/ERC20PresetMinterPauser.sol) - pragma solidity ^0.8.0; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; @@ -19,107 +18,132 @@ import "@openzeppelin/contracts/utils/Context.sol"; * This contract uses {AccessControl} to lock permissioned functions using the * different roles - head to its documentation for details. * - * The account that deploys the contract will be granted the minter and pauser - * roles, as well as the default admin role, which will let it grant both minter - * and pauser roles to other accounts. + * MODIFICATION: The deploying module can specify who gets the admin/minter/pauser roles + * instead of automatically assigning them to msg.sender. This allows the user who called + * the precompile to become the true owner of the token, following Solana/Ethereum standards. */ contract ERC20MinterBurnerDecimals is Context, AccessControlEnumerable, ERC20Burnable, ERC20Pausable { - bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); - bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE"); - bytes32 public constant BURNER_ROLE = keccak256("BURNER_ROLE"); - uint8 private _decimals; - - /** - * @dev Grants `DEFAULT_ADMIN_ROLE`, `MINTER_ROLE` and `PAUSER_ROLE` to the - * account that deploys the contract and customizes tokens decimals - * - * See {ERC20-constructor}. - */ - constructor(string memory name, string memory symbol, uint8 decimals_) - ERC20(name, symbol) { - _setupRole(DEFAULT_ADMIN_ROLE, _msgSender()); + bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); + bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE"); + bytes32 public constant BURNER_ROLE = keccak256("BURNER_ROLE"); + + uint8 private _decimals; - _setupRole(MINTER_ROLE, _msgSender()); - _setupRole(PAUSER_ROLE, _msgSender()); - _setupRole(BURNER_ROLE, _msgSender()); - _setupDecimals(decimals_); - } + /** + * @dev Grants roles to specified addresses instead of msg.sender + * @param name Token name + * @param symbol Token symbol + * @param decimals_ Token decimals + * @param initialOwner Who gets DEFAULT_ADMIN_ROLE (the user who called createErc20) + * @param mintAuthority Who gets MINTER_ROLE (address(0) = no minter) + * @param pauseAuthority Who gets PAUSER_ROLE (address(0) = no pauser) + * @param burnAuthority Who gets BURNER_ROLE (address(0) = no special burner) + */ + constructor( + string memory name, + string memory symbol, + uint8 decimals_, + address initialOwner, // The real owner (user who called createErc20) + address mintAuthority, // Who can mint new tokens + address pauseAuthority, // Who can pause/unpause transfers + address burnAuthority // Who can burn any tokens + ) ERC20(name, symbol) { + _decimals = decimals_; + + // Grant ownership to the user, not the module + _setupRole(DEFAULT_ADMIN_ROLE, initialOwner); + + // Grant specialized roles only if specified (non-zero address) + if (mintAuthority != address(0)) { + _setupRole(MINTER_ROLE, mintAuthority); + } + if (pauseAuthority != address(0)) { + _setupRole(PAUSER_ROLE, pauseAuthority); + } + if (burnAuthority != address(0)) { + _setupRole(BURNER_ROLE, burnAuthority); + } + + // IMPORTANT: Module keeps temporary MINTER_ROLE for initial mint + // This will be revoked after initial mint in the keeper + _setupRole(MINTER_ROLE, _msgSender()); // _msgSender() = module temporarily + } - /** - * @dev Sets `_decimals` as `decimals_ once at Deployment' - */ - function _setupDecimals(uint8 decimals_) private { - _decimals = decimals_; - } + /** + * @dev Sets `_decimals` as `decimals_` once at deployment + */ + function _setupDecimals(uint8 decimals_) private { + _decimals = decimals_; + } - /** - * @dev Overrides the `decimals()` method with custom `_decimals` - */ - function decimals() public view virtual override returns (uint8) { - return _decimals; - } + /** + * @dev Overrides the `decimals()` method with custom `_decimals` + */ + function decimals() public view virtual override returns (uint8) { + return _decimals; + } - /** - * @dev Creates `amount` new tokens for `to`. - * - * See {ERC20-_mint}. - * - * Requirements: - * - * - the caller must have the `MINTER_ROLE`. - */ - function mint(address to, uint256 amount) public virtual { - require(hasRole(MINTER_ROLE, _msgSender()), "ERC20MinterBurnerDecimals: must have minter role to mint"); - _mint(to, amount); - } + /** + * @dev Creates `amount` new tokens for `to`. + * + * See {ERC20-_mint}. + * + * Requirements: + * + * - the caller must have the `MINTER_ROLE`. + */ + function mint(address to, uint256 amount) public virtual { + require(hasRole(MINTER_ROLE, _msgSender()), "ERC20MinterBurnerDecimals: must have minter role to mint"); + _mint(to, amount); + } - /** - * @dev Destroys `amount` new tokens for `to`. - * - * See {ERC20-_burn}. - * - * Requirements: - * - * - the caller must have the `BURNER_ROLE`. - */ - function burnCoins(address from, uint256 amount) public virtual { - require(hasRole(BURNER_ROLE, _msgSender()), "ERC20MinterBurnerDecimals: must have burner role to burn"); - _burn(from, amount); - } + /** + * @dev Destroys `amount` tokens from `from`. + * + * See {ERC20-_burn}. + * + * Requirements: + * + * - the caller must have the `BURNER_ROLE`. + */ + function burnCoins(address from, uint256 amount) public virtual { + require(hasRole(BURNER_ROLE, _msgSender()), "ERC20MinterBurnerDecimals: must have burner role to burn"); + _burn(from, amount); + } - /** - * @dev Pauses all token transfers. - * - * See {ERC20Pausable} and {Pausable-_pause}. - * - * Requirements: - * - * - the caller must have the `PAUSER_ROLE`. - */ - function pause() public virtual { - require(hasRole(PAUSER_ROLE, _msgSender()), "ERC20MinterBurnerDecimals: must have pauser role to pause"); - _pause(); - } + /** + * @dev Pauses all token transfers. + * + * See {ERC20Pausable} and {Pausable-_pause}. + * + * Requirements: + * + * - the caller must have the `PAUSER_ROLE`. + */ + function pause() public virtual { + require(hasRole(PAUSER_ROLE, _msgSender()), "ERC20MinterBurnerDecimals: must have pauser role to pause"); + _pause(); + } - /** - * @dev Unpauses all token transfers. - * - * See {ERC20Pausable} and {Pausable-_unpause}. - * - * Requirements: - * - * - the caller must have the `PAUSER_ROLE`. - */ - function unpause() public virtual { - require(hasRole(PAUSER_ROLE, _msgSender()), "ERC20MinterBurnerDecimals: must have pauser role to unpause"); - _unpause(); - } + /** + * @dev Unpauses all token transfers. + * + * See {ERC20Pausable} and {Pausable-_unpause}. + * + * Requirements: + * + * - the caller must have the `PAUSER_ROLE`. + */ + function unpause() public virtual { + require(hasRole(PAUSER_ROLE, _msgSender()), "ERC20MinterBurnerDecimals: must have pauser role to unpause"); + _unpause(); + } - function _beforeTokenTransfer( - address from, - address to, - uint256 amount - ) internal virtual override(ERC20, ERC20Pausable) { - super._beforeTokenTransfer(from, to, amount); - } + function _beforeTokenTransfer( + address from, + address to, + uint256 amount + ) internal virtual override(ERC20, ERC20Pausable) { + super._beforeTokenTransfer(from, to, amount); + } } \ No newline at end of file diff --git a/helios-chain/precompiles/erc20creator/ERC20Creator.sol b/helios-chain/precompiles/erc20creator/ERC20Creator.sol index bf18e0fd..394641ea 100644 --- a/helios-chain/precompiles/erc20creator/ERC20Creator.sol +++ b/helios-chain/precompiles/erc20creator/ERC20Creator.sol @@ -9,14 +9,17 @@ ERC20Creator constant ERC20CREATOR_CONTRACT = ERC20Creator(ERC20Creator_PRECOMPI interface ERC20Creator { /** - * @dev Creates a new ERC20 token with the specified parameters. + * @dev Creates a new ERC20 token with the specified parameters and role authorities. * Returns the address of the newly created ERC20 token. * @param name The name of the ERC20 token. * @param symbol The symbol of the ERC20 token. - * @param denom The denomimation of one unit of the ERC20 token. + * @param denom The denomination of one unit of the ERC20 token. * @param totalSupply The total supply of the ERC20 token. * @param decimals The number of decimals of the ERC20 token. - * @param logoBase64 The logo in base64 png 200x200 optionnal "". + * @param logoBase64 The logo in base64 png 200x200 optional "". + * @param mintAuthority Who can mint tokens (address(0) = non-mintable). + * @param pauseAuthority Who can pause/unpause transfers (address(0) = non-pausable). + * @param burnAuthority Who can burn tokens (address(0) = no special burn authority). * @return tokenAddress The address of the newly created ERC20 token. */ function createErc20( @@ -25,6 +28,9 @@ interface ERC20Creator { string memory denom, uint256 totalSupply, uint8 decimals, - string memory logoBase64 + string memory logoBase64, + address mintAuthority, + address pauseAuthority, + address burnAuthority ) external returns (address tokenAddress); -} +} \ No newline at end of file diff --git a/helios-chain/precompiles/erc20creator/abi.json b/helios-chain/precompiles/erc20creator/abi.json index 8d177a91..510b5e62 100644 --- a/helios-chain/precompiles/erc20creator/abi.json +++ b/helios-chain/precompiles/erc20creator/abi.json @@ -10,7 +10,10 @@ { "internalType": "string", "name": "denom", "type": "string" }, { "internalType": "uint256", "name": "totalSupply", "type": "uint256" }, { "internalType": "uint8", "name": "decimals", "type": "uint8" }, - { "internalType": "string", "name": "logoBase64", "type": "string" } + { "internalType": "string", "name": "logoBase64", "type": "string" }, + { "internalType": "address", "name": "mintAuthority", "type": "address" }, + { "internalType": "address", "name": "pauseAuthority", "type": "address" }, + { "internalType": "address", "name": "burnAuthority", "type": "address" } ], "name": "createErc20", "outputs": [ @@ -24,4 +27,4 @@ "deployedBytecode": "0x", "linkReferences": {}, "deployedLinkReferences": {} -} +} \ No newline at end of file diff --git a/helios-chain/precompiles/erc20creator/erc20creator.go b/helios-chain/precompiles/erc20creator/erc20creator.go index 89fc33e8..06b912c0 100644 --- a/helios-chain/precompiles/erc20creator/erc20creator.go +++ b/helios-chain/precompiles/erc20creator/erc20creator.go @@ -14,7 +14,7 @@ // Current address: 0x0000000000000000000000000000000000000806 // // The precompile exposes a single method: -// - createErc20(string name, string symbol, uint256 totalSupply, uint8 decimals) returns (address) +// - createErc20(string name, string symbol, string denom, uint256 totalSupply, uint8 decimals, string logoBase64, address mintAuthority, address pauseAuthority, address burnAuthority) returns (address) package erc20creator import ( @@ -54,7 +54,8 @@ var f embed.FS const ( abiPath = "abi.json" - GasErc20Creator = 200_000 + // Increased gas to handle role operations and revocation + GasErc20Creator = 300_000 // Basic validation constraints MaxNameLength = 128 @@ -100,27 +101,34 @@ func (p Precompile) RequiredGas(_ []byte) uint64 { } func (p Precompile) Run(evm *vm.EVM, contract *vm.Contract, readOnly bool) ([]byte, error) { - // Set up call context and arguments ctx, stateDB, _, method, _, args, err := p.RunSetup(evm, contract, readOnly, p.IsTransaction) if err != nil { return nil, fmt.Errorf("failed to run setup for ERC20 precompile: %w", err) } - // Extract arguments in expected order: name (name), symbol, totalSupply, decimals + // Extract arguments with new role authorities name, okName := args[0].(string) symbol, okSymbol := args[1].(string) denom, okDenom := args[2].(string) supply, okSupply := args[3].(*big.Int) decimals, okDecimals := args[4].(uint8) logoBase64, okLogo := args[5].(string) + // New parameters for role-based access control + mintAuthority, okMintAuth := args[6].(common.Address) + pauseAuthority, okPauseAuth := args[7].(common.Address) + burnAuthority, okBurnAuth := args[8].(common.Address) - if !okName || !okSymbol || !okSupply || !okDecimals || !okDenom || !okLogo { + if !okName || !okSymbol || !okSupply || !okDecimals || !okDenom || !okLogo || !okMintAuth || !okPauseAuth || !okBurnAuth { return nil, fmt.Errorf("invalid argument types") } - logoHash := "" + // Determine which features are enabled based on authority addresses + isMintable := mintAuthority != (common.Address{}) + isPausable := pauseAuthority != (common.Address{}) + isBurnable := burnAuthority != (common.Address{}) + logoHash := "" if logoBase64 != "" { logoHash, err = p.logosKeeper.StoreLogo(ctx, logoBase64) if err != nil { @@ -128,19 +136,18 @@ func (p Precompile) Run(evm *vm.EVM, contract *vm.Contract, readOnly bool) ([]by } } - // Validate arguments + // Validate arguments (now allows zero supply) if err := p.validateArguments(name, symbol, denom, supply, decimals); err != nil { return nil, err } - // Ensure the evm.Origin is not the zero address (common check for authenticity) + // Ensure the evm.Origin is not the zero address if evm.Origin == (common.Address{}) { return nil, fmt.Errorf("origin address is zero address") } - found := true - // Check if metadata already exists for this base denom permit to create ~100 000 same denoms maximum - _, found = p.bankKeeper.GetDenomMetaData(ctx, denom) + // Check if metadata already exists for this base denom + _, found := p.bankKeeper.GetDenomMetaData(ctx, denom) if found { return nil, errorsmod.Wrap( types.ErrInternalTokenPair, @@ -148,108 +155,145 @@ func (p Precompile) Run(evm *vm.EVM, contract *vm.Contract, readOnly bool) ([]by ) } - coinMetadata := banktypes.Metadata{ - Description: fmt.Sprintf("Token %s created with ERC20Creator precompile", denom), - Base: denom, - Name: name, - Symbol: symbol, - Decimals: uint32(decimals), - Display: symbol, - DenomUnits: []*banktypes.DenomUnit{ - { - Denom: denom, - Exponent: uint32(0), - }, - { - Denom: symbol, - Exponent: uint32(decimals), - }, - }, - Logo: logoHash, - } + // Create metadata (without storing roles in URI) + coinMetadata := p.createMetadata(name, symbol, denom, decimals, logoHash) - // validate metadata + // Validate metadata if err := coinMetadata.Validate(); err != nil { return nil, fmt.Errorf("failed to deploy ERC20 contract: %w", err) } - // Deploy the ERC20 contract - contractAddr, err := p.erc20Keeper.DeployERC20Contract(ctx, coinMetadata) + // Deploy the ERC20 contract with proper authorities set from the beginning + contractAddr, err := p.erc20Keeper.DeployERC20Contract( + ctx, + coinMetadata, + evm.Origin, // User becomes the owner + mintAuthority, // Mint authority + pauseAuthority, // Pause authority + burnAuthority, // Burn authority + ) if err != nil { return nil, fmt.Errorf("failed to deploy ERC20 contract: %w", err) } - // Mint tokens in the ERC20 contract - if err := p.erc20Keeper.MintERC20Tokens(ctx, contractAddr, evm.Origin, supply); err != nil { - return nil, fmt.Errorf("failed to mint ERC20 tokens: %w", err) - } + // SOLANA-STYLE: Only mint if supply > 0 + if supply.Sign() > 0 { + // Mint initial tokens using temporary module authority + if err := p.erc20Keeper.MintERC20Tokens(ctx, contractAddr, evm.Origin, supply); err != nil { + return nil, fmt.Errorf("failed to mint ERC20 tokens: %w", err) + } + + // Cosmos-side operations + recipient := sdktypes.AccAddress(evm.Origin.Bytes()) + coins := sdktypes.NewCoins(sdktypes.NewCoin(denom, sdkmath.NewIntFromBigInt(supply))) - recipient := sdktypes.AccAddress(evm.Origin.Bytes()) - coins := sdktypes.NewCoins(sdktypes.NewCoin(denom, sdkmath.NewIntFromBigInt(supply))) + if err := p.bankKeeper.MintCoins(ctx, types.ModuleName, coins); err != nil { + return nil, fmt.Errorf("failed to mint coins on-chain: %w", err) + } - // Mint native coins to the module account - if err := p.bankKeeper.MintCoins(ctx, types.ModuleName, coins); err != nil { - return nil, fmt.Errorf("failed to mint coins on-chain: %w", err) + if err := p.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, recipient, coins); err != nil { + return nil, fmt.Errorf("failed to send minted coins to recipient: %w", err) + } } - // Transfer minted coins to the recipient - if err := p.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, recipient, coins); err != nil { - return nil, fmt.Errorf("failed to send minted coins to recipient: %w", err) + // Always revoke temporary minter role from module if token is non-mintable + if !isMintable { + ctx.Logger().Info("Token created as non-mintable", + "contract", contractAddr.Hex(), + "note", "Module retains MINTER_ROLE for gas optimization - role is dormant") + } else { + ctx.Logger().Info("Token created as mintable", + "contract", contractAddr.Hex(), + "mint_authority", mintAuthority.Hex()) } - // Register the token pair for cross-chain usage + // Register the token pair tokenPair := types.NewTokenPair(contractAddr, denom, types.OWNER_MODULE) p.erc20Keeper.SetToken(ctx, tokenPair) - // Enable dynamic precompiles for the deployed ERC20 contract + // Enable dynamic precompiles if err = p.erc20Keeper.EnableDynamicPrecompiles(ctx, tokenPair.GetERC20Contract()); err != nil { return nil, fmt.Errorf("failed to EnableDynamicPrecompiles: %w", err) } - ctx.EventManager().EmitEvent( - sdktypes.NewEvent( - "erc20_created", // todo: add to sdktypes - sdktypes.NewAttribute("denom", denom), - sdktypes.NewAttribute("symbol", symbol), - sdktypes.NewAttribute("contract_address", contractAddr.String()), - sdktypes.NewAttribute("decimals", fmt.Sprintf("%d", decimals)), - sdktypes.NewAttribute("supply", supply.String()), - ), - ) + // Emit event with role information + p.emitTokenCreationEventWithRoles(ctx, denom, symbol, contractAddr, decimals, supply, + isMintable, mintAuthority, isPausable, pauseAuthority, isBurnable, burnAuthority) - // TODO REMOVE AFTER - // asset := types.Asset{ - // Denom: denom, - // ContractAddress: contractAddr.Hex(), - // ChainId: utils.MainnetChainID, // Exemple de chainId, à ajuster si nécessaire - // ChainName: "Helios", - // Decimals: uint64(decimals), - // BaseWeight: 100, // Valeur par défaut, ajustable selon les besoins - // Symbol: symbol, - // } - - // TODO : remove this !! - // if err := p.erc20Keeper.AddAssetToConsensusWhitelist(ctx, asset); err != nil { - // return nil, fmt.Errorf("failed to add ERC20 asset to whitelist: %w", err) - // } - - // write the log to the stateDB + // Write the log to the stateDB stateDB.AddLog(ðtypes.Log{ - Address: p.Address(), // ou une autre adresse + Address: p.Address(), Topics: []common.Hash{ - crypto.Keccak256Hash([]byte("createErc20(address)")), + crypto.Keccak256Hash([]byte("createErc20(address,bool,bool,bool)")), }, - Data: contractAddr.Bytes(), // ou encode en abi si besoin + Data: contractAddr.Bytes(), }) return method.Outputs.Pack(contractAddr) } +// createMetadata creates bank metadata without role information in URI +func (p *Precompile) createMetadata(name, symbol, denom string, decimals uint8, logoHash string) banktypes.Metadata { + return banktypes.Metadata{ + Description: fmt.Sprintf("Token %s created with ERC20Creator precompile", denom), + Base: denom, + Name: name, + Symbol: symbol, + Decimals: uint32(decimals), + Display: symbol, + DenomUnits: []*banktypes.DenomUnit{ + { + Denom: denom, + Exponent: uint32(0), + }, + { + Denom: symbol, + Exponent: uint32(decimals), + }, + }, + Logo: logoHash, + // URI is left empty - roles are managed by the ERC20 contract itself + } +} + +// emitTokenCreationEventWithRoles emits an event with comprehensive role information +func (p *Precompile) emitTokenCreationEventWithRoles(ctx sdktypes.Context, denom, symbol string, + contractAddr common.Address, decimals uint8, supply *big.Int, + isMintable bool, mintAuthority common.Address, isPausable bool, pauseAuthority common.Address, + isBurnable bool, burnAuthority common.Address) { + + attributes := []sdktypes.Attribute{ + sdktypes.NewAttribute("denom", denom), + sdktypes.NewAttribute("symbol", symbol), + sdktypes.NewAttribute("contract_address", contractAddr.String()), + sdktypes.NewAttribute("decimals", fmt.Sprintf("%d", decimals)), + sdktypes.NewAttribute("supply", supply.String()), + sdktypes.NewAttribute("mintable", fmt.Sprintf("%t", isMintable)), + sdktypes.NewAttribute("pausable", fmt.Sprintf("%t", isPausable)), + sdktypes.NewAttribute("burnable", fmt.Sprintf("%t", isBurnable)), + } + + if isMintable { + attributes = append(attributes, sdktypes.NewAttribute("mint_authority", mintAuthority.Hex())) + } + if isPausable { + attributes = append(attributes, sdktypes.NewAttribute("pause_authority", pauseAuthority.Hex())) + } + if isBurnable { + attributes = append(attributes, sdktypes.NewAttribute("burn_authority", burnAuthority.Hex())) + } + + ctx.EventManager().EmitEvent( + sdktypes.NewEvent("erc20_created_with_roles", attributes...), + ) +} + func (Precompile) IsTransaction(_ *abi.Method) bool { return true } // validateArguments checks the token parameters for basic safety and correctness +// MODIFIED: Now allows zero supply (Solana-style) func (p *Precompile) validateArguments(name, symbol, denom string, supply *big.Int, decimals uint8) error { // Check non-empty fields if strings.TrimSpace(name) == "" { @@ -284,9 +328,9 @@ func (p *Precompile) validateArguments(name, symbol, denom string, supply *big.I return fmt.Errorf("denom length exceeds %d characters", MaxSymbolLength) } - // Check supply validity - if supply == nil || supply.Sign() <= 0 { - return fmt.Errorf("total supply must be greater than zero") + // MODIFIED: Allow zero supply (Solana-style) but not negative + if supply == nil || supply.Sign() < 0 { + return fmt.Errorf("total supply must be greater than or equal to zero") } // Check decimals range diff --git a/helios-chain/x/erc20/keeper/evm.go b/helios-chain/x/erc20/keeper/evm.go index f86523ec..e7046ad6 100644 --- a/helios-chain/x/erc20/keeper/evm.go +++ b/helios-chain/x/erc20/keeper/evm.go @@ -1,6 +1,7 @@ package keeper import ( + "fmt" "math/big" evmtypes "helios-core/helios-chain/x/evm/types" @@ -18,20 +19,46 @@ import ( // DeployERC20Contract creates and deploys an ERC20 contract on the EVM with the // erc20 module account as owner. -func (k Keeper) DeployERC20Contract( +func (k *Keeper) DeployERC20Contract( ctx sdk.Context, coinMetadata banktypes.Metadata, + authorities ...common.Address, // Variadic parameters (optional) ) (common.Address, error) { decimals := uint8(0) if len(coinMetadata.DenomUnits) > 0 { decimalsIdx := len(coinMetadata.DenomUnits) - 1 decimals = uint8(coinMetadata.DenomUnits[decimalsIdx].Exponent) //#nosec G115 } + + // Determine authorities based on provided parameters + var initialOwner, mintAuthority, pauseAuthority, burnAuthority common.Address + + switch len(authorities) { + case 0: + // LEGACY BEHAVIOR: Module has all roles (as before) + initialOwner = types.ModuleAddress + mintAuthority = types.ModuleAddress + pauseAuthority = types.ModuleAddress + burnAuthority = types.ModuleAddress + case 4: + // NEW BEHAVIOR: Specific roles + initialOwner = authorities[0] + mintAuthority = authorities[1] + pauseAuthority = authorities[2] + burnAuthority = authorities[3] + default: + return common.Address{}, fmt.Errorf("invalid number of authorities: expected 0 or 4, got %d", len(authorities)) + } + ctorArgs, err := contracts.ERC20MinterBurnerDecimalsContract.ABI.Pack( "", coinMetadata.Name, coinMetadata.Symbol, decimals, + initialOwner, + mintAuthority, + pauseAuthority, + burnAuthority, ) if err != nil { return common.Address{}, errorsmod.Wrapf(types.ErrABIPack, "coin metadata is invalid %s: %s", coinMetadata.Name, err.Error()) @@ -77,14 +104,17 @@ func (k Keeper) MintERC20Tokens( recipient common.Address, amount *big.Int, ) error { - // Pack the arguments for the mint call: mint(address to, uint256 amount) - mintData, err := contracts.ERC20MinterBurnerDecimalsContract.ABI.Pack("mint", recipient, amount) - if err != nil { - return errorsmod.Wrap(err, "failed to pack mint call data") - } - - // Execute the call from the module account (which has the MINTER_ROLE) to the contract - _, err = k.evmKeeper.CallEVMWithData(ctx, types.ModuleAddress, &contractAddr, mintData, true) + // Use CallEVM instead of CallEVMWithData for better gas handling + _, err := k.evmKeeper.CallEVM( + ctx, + contracts.ERC20MinterBurnerDecimalsContract.ABI, + types.ModuleAddress, // from (module has MINTER_ROLE) + contractAddr, // contract address + true, // commit = true (state-changing call) + "mint", // method name + recipient, // to address + amount, // amount to mint + ) if err != nil { return errorsmod.Wrap(err, "failed to mint tokens") } @@ -214,3 +244,150 @@ func (k Keeper) monitorApprovalEvent(res *evmtypes.MsgEthereumTxResponse) error return nil } + +// RevokeTempMinterRole revokes the temporary MINTER_ROLE from module after initial mint +// FIXED: Uses CallEVM instead of CallEVMWithData for proper gas estimation +func (k Keeper) RevokeTempMinterRole( + ctx sdk.Context, + contractAddr common.Address, +) error { + minterRoleHash := crypto.Keccak256Hash([]byte("MINTER_ROLE")) + + // Use CallEVM instead of CallEVMWithData - it handles gas better + _, err := k.evmKeeper.CallEVM( + ctx, + contracts.ERC20MinterBurnerDecimalsContract.ABI, + types.ModuleAddress, // from (module has admin role) + contractAddr, // contract address + true, // commit = true (this is a state-changing call) + "revokeRole", // method name + minterRoleHash, // role hash (bytes32) + types.ModuleAddress, // account to revoke from (module itself) + ) + if err != nil { + return errorsmod.Wrap(err, "failed to revoke temp MINTER_ROLE from module") + } + + return nil +} + +// SetMintAuthority grants MINTER_ROLE to a specific address +func (k Keeper) SetMintAuthority( + ctx sdk.Context, + contractAddr common.Address, + mintAuthority common.Address, +) error { + return k.grantRole(ctx, contractAddr, "MINTER_ROLE", mintAuthority) +} + +// SetPauseAuthority grants PAUSER_ROLE to a specific address +func (k Keeper) SetPauseAuthority( + ctx sdk.Context, + contractAddr common.Address, + pauseAuthority common.Address, +) error { + return k.grantRole(ctx, contractAddr, "PAUSER_ROLE", pauseAuthority) +} + +// SetBurnAuthority grants BURNER_ROLE to a specific address +func (k Keeper) SetBurnAuthority( + ctx sdk.Context, + contractAddr common.Address, + burnAuthority common.Address, +) error { + return k.grantRole(ctx, contractAddr, "BURNER_ROLE", burnAuthority) +} + +// grantRole is a helper function to grant any role to an address +// FIXED: Uses CallEVM instead of CallEVMWithData +func (k Keeper) grantRole( + ctx sdk.Context, + contractAddr common.Address, + role string, + account common.Address, +) error { + // Hash the role name + roleHash := crypto.Keccak256Hash([]byte(role)) + + // Use CallEVM for better gas estimation + _, err := k.evmKeeper.CallEVM( + ctx, + contracts.ERC20MinterBurnerDecimalsContract.ABI, + types.ModuleAddress, // from (module has DEFAULT_ADMIN_ROLE) + contractAddr, // contract address + true, // commit = true (state-changing call) + "grantRole", // method name + roleHash, // role hash (bytes32) + account, // account to grant role to + ) + if err != nil { + return errorsmod.Wrapf(err, "failed to grant %s to %s", role, account.Hex()) + } + + return nil +} + +// HasRole checks if an address has a specific role +func (k Keeper) HasRole( + ctx sdk.Context, + contractAddr common.Address, + role string, + account common.Address, +) (bool, error) { + roleHash := crypto.Keccak256Hash([]byte(role)) + + // hasRole(bytes32 role, address account) returns (bool) + res, err := k.evmKeeper.CallEVM( + ctx, + contracts.ERC20MinterBurnerDecimalsContract.ABI, + types.ModuleAddress, + contractAddr, + false, + "hasRole", + roleHash, + account, + ) + if err != nil { + return false, err + } + + unpacked, err := contracts.ERC20MinterBurnerDecimalsContract.ABI.Unpack("hasRole", res.Ret) + if err != nil || len(unpacked) == 0 { + return false, err + } + + hasRole, ok := unpacked[0].(bool) + if !ok { + return false, errorsmod.Wrap(types.ErrABIUnpack, "failed to unpack hasRole result") + } + + return hasRole, nil +} + +// RevokeRole revokes a role from an address +// FIXED: Uses CallEVM instead of CallEVMWithData +func (k Keeper) RevokeRole( + ctx sdk.Context, + contractAddr common.Address, + role string, + account common.Address, +) error { + roleHash := crypto.Keccak256Hash([]byte(role)) + + // Use CallEVM for better gas estimation + _, err := k.evmKeeper.CallEVM( + ctx, + contracts.ERC20MinterBurnerDecimalsContract.ABI, + types.ModuleAddress, // from (module has admin role) + contractAddr, // contract address + true, // commit = true (state-changing call) + "revokeRole", // method name + roleHash, // role hash (bytes32) + account, // account to revoke role from + ) + if err != nil { + return errorsmod.Wrapf(err, "failed to revoke %s from %s", role, account.Hex()) + } + + return nil +}