diff --git a/cadence/args/deploy-erc20-deployer-args.json b/cadence/args/deploy-erc20-deployer-args.json new file mode 100644 index 00000000..4274e6a4 --- /dev/null +++ b/cadence/args/deploy-erc20-deployer-args.json @@ -0,0 +1,14 @@ +[ + { + "type": "String", + "value": "608060405234801561001057600080fd5b50338061003757604051631e4fbdf760e01b81526000600482015260240160405180910390fd5b61004081610046565b50610096565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b612096806100a56000396000f3fe60806040523480156200001157600080fd5b5060043610620000875760003560e01c8063715018a61162000062578063715018a614620000fc5780638da5cb5b1462000108578063ee2d8496146200011a578063f2fde38b146200013157600080fd5b806301ffc9a7146200008c578063476d399714620000b85780636418e6de14620000e8575b600080fd5b620000a36200009d36600462000438565b62000148565b60405190151581526020015b60405180910390f35b620000cf620000c936600462000516565b62000180565b6040516001600160a01b039091168152602001620000af565b600154620000cf906001600160a01b031681565b62000106620002a5565b005b6000546001600160a01b0316620000cf565b620001066200012b366004620005f8565b620002bd565b6200010662000142366004620005f8565b62000367565b60006001600160e01b0319821663476d399760e01b14806200017a57506301ffc9a760e01b6001600160e01b03198316145b92915050565b6001546000906001600160a01b03163314620002095760405162461bcd60e51b815260206004820152603f60248201527f466c6f7745564d4272696467656445524332304465706c6f7965723a204f6e6c60448201527f792064656c656761746564206465706c6f7965722063616e206465706c6f790060648201526084015b60405180910390fd5b600080546001600160a01b0316878787878760405162000229906200042a565b6200023a969594939291906200066b565b604051809103906000f08015801562000257573d6000803e3d6000fd5b5090507f99a64021330f1af36b3fd5f64a1d12b99b8ddf91fa553618c4df01ffba4c1cee818888888860405162000293959493929190620006f4565b60405180910390a19695505050505050565b620002af620003ab565b620002bb6000620003da565b565b620002c7620003ab565b6001600160a01b038116620003455760405162461bcd60e51b815260206004820152603f60248201527f466c6f7745564d4272696467656445524332304465706c6f7965723a20496e7660448201527f616c69642064656c656761746564206465706c6f796572206164647265737300606482015260840162000200565b600180546001600160a01b0319166001600160a01b0392909216919091179055565b62000371620003ab565b6001600160a01b0381166200039d57604051631e4fbdf760e01b81526000600482015260240162000200565b620003a881620003da565b50565b6000546001600160a01b03163314620002bb5760405163118cdaa760e01b815233600482015260240162000200565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6118fa806200076783390190565b6000602082840312156200044b57600080fd5b81356001600160e01b0319811681146200046457600080fd5b9392505050565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126200049357600080fd5b813567ffffffffffffffff80821115620004b157620004b16200046b565b604051601f8301601f19908116603f01168101908282118183101715620004dc57620004dc6200046b565b81604052838152866020858801011115620004f657600080fd5b836020870160208301376000602085830101528094505050505092915050565b600080600080600060a086880312156200052f57600080fd5b853567ffffffffffffffff808211156200054857600080fd5b6200055689838a0162000481565b965060208801359150808211156200056d57600080fd5b6200057b89838a0162000481565b955060408801359150808211156200059257600080fd5b620005a089838a0162000481565b94506060880135915080821115620005b757600080fd5b620005c589838a0162000481565b93506080880135915080821115620005dc57600080fd5b50620005eb8882890162000481565b9150509295509295909350565b6000602082840312156200060b57600080fd5b81356001600160a01b03811681146200046457600080fd5b6000815180845260005b818110156200064b576020818501810151868301820152016200062d565b506000602082860101526020601f19601f83011685010191505092915050565b6001600160a01b038716815260c060208201819052600090620006919083018862000623565b8281036040840152620006a5818862000623565b90508281036060840152620006bb818762000623565b90508281036080840152620006d1818662000623565b905082810360a0840152620006e7818562000623565b9998505050505050505050565b6001600160a01b038616815260a0602082018190526000906200071a9083018762000623565b82810360408401526200072e818762000623565b9050828103606084015262000744818662000623565b905082810360808401526200075a818562000623565b9897505050505050505056fe6101606040523480156200001257600080fd5b50604051620018fa380380620018fa833981016040819052620000359162000357565b6040805180820190915260018152603160f81b6020820152859081908882886003620000628382620004db565b506004620000718282620004db565b5050506001600160a01b038116620000a457604051631e4fbdf760e01b8152600060048201526024015b60405180910390fd5b620000af816200019f565b50620000bd826006620001f1565b61012052620000ce816007620001f1565b61014052815160208084019190912060e052815190820120610100524660a0526200015c60e05161010051604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201529081019290925260608201524660808201523060a082015260009060c00160405160208183030381529060405280519060200120905090565b60805250503060c052506009620001748482620004db565b50600a620001838382620004db565b50600b620001928282620004db565b5050505050505062000601565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6000602083511015620002115762000209836200022a565b905062000224565b816200021e8482620004db565b5060ff90505b92915050565b600080829050601f8151111562000258578260405163305a27a960e01b81526004016200009b9190620005a7565b80516200026582620005dc565b179392505050565b80516001600160a01b03811681146200028557600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60005b83811015620002bd578181015183820152602001620002a3565b50506000910152565b600082601f830112620002d857600080fd5b81516001600160401b0380821115620002f557620002f56200028a565b604051601f8301601f19908116603f011681019082821181831017156200032057620003206200028a565b816040528381528660208588010111156200033a57600080fd5b6200034d846020830160208901620002a0565b9695505050505050565b60008060008060008060c087890312156200037157600080fd5b6200037c876200026d565b60208801519096506001600160401b03808211156200039a57600080fd5b620003a88a838b01620002c6565b96506040890151915080821115620003bf57600080fd5b620003cd8a838b01620002c6565b95506060890151915080821115620003e457600080fd5b620003f28a838b01620002c6565b945060808901519150808211156200040957600080fd5b620004178a838b01620002c6565b935060a08901519150808211156200042e57600080fd5b506200043d89828a01620002c6565b9150509295509295509295565b600181811c908216806200045f57607f821691505b6020821081036200048057634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115620004d6576000816000526020600020601f850160051c81016020861015620004b15750805b601f850160051c820191505b81811015620004d257828155600101620004bd565b5050505b505050565b81516001600160401b03811115620004f757620004f76200028a565b6200050f816200050884546200044a565b8462000486565b602080601f8311600181146200054757600084156200052e5750858301515b600019600386901b1c1916600185901b178555620004d2565b600085815260208120601f198616915b82811015620005785788860151825594840194600190910190840162000557565b5085821015620005975787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6020815260008251806020840152620005c8816040850160208701620002a0565b601f01601f19169190910160400192915050565b80516020808301519190811015620004805760001960209190910360031b1b16919050565b60805160a05160c05160e05161010051610120516101405161129e6200065c6000396000610a8801526000610a5b01526000610918015260006108f00152600061084b015260006108750152600061089f015261129e6000f3fe608060405234801561001057600080fd5b50600436106101735760003560e01c8063715018a6116100de578063a76b4d5611610097578063dc9716eb11610071578063dc9716eb146102f8578063dd62ed3e14610300578063e8a3d48514610339578063f2fde38b1461034157600080fd5b8063a76b4d56146102ca578063a9059cbb146102d2578063d505accf146102e557600080fd5b8063715018a61461025e57806379cc6790146102665780637ecebe001461027957806384b0196e1461028c5780638da5cb5b146102a757806395d89b41146102c257600080fd5b8063313ce56711610130578063313ce567146101ee5780633644e515146101fd5780633fd4d4a81461020557806340c10f191461020d57806342966c681461022257806370a082311461023557600080fd5b806306fdde0314610178578063095ea7b3146101965780630cd9acb7146101b9578063120a88ad146101c157806318160ddd146101c957806323b872dd146101db575b600080fd5b610180610354565b60405161018d9190610fe8565b60405180910390f35b6101a96101a436600461101e565b6103e6565b604051901515815260200161018d565b610180610400565b61018061048e565b6002545b60405190815260200161018d565b6101a96101e9366004611048565b61049d565b6040516012815260200161018d565b6101cd6104c1565b6101806104d0565b61022061021b36600461101e565b6104df565b005b610220610230366004611084565b6104f5565b6101cd61024336600461109d565b6001600160a01b031660009081526020819052604090205490565b610220610502565b61022061027436600461101e565b610516565b6101cd61028736600461109d565b61052b565b610294610549565b60405161018d97969594939291906110b8565b6005546040516001600160a01b03909116815260200161018d565b61018061058f565b61018061059e565b6101a96102e036600461101e565b6105ab565b6102206102f3366004611151565b6105b9565b6101806106f8565b6101cd61030e3660046111c4565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b610180610705565b61022061034f36600461109d565b610714565b606060038054610363906111f7565b80601f016020809104026020016040519081016040528092919081815260200182805461038f906111f7565b80156103dc5780601f106103b1576101008083540402835291602001916103dc565b820191906000526020600020905b8154815290600101906020018083116103bf57829003601f168201915b5050505050905090565b6000336103f481858561074f565b60019150505b92915050565b6009805461040d906111f7565b80601f0160208091040260200160405190810160405280929190818152602001828054610439906111f7565b80156104865780601f1061045b57610100808354040283529160200191610486565b820191906000526020600020905b81548152906001019060200180831161046957829003601f168201915b505050505081565b606060098054610363906111f7565b6000336104ab858285610761565b6104b68585856107df565b506001949350505050565b60006104cb61083e565b905090565b6060600a8054610363906111f7565b6104e7610969565b6104f18282610996565b5050565b6104ff33826109cc565b50565b61050a610969565b6105146000610a02565b565b610521823383610761565b6104f182826109cc565b6001600160a01b0381166000908152600860205260408120546103fa565b60006060806000806000606061055d610a54565b610565610a81565b60408051600080825260208201909252600f60f81b9b939a50919850469750309650945092509050565b606060048054610363906111f7565b600b805461040d906111f7565b6000336103f48185856107df565b834211156105e25760405163313c898160e11b8152600481018590526024015b60405180910390fd5b60007f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c988888861062f8c6001600160a01b0316600090815260086020526040902080546001810190915590565b6040805160208101969096526001600160a01b0394851690860152929091166060840152608083015260a082015260c0810186905260e001604051602081830303815290604052805190602001209050600061068a82610aae565b9050600061069a82878787610adb565b9050896001600160a01b0316816001600160a01b0316146106e1576040516325c0072360e11b81526001600160a01b0380831660048301528b1660248201526044016105d9565b6106ec8a8a8a61074f565b50505050505050505050565b600a805461040d906111f7565b6060600b8054610363906111f7565b61071c610969565b6001600160a01b03811661074657604051631e4fbdf760e01b8152600060048201526024016105d9565b6104ff81610a02565b61075c8383836001610b09565b505050565b6001600160a01b0383811660009081526001602090815260408083209386168352929052205460001981146107d957818110156107ca57604051637dc7a0d960e11b81526001600160a01b038416600482015260248101829052604481018390526064016105d9565b6107d984848484036000610b09565b50505050565b6001600160a01b03831661080957604051634b637e8f60e11b8152600060048201526024016105d9565b6001600160a01b0382166108335760405163ec442f0560e01b8152600060048201526024016105d9565b61075c838383610bde565b6000306001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614801561089757507f000000000000000000000000000000000000000000000000000000000000000046145b156108c157507f000000000000000000000000000000000000000000000000000000000000000090565b6104cb604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201527f0000000000000000000000000000000000000000000000000000000000000000918101919091527f000000000000000000000000000000000000000000000000000000000000000060608201524660808201523060a082015260009060c00160405160208183030381529060405280519060200120905090565b6005546001600160a01b031633146105145760405163118cdaa760e01b81523360048201526024016105d9565b6001600160a01b0382166109c05760405163ec442f0560e01b8152600060048201526024016105d9565b6104f160008383610bde565b6001600160a01b0382166109f657604051634b637e8f60e11b8152600060048201526024016105d9565b6104f182600083610bde565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b60606104cb7f00000000000000000000000000000000000000000000000000000000000000006006610d08565b60606104cb7f00000000000000000000000000000000000000000000000000000000000000006007610d08565b60006103fa610abb61083e565b8360405161190160f01b8152600281019290925260228201526042902090565b600080600080610aed88888888610db3565b925092509250610afd8282610e82565b50909695505050505050565b6001600160a01b038416610b335760405163e602df0560e01b8152600060048201526024016105d9565b6001600160a01b038316610b5d57604051634a1406b160e11b8152600060048201526024016105d9565b6001600160a01b03808516600090815260016020908152604080832093871683529290522082905580156107d957826001600160a01b0316846001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92584604051610bd091815260200190565b60405180910390a350505050565b6001600160a01b038316610c09578060026000828254610bfe9190611231565b90915550610c7b9050565b6001600160a01b03831660009081526020819052604090205481811015610c5c5760405163391434e360e21b81526001600160a01b038516600482015260248101829052604481018390526064016105d9565b6001600160a01b03841660009081526020819052604090209082900390555b6001600160a01b038216610c9757600280548290039055610cb6565b6001600160a01b03821660009081526020819052604090208054820190555b816001600160a01b0316836001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef83604051610cfb91815260200190565b60405180910390a3505050565b606060ff8314610d2257610d1b83610f3b565b90506103fa565b818054610d2e906111f7565b80601f0160208091040260200160405190810160405280929190818152602001828054610d5a906111f7565b8015610da75780601f10610d7c57610100808354040283529160200191610da7565b820191906000526020600020905b815481529060010190602001808311610d8a57829003601f168201915b505050505090506103fa565b600080807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0841115610dee5750600091506003905082610e78565b604080516000808252602082018084528a905260ff891692820192909252606081018790526080810186905260019060a0016020604051602081039080840390855afa158015610e42573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116610e6e57506000925060019150829050610e78565b9250600091508190505b9450945094915050565b6000826003811115610e9657610e96611252565b03610e9f575050565b6001826003811115610eb357610eb3611252565b03610ed15760405163f645eedf60e01b815260040160405180910390fd5b6002826003811115610ee557610ee5611252565b03610f065760405163fce698f760e01b8152600481018290526024016105d9565b6003826003811115610f1a57610f1a611252565b036104f1576040516335e2f38360e21b8152600481018290526024016105d9565b60606000610f4883610f7a565b604080516020808252818301909252919250600091906020820181803683375050509182525060208101929092525090565b600060ff8216601f8111156103fa57604051632cd44ac360e21b815260040160405180910390fd5b6000815180845260005b81811015610fc857602081850181015186830182015201610fac565b506000602082860101526020601f19601f83011685010191505092915050565b602081526000610ffb6020830184610fa2565b9392505050565b80356001600160a01b038116811461101957600080fd5b919050565b6000806040838503121561103157600080fd5b61103a83611002565b946020939093013593505050565b60008060006060848603121561105d57600080fd5b61106684611002565b925061107460208501611002565b9150604084013590509250925092565b60006020828403121561109657600080fd5b5035919050565b6000602082840312156110af57600080fd5b610ffb82611002565b60ff60f81b881681526000602060e060208401526110d960e084018a610fa2565b83810360408501526110eb818a610fa2565b606085018990526001600160a01b038816608086015260a0850187905284810360c08601528551808252602080880193509091019060005b8181101561113f57835183529284019291840191600101611123565b50909c9b505050505050505050505050565b600080600080600080600060e0888a03121561116c57600080fd5b61117588611002565b965061118360208901611002565b95506040880135945060608801359350608088013560ff811681146111a757600080fd5b9699959850939692959460a0840135945060c09093013592915050565b600080604083850312156111d757600080fd5b6111e083611002565b91506111ee60208401611002565b90509250929050565b600181811c9082168061120b57607f821691505b60208210810361122b57634e487b7160e01b600052602260045260246000fd5b50919050565b808201808211156103fa57634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052602160045260246000fdfea26469706673582212206fb41458119173f9f1d07720d0b22fbfacf4726505008b5c43816c9902cd0fc464736f6c63430008170033a26469706673582212201df4bdff78560cbe320524756593933725001e7f7f8e2f575636163e3d9cc87d64736f6c63430008170033" + }, + { + "type": "UInt64", + "value": "12000000" + }, + { + "type": "UFix64", + "value": "0.0" + } +] \ No newline at end of file diff --git a/cadence/args/deploy-erc721-deployer-args.json b/cadence/args/deploy-erc721-deployer-args.json new file mode 100644 index 00000000..7671744d --- /dev/null +++ b/cadence/args/deploy-erc721-deployer-args.json @@ -0,0 +1,14 @@ +[ + { + "type": "String", + "value": "608060405234801561001057600080fd5b50338061003757604051631e4fbdf760e01b81526000600482015260240160405180910390fd5b61004081610046565b50610096565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b612657806100a56000396000f3fe60806040523480156200001157600080fd5b5060043610620000875760003560e01c8063715018a61162000062578063715018a614620000fc5780638da5cb5b1462000108578063ee2d8496146200011a578063f2fde38b146200013157600080fd5b806301ffc9a7146200008c578063476d399714620000b85780636418e6de14620000e8575b600080fd5b620000a36200009d3660046200043c565b62000148565b60405190151581526020015b60405180910390f35b620000cf620000c93660046200051a565b62000180565b6040516001600160a01b039091168152602001620000af565b600154620000cf906001600160a01b031681565b62000106620002a7565b005b6000546001600160a01b0316620000cf565b620001066200012b366004620005fc565b620002bf565b6200010662000142366004620005fc565b6200036b565b60006001600160e01b0319821663476d399760e01b14806200017a57506301ffc9a760e01b6001600160e01b03198316145b92915050565b6001546000906001600160a01b031633146200020b576040805162461bcd60e51b81526020600482015260248101919091527f466c6f7745564d427269646765644552433732314465706c6f7965723a204f6e60448201527f6c792064656c656761746564206465706c6f7965722063616e206465706c6f7960648201526084015b60405180910390fd5b600080546001600160a01b031687878787876040516200022b906200042e565b6200023c969594939291906200066f565b604051809103906000f08015801562000259573d6000803e3d6000fd5b5090507fbebce54951ebf20c0dcd195a45bb2388d9ac8e38b5974e00bb63c5822dbe65f0818888888860405162000295959493929190620006f8565b60405180910390a19695505050505050565b620002b1620003af565b620002bd6000620003de565b565b620002c9620003af565b6001600160a01b03811662000349576040805162461bcd60e51b81526020600482015260248101919091527f466c6f7745564d427269646765644552433732314465706c6f7965723a20496e60448201527f76616c69642064656c656761746564206465706c6f7965722061646472657373606482015260840162000202565b600180546001600160a01b0319166001600160a01b0392909216919091179055565b62000375620003af565b6001600160a01b038116620003a157604051631e4fbdf760e01b81526000600482015260240162000202565b620003ac81620003de565b50565b6000546001600160a01b03163314620002bd5760405163118cdaa760e01b815233600482015260240162000202565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b611eb7806200076b83390190565b6000602082840312156200044f57600080fd5b81356001600160e01b0319811681146200046857600080fd5b9392505050565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126200049757600080fd5b813567ffffffffffffffff80821115620004b557620004b56200046f565b604051601f8301601f19908116603f01168101908282118183101715620004e057620004e06200046f565b81604052838152866020858801011115620004fa57600080fd5b836020870160208301376000602085830101528094505050505092915050565b600080600080600060a086880312156200053357600080fd5b853567ffffffffffffffff808211156200054c57600080fd5b6200055a89838a0162000485565b965060208801359150808211156200057157600080fd5b6200057f89838a0162000485565b955060408801359150808211156200059657600080fd5b620005a489838a0162000485565b94506060880135915080821115620005bb57600080fd5b620005c989838a0162000485565b93506080880135915080821115620005e057600080fd5b50620005ef8882890162000485565b9150509295509295909350565b6000602082840312156200060f57600080fd5b81356001600160a01b03811681146200046857600080fd5b6000815180845260005b818110156200064f5760208185018101518683018201520162000631565b506000602082860101526020601f19601f83011685010191505092915050565b6001600160a01b038716815260c060208201819052600090620006959083018862000627565b8281036040840152620006a9818862000627565b90508281036060840152620006bf818762000627565b90508281036080840152620006d5818662000627565b905082810360a0840152620006eb818562000627565b9998505050505050505050565b6001600160a01b038616815260a0602082018190526000906200071e9083018762000627565b828103604084015262000732818762000627565b9050828103606084015262000748818662000627565b905082810360808401526200075e818562000627565b9897505050505050505056fe60806040523480156200001157600080fd5b5060405162001eb738038062001eb7833981016040819052620000349162000202565b858585600062000045838262000386565b50600162000054828262000386565b5050506001600160a01b0381166200008657604051631e4fbdf760e01b81526000600482015260240160405180910390fd5b6200009181620000cb565b50600c620000a0848262000386565b50600d620000af838262000386565b50600e620000be828262000386565b5050505050505062000452565b600b80546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b80516001600160a01b03811681146200013557600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126200016257600080fd5b81516001600160401b03808211156200017f576200017f6200013a565b604051601f8301601f19908116603f01168101908282118183101715620001aa57620001aa6200013a565b8160405283815260209250866020858801011115620001c857600080fd5b600091505b83821015620001ec5785820183015181830184015290820190620001cd565b6000602085830101528094505050505092915050565b60008060008060008060c087890312156200021c57600080fd5b62000227876200011d565b60208801519096506001600160401b03808211156200024557600080fd5b620002538a838b0162000150565b965060408901519150808211156200026a57600080fd5b620002788a838b0162000150565b955060608901519150808211156200028f57600080fd5b6200029d8a838b0162000150565b94506080890151915080821115620002b457600080fd5b620002c28a838b0162000150565b935060a0890151915080821115620002d957600080fd5b50620002e889828a0162000150565b9150509295509295509295565b600181811c908216806200030a57607f821691505b6020821081036200032b57634e487b7160e01b600052602260045260246000fd5b50919050565b601f82111562000381576000816000526020600020601f850160051c810160208610156200035c5750805b601f850160051c820191505b818110156200037d5782815560010162000368565b5050505b505050565b81516001600160401b03811115620003a257620003a26200013a565b620003ba81620003b38454620002f5565b8462000331565b602080601f831160018114620003f25760008415620003d95750858301515b600019600386901b1c1916600185901b1785556200037d565b600085815260208120601f198616915b82811015620004235788860151825594840194600190910190840162000402565b5085821015620004425787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b611a5580620004626000396000f3fe608060405234801561001057600080fd5b50600436106101cf5760003560e01c806370a0823111610104578063a76b4d56116100a2578063cd279c7c11610071578063cd279c7c146103a8578063e8a3d485146103bb578063e985e9c5146103c3578063f2fde38b146103d657600080fd5b8063a76b4d5614610372578063b49bbd941461037a578063b88d4fde14610382578063c87b56dd1461039557600080fd5b806394e29329116100de57806394e293291461034757806395d89b411461034f578063a159047b14610357578063a22cb4651461035f57600080fd5b806370a082311461031b578063715018a61461032e5780638da5cb5b1461033657600080fd5b80632f745c59116101715780634f558e791161014b5780634f558e79146102c25780634f6ccce7146102ed5780635e0a9661146103005780636352211e1461030857600080fd5b80632f745c591461028957806342842e0e1461029c57806342966c68146102af57600080fd5b8063095ea7b3116101ad578063095ea7b31461023c57806318160ddd1461025157806318e97fd11461026357806323b872dd1461027657600080fd5b806301ffc9a7146101d457806306fdde03146101fc578063081812fc14610211575b600080fd5b6101e76101e2366004611494565b6103e9565b60405190151581526020015b60405180910390f35b6102046103fa565b6040516101f39190611501565b61022461021f366004611514565b61048c565b6040516001600160a01b0390911681526020016101f3565b61024f61024a366004611549565b6104b5565b005b6009545b6040519081526020016101f3565b61024f61027136600461161f565b6104c4565b61024f610284366004611666565b6104d6565b610255610297366004611549565b610566565b61024f6102aa366004611666565b6105cb565b61024f6102bd366004611514565b6105eb565b6101e76102d0366004611514565b6000908152600260205260409020546001600160a01b0316151590565b6102556102fb366004611514565b6105f7565b610204610650565b610224610316366004611514565b61065f565b6102556103293660046116a2565b61066a565b61024f6106b2565b600b546001600160a01b0316610224565b6102046106c6565b6102046106d5565b6102046106e4565b61024f61036d3660046116bd565b610772565b61020461077d565b61020461078a565b61024f6103903660046116f9565b610797565b6102046103a3366004611514565b6107ae565b61024f6103b6366004611775565b6107b9565b6102046107d5565b6101e76103d13660046117cc565b6107e4565b61024f6103e43660046116a2565b610812565b60006103f482610850565b92915050565b606060008054610409906117ff565b80601f0160208091040260200160405190810160405280929190818152602001828054610435906117ff565b80156104825780601f1061045757610100808354040283529160200191610482565b820191906000526020600020905b81548152906001019060200180831161046557829003601f168201915b5050505050905090565b600061049782610875565b506000828152600460205260409020546001600160a01b03166103f4565b6104c08282336108ae565b5050565b6104cc6108bb565b6104c082826108e8565b6001600160a01b03821661050557604051633250574960e11b8152600060048201526024015b60405180910390fd5b6000610512838333610938565b9050836001600160a01b0316816001600160a01b031614610560576040516364283d7b60e01b81526001600160a01b03808616600483015260248201849052821660448201526064016104fc565b50505050565b60006105718361066a565b82106105a25760405163295f44f760e21b81526001600160a01b0384166004820152602481018390526044016104fc565b506001600160a01b03919091166000908152600760209081526040808320938352929052205490565b6105e683838360405180602001604052806000815250610797565b505050565b6104c060008233610938565b600061060260095490565b821061062b5760405163295f44f760e21b815260006004820152602481018390526044016104fc565b6009828154811061063e5761063e611839565b90600052602060002001549050919050565b6060600d8054610409906117ff565b60006103f482610875565b60006001600160a01b038216610696576040516322718ad960e21b8152600060048201526024016104fc565b506001600160a01b031660009081526003602052604090205490565b6106ba6108bb565b6106c4600061094d565b565b6060600c8054610409906117ff565b606060018054610409906117ff565b600d80546106f1906117ff565b80601f016020809104026020016040519081016040528092919081815260200182805461071d906117ff565b801561076a5780601f1061073f5761010080835404028352916020019161076a565b820191906000526020600020905b81548152906001019060200180831161074d57829003601f168201915b505050505081565b6104c033838361099f565b600e80546106f1906117ff565b600c80546106f1906117ff565b6107a28484846104d6565b61056084848484610a3e565b60606103f482610b67565b6107c16108bb565b6107cb8383610c70565b6105e682826108e8565b6060600e8054610409906117ff565b6001600160a01b03918216600090815260056020908152604080832093909416825291909152205460ff1690565b61081a6108bb565b6001600160a01b03811661084457604051631e4fbdf760e01b8152600060048201526024016104fc565b61084d8161094d565b50565b60006001600160e01b0319821663780e9d6360e01b14806103f457506103f482610c8a565b6000818152600260205260408120546001600160a01b0316806103f457604051637e27328960e01b8152600481018490526024016104fc565b6105e68383836001610caf565b600b546001600160a01b031633146106c45760405163118cdaa760e01b81523360048201526024016104fc565b6000828152600660205260409020610900828261189f565b506040518281527ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79060200160405180910390a15050565b6000610945848484610db5565b949350505050565b600b80546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6001600160a01b0382166109d157604051630b61174360e31b81526001600160a01b03831660048201526024016104fc565b6001600160a01b03838116600081815260056020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b6001600160a01b0383163b1561056057604051630a85bd0160e11b81526001600160a01b0384169063150b7a0290610a8090339088908790879060040161195f565b6020604051808303816000875af1925050508015610abb575060408051601f3d908101601f19168201909252610ab89181019061199c565b60015b610b24573d808015610ae9576040519150601f19603f3d011682016040523d82523d6000602084013e610aee565b606091505b508051600003610b1c57604051633250574960e11b81526001600160a01b03851660048201526024016104fc565b805181602001fd5b6001600160e01b03198116630a85bd0160e11b14610b6057604051633250574960e11b81526001600160a01b03851660048201526024016104fc565b5050505050565b6060610b7282610875565b5060008281526006602052604081208054610b8c906117ff565b80601f0160208091040260200160405190810160405280929190818152602001828054610bb8906117ff565b8015610c055780601f10610bda57610100808354040283529160200191610c05565b820191906000526020600020905b815481529060010190602001808311610be857829003601f168201915b505050505090506000610c2360408051602081019091526000815290565b90508051600003610c35575092915050565b815115610c67578082604051602001610c4f9291906119b9565b60405160208183030381529060405292505050919050565b61094584610e82565b6104c0828260405180602001604052806000815250610ef7565b60006001600160e01b03198216632483248360e11b14806103f457506103f482610f0e565b8080610cc357506001600160a01b03821615155b15610d85576000610cd384610875565b90506001600160a01b03831615801590610cff5750826001600160a01b0316816001600160a01b031614155b8015610d125750610d1081846107e4565b155b15610d3b5760405163a9fbf51f60e01b81526001600160a01b03841660048201526024016104fc565b8115610d835783856001600160a01b0316826001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45b505b5050600090815260046020526040902080546001600160a01b0319166001600160a01b0392909216919091179055565b600080610dc3858585610f5e565b90506001600160a01b038116610e2057610e1b84600980546000838152600a60205260408120829055600182018355919091527f6e1540171b6c0c960b71a7020d9f60077f6af931a8bbf590da0223dacf75c7af0155565b610e43565b846001600160a01b0316816001600160a01b031614610e4357610e438185611057565b6001600160a01b038516610e5f57610e5a846110e8565b610945565b846001600160a01b0316816001600160a01b031614610945576109458585611197565b6060610e8d82610875565b506000610ea560408051602081019091526000815290565b90506000815111610ec55760405180602001604052806000815250610ef0565b80610ecf846111e7565b604051602001610ee09291906119b9565b6040516020818303038152906040525b9392505050565b610f01838361127a565b6105e66000848484610a3e565b60006001600160e01b031982166380ac58cd60e01b1480610f3f57506001600160e01b03198216635b5e139f60e01b145b806103f457506301ffc9a760e01b6001600160e01b03198316146103f4565b6000828152600260205260408120546001600160a01b0390811690831615610f8b57610f8b8184866112df565b6001600160a01b03811615610fc957610fa8600085600080610caf565b6001600160a01b038116600090815260036020526040902080546000190190555b6001600160a01b03851615610ff8576001600160a01b0385166000908152600360205260409020805460010190555b60008481526002602052604080822080546001600160a01b0319166001600160a01b0389811691821790925591518793918516917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4949350505050565b60006110628361066a565b6000838152600860205260409020549091508082146110b5576001600160a01b03841660009081526007602090815260408083208584528252808320548484528184208190558352600890915290208190555b5060009182526008602090815260408084208490556001600160a01b039094168352600781528383209183525290812055565b6009546000906110fa906001906119e8565b6000838152600a60205260408120546009805493945090928490811061112257611122611839565b90600052602060002001549050806009838154811061114357611143611839565b6000918252602080832090910192909255828152600a9091526040808220849055858252812055600980548061117b5761117b611a09565b6001900381819060005260206000200160009055905550505050565b600060016111a48461066a565b6111ae91906119e8565b6001600160a01b039093166000908152600760209081526040808320868452825280832085905593825260089052919091209190915550565b606060006111f483611343565b600101905060008167ffffffffffffffff81111561121457611214611573565b6040519080825280601f01601f19166020018201604052801561123e576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a850494508461124857509392505050565b6001600160a01b0382166112a457604051633250574960e11b8152600060048201526024016104fc565b60006112b283836000610938565b90506001600160a01b038116156105e6576040516339e3563760e11b8152600060048201526024016104fc565b6112ea83838361141b565b6105e6576001600160a01b03831661131857604051637e27328960e01b8152600481018290526024016104fc565b60405163177e802f60e01b81526001600160a01b0383166004820152602481018290526044016104fc565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b83106113825772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef810000000083106113ae576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc1000083106113cc57662386f26fc10000830492506010015b6305f5e10083106113e4576305f5e100830492506008015b61271083106113f857612710830492506004015b6064831061140a576064830492506002015b600a83106103f45760010192915050565b60006001600160a01b038316158015906109455750826001600160a01b0316846001600160a01b03161480611455575061145584846107e4565b806109455750506000908152600460205260409020546001600160a01b03908116911614919050565b6001600160e01b03198116811461084d57600080fd5b6000602082840312156114a657600080fd5b8135610ef08161147e565b60005b838110156114cc5781810151838201526020016114b4565b50506000910152565b600081518084526114ed8160208601602086016114b1565b601f01601f19169290920160200192915050565b602081526000610ef060208301846114d5565b60006020828403121561152657600080fd5b5035919050565b80356001600160a01b038116811461154457600080fd5b919050565b6000806040838503121561155c57600080fd5b6115658361152d565b946020939093013593505050565b634e487b7160e01b600052604160045260246000fd5b600067ffffffffffffffff808411156115a4576115a4611573565b604051601f8501601f19908116603f011681019082821181831017156115cc576115cc611573565b816040528093508581528686860111156115e557600080fd5b858560208301376000602087830101525050509392505050565b600082601f83011261161057600080fd5b610ef083833560208501611589565b6000806040838503121561163257600080fd5b82359150602083013567ffffffffffffffff81111561165057600080fd5b61165c858286016115ff565b9150509250929050565b60008060006060848603121561167b57600080fd5b6116848461152d565b92506116926020850161152d565b9150604084013590509250925092565b6000602082840312156116b457600080fd5b610ef08261152d565b600080604083850312156116d057600080fd5b6116d98361152d565b9150602083013580151581146116ee57600080fd5b809150509250929050565b6000806000806080858703121561170f57600080fd5b6117188561152d565b93506117266020860161152d565b925060408501359150606085013567ffffffffffffffff81111561174957600080fd5b8501601f8101871361175a57600080fd5b61176987823560208401611589565b91505092959194509250565b60008060006060848603121561178a57600080fd5b6117938461152d565b925060208401359150604084013567ffffffffffffffff8111156117b657600080fd5b6117c2868287016115ff565b9150509250925092565b600080604083850312156117df57600080fd5b6117e88361152d565b91506117f66020840161152d565b90509250929050565b600181811c9082168061181357607f821691505b60208210810361183357634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052603260045260246000fd5b601f8211156105e6576000816000526020600020601f850160051c810160208610156118785750805b601f850160051c820191505b8181101561189757828155600101611884565b505050505050565b815167ffffffffffffffff8111156118b9576118b9611573565b6118cd816118c784546117ff565b8461184f565b602080601f83116001811461190257600084156118ea5750858301515b600019600386901b1c1916600185901b178555611897565b600085815260208120601f198616915b8281101561193157888601518255948401946001909101908401611912565b508582101561194f5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6001600160a01b0385811682528416602082015260408101839052608060608201819052600090611992908301846114d5565b9695505050505050565b6000602082840312156119ae57600080fd5b8151610ef08161147e565b600083516119cb8184602088016114b1565b8351908301906119df8183602088016114b1565b01949350505050565b818103818111156103f457634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052603160045260246000fdfea264697066735822122074d34aec07c0da793ce5cac74069bf4177b7594babf4fede87db849ea2f57b3764736f6c63430008170033a2646970667358221220953493586f5fb5670e80849013b6c27540a3f06c628c3046b81886afa405e0c664736f6c63430008170033" + }, + { + "type": "UInt64", + "value": "12000000" + }, + { + "type": "UFix64", + "value": "0.0" + } +] \ No newline at end of file diff --git a/cadence/args/deploy-factory-args.json b/cadence/args/deploy-factory-args.json index bee7f760..512e101b 100644 --- a/cadence/args/deploy-factory-args.json +++ b/cadence/args/deploy-factory-args.json @@ -1,7 +1,7 @@ [ { "type": "String", - "value": "608060405234801561001057600080fd5b50338061003757604051631e4fbdf760e01b81526000600482015260240160405180910390fd5b61004081610046565b50610096565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b61484a806100a56000396000f3fe60806040523480156200001157600080fd5b5060043610620000c35760003560e01c8063715018a6116200007a578063715018a6146200018f5780638da5cb5b146200019b578063d56e0ccf14620001ad578063daa09e5414620001e4578063f2fde38b14620001fb578063f93241dd146200021257600080fd5b806304433bbc14620000c85780630a2c0ce914620000fc578063263e0c1b1462000122578063335f4c76146200014a57806340f8d42b146200016157806361a169051462000178575b600080fd5b620000df620000d936600462000c0a565b62000229565b6040516001600160a01b0390911681526020015b60405180910390f35b620001136200010d36600462000c4b565b6200025c565b604051620000f3919062000cd1565b620001396200013336600462000c4b565b62000310565b6040519015158152602001620000f3565b620001396200015b36600462000c4b565b62000724565b620000df6200017236600462000ce6565b62000752565b620000df6200018936600462000ce6565b62000853565b6200019962000942565b005b6000546001600160a01b0316620000df565b620000df620001be36600462000c0a565b80516020818301810180516001825292820191909301209152546001600160a01b031681565b62000139620001f536600462000c4b565b6200095a565b620001996200020c36600462000c4b565b620009da565b620001136200022336600462000c4b565b62000a22565b60006001826040516200023d919062000dc8565b908152604051908190036020019020546001600160a01b031692915050565b6001600160a01b0381166000908152600260205260409020805460609190620002859062000de6565b80601f0160208091040260200160405190810160405280929190818152602001828054620002b39062000de6565b8015620003045780601f10620002d85761010080835404028352916020019162000304565b820191906000526020600020905b815481529060010190602001808311620002e657829003601f168201915b50505050509050919050565b60408051600481526024810182526020810180516001600160e01b03166318160ddd60e01b1790529051600091829182916001600160a01b0386169162000358919062000dc8565b600060405180830381855afa9150503d806000811462000395576040519150601f19603f3d011682016040523d82523d6000602084013e6200039a565b606091505b5091509150811580620003ac57508051155b15620003bc575060009392505050565b604051600060248201526001600160a01b0385169060440160408051601f198184030181529181526020820180516001600160e01b03166370a0823160e01b179052516200040b919062000dc8565b600060405180830381855afa9150503d806000811462000448576040519150601f19603f3d011682016040523d82523d6000602084013e6200044d565b606091505b5090925090508115806200046057508051155b1562000470575060009392505050565b60405160006024820181905260448201526001600160a01b0385169060640160408051601f198184030181529181526020820180516001600160e01b0316636eb1769f60e11b17905251620004c6919062000dc8565b600060405180830381855afa9150503d806000811462000503576040519150601f19603f3d011682016040523d82523d6000602084013e62000508565b606091505b5090925090508115806200051b57508051155b156200052b575060009392505050565b60408051600481526024810182526020810180516001600160e01b03166306fdde0360e01b17905290516001600160a01b038616916200056b9162000dc8565b600060405180830381855afa9150503d8060008114620005a8576040519150601f19603f3d011682016040523d82523d6000602084013e620005ad565b606091505b509092509050811580620005c057508051155b15620005d0575060009392505050565b60408051600481526024810182526020810180516001600160e01b03166395d89b4160e01b17905290516001600160a01b03861691620006109162000dc8565b600060405180830381855afa9150503d80600081146200064d576040519150601f19603f3d011682016040523d82523d6000602084013e62000652565b606091505b5090925090508115806200066557508051155b1562000675575060009392505050565b60408051600481526024810182526020810180516001600160e01b031663313ce56760e01b17905290516001600160a01b03861691620006b59162000dc8565b600060405180830381855afa9150503d8060008114620006f2576040519150601f19603f3d011682016040523d82523d6000602084013e620006f7565b606091505b5090925090508115806200070a57508051155b156200071a575060009392505050565b5060019392505050565b6001600160a01b03811660009081526002602052604081208054620007499062000de6565b15159392505050565b60006200075e62000ac4565b600080546001600160a01b031687878787876040516200077e9062000b43565b6200078f9695949392919062000e22565b604051809103906000f080158015620007ac573d6000803e3d6000fd5b50905080600185604051620007c2919062000dc8565b908152604080516020928190038301902080546001600160a01b0319166001600160a01b03948516179055918316600090815260029091522062000807858262000f00565b507f99a64021330f1af36b3fd5f64a1d12b99b8ddf91fa553618c4df01ffba4c1cee81888888886040516200084195949392919062000fcd565b60405180910390a19695505050505050565b60006200085f62000ac4565b600080546001600160a01b031687878787876040516200087f9062000b51565b620008909695949392919062000e22565b604051809103906000f080158015620008ad573d6000803e3d6000fd5b50905080600185604051620008c3919062000dc8565b908152604080516020928190038301902080546001600160a01b0319166001600160a01b03948516179055918316600090815260029091522062000908858262000f00565b507fbebce54951ebf20c0dcd195a45bb2388d9ac8e38b5974e00bb63c5822dbe65f081888888886040516200084195949392919062000fcd565b6200094c62000ac4565b62000958600062000af3565b565b6040516301ffc9a760e01b81526380ac58cd60e01b60048201526000906001600160a01b038316906301ffc9a790602401602060405180830381865afa925050508015620009c7575060408051601f3d908101601f19168201909252620009c4918101906200103f565b60015b620009d457506000919050565b92915050565b620009e462000ac4565b6001600160a01b03811662000a1457604051631e4fbdf760e01b8152600060048201526024015b60405180910390fd5b62000a1f8162000af3565b50565b6002602052600090815260409020805462000a3d9062000de6565b80601f016020809104026020016040519081016040528092919081815260200182805462000a6b9062000de6565b801562000abc5780601f1062000a905761010080835404028352916020019162000abc565b820191906000526020600020905b81548152906001019060200180831162000a9e57829003601f168201915b505050505081565b6000546001600160a01b03163314620009585760405163118cdaa760e01b815233600482015260240162000a0b565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6118fa806200106483390190565b611eb7806200295e83390190565b634e487b7160e01b600052604160045260246000fd5b600082601f83011262000b8757600080fd5b813567ffffffffffffffff8082111562000ba55762000ba562000b5f565b604051601f8301601f19908116603f0116810190828211818310171562000bd05762000bd062000b5f565b8160405283815286602085880101111562000bea57600080fd5b836020870160208301376000602085830101528094505050505092915050565b60006020828403121562000c1d57600080fd5b813567ffffffffffffffff81111562000c3557600080fd5b62000c438482850162000b75565b949350505050565b60006020828403121562000c5e57600080fd5b81356001600160a01b038116811462000c7657600080fd5b9392505050565b60005b8381101562000c9a57818101518382015260200162000c80565b50506000910152565b6000815180845262000cbd81602086016020860162000c7d565b601f01601f19169290920160200192915050565b60208152600062000c76602083018462000ca3565b600080600080600060a0868803121562000cff57600080fd5b853567ffffffffffffffff8082111562000d1857600080fd5b62000d2689838a0162000b75565b9650602088013591508082111562000d3d57600080fd5b62000d4b89838a0162000b75565b9550604088013591508082111562000d6257600080fd5b62000d7089838a0162000b75565b9450606088013591508082111562000d8757600080fd5b62000d9589838a0162000b75565b9350608088013591508082111562000dac57600080fd5b5062000dbb8882890162000b75565b9150509295509295909350565b6000825162000ddc81846020870162000c7d565b9190910192915050565b600181811c9082168062000dfb57607f821691505b60208210810362000e1c57634e487b7160e01b600052602260045260246000fd5b50919050565b6001600160a01b038716815260c06020820181905260009062000e489083018862000ca3565b828103604084015262000e5c818862000ca3565b9050828103606084015262000e72818762000ca3565b9050828103608084015262000e88818662000ca3565b905082810360a084015262000e9e818562000ca3565b9998505050505050505050565b601f82111562000efb576000816000526020600020601f850160051c8101602086101562000ed65750805b601f850160051c820191505b8181101562000ef75782815560010162000ee2565b5050505b505050565b815167ffffffffffffffff81111562000f1d5762000f1d62000b5f565b62000f358162000f2e845462000de6565b8462000eab565b602080601f83116001811462000f6d576000841562000f545750858301515b600019600386901b1c1916600185901b17855562000ef7565b600085815260208120601f198616915b8281101562000f9e5788860151825594840194600190910190840162000f7d565b508582101562000fbd5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6001600160a01b038616815260a06020820181905260009062000ff39083018762000ca3565b828103604084015262001007818762000ca3565b905082810360608401526200101d818662000ca3565b9050828103608084015262001033818562000ca3565b98975050505050505050565b6000602082840312156200105257600080fd5b8151801515811462000c7657600080fdfe6101606040523480156200001257600080fd5b50604051620018fa380380620018fa833981016040819052620000359162000357565b6040805180820190915260018152603160f81b6020820152859081908882886003620000628382620004db565b506004620000718282620004db565b5050506001600160a01b038116620000a457604051631e4fbdf760e01b8152600060048201526024015b60405180910390fd5b620000af816200019f565b50620000bd826006620001f1565b61012052620000ce816007620001f1565b61014052815160208084019190912060e052815190820120610100524660a0526200015c60e05161010051604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201529081019290925260608201524660808201523060a082015260009060c00160405160208183030381529060405280519060200120905090565b60805250503060c052506009620001748482620004db565b50600a620001838382620004db565b50600b620001928282620004db565b5050505050505062000601565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6000602083511015620002115762000209836200022a565b905062000224565b816200021e8482620004db565b5060ff90505b92915050565b600080829050601f8151111562000258578260405163305a27a960e01b81526004016200009b9190620005a7565b80516200026582620005dc565b179392505050565b80516001600160a01b03811681146200028557600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60005b83811015620002bd578181015183820152602001620002a3565b50506000910152565b600082601f830112620002d857600080fd5b81516001600160401b0380821115620002f557620002f56200028a565b604051601f8301601f19908116603f011681019082821181831017156200032057620003206200028a565b816040528381528660208588010111156200033a57600080fd5b6200034d846020830160208901620002a0565b9695505050505050565b60008060008060008060c087890312156200037157600080fd5b6200037c876200026d565b60208801519096506001600160401b03808211156200039a57600080fd5b620003a88a838b01620002c6565b96506040890151915080821115620003bf57600080fd5b620003cd8a838b01620002c6565b95506060890151915080821115620003e457600080fd5b620003f28a838b01620002c6565b945060808901519150808211156200040957600080fd5b620004178a838b01620002c6565b935060a08901519150808211156200042e57600080fd5b506200043d89828a01620002c6565b9150509295509295509295565b600181811c908216806200045f57607f821691505b6020821081036200048057634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115620004d6576000816000526020600020601f850160051c81016020861015620004b15750805b601f850160051c820191505b81811015620004d257828155600101620004bd565b5050505b505050565b81516001600160401b03811115620004f757620004f76200028a565b6200050f816200050884546200044a565b8462000486565b602080601f8311600181146200054757600084156200052e5750858301515b600019600386901b1c1916600185901b178555620004d2565b600085815260208120601f198616915b82811015620005785788860151825594840194600190910190840162000557565b5085821015620005975787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6020815260008251806020840152620005c8816040850160208701620002a0565b601f01601f19169190910160400192915050565b80516020808301519190811015620004805760001960209190910360031b1b16919050565b60805160a05160c05160e05161010051610120516101405161129e6200065c6000396000610a8801526000610a5b01526000610918015260006108f00152600061084b015260006108750152600061089f015261129e6000f3fe608060405234801561001057600080fd5b50600436106101735760003560e01c8063715018a6116100de578063a76b4d5611610097578063dc9716eb11610071578063dc9716eb146102f8578063dd62ed3e14610300578063e8a3d48514610339578063f2fde38b1461034157600080fd5b8063a76b4d56146102ca578063a9059cbb146102d2578063d505accf146102e557600080fd5b8063715018a61461025e57806379cc6790146102665780637ecebe001461027957806384b0196e1461028c5780638da5cb5b146102a757806395d89b41146102c257600080fd5b8063313ce56711610130578063313ce567146101ee5780633644e515146101fd5780633fd4d4a81461020557806340c10f191461020d57806342966c681461022257806370a082311461023557600080fd5b806306fdde0314610178578063095ea7b3146101965780630cd9acb7146101b9578063120a88ad146101c157806318160ddd146101c957806323b872dd146101db575b600080fd5b610180610354565b60405161018d9190610fe8565b60405180910390f35b6101a96101a436600461101e565b6103e6565b604051901515815260200161018d565b610180610400565b61018061048e565b6002545b60405190815260200161018d565b6101a96101e9366004611048565b61049d565b6040516012815260200161018d565b6101cd6104c1565b6101806104d0565b61022061021b36600461101e565b6104df565b005b610220610230366004611084565b6104f5565b6101cd61024336600461109d565b6001600160a01b031660009081526020819052604090205490565b610220610502565b61022061027436600461101e565b610516565b6101cd61028736600461109d565b61052b565b610294610549565b60405161018d97969594939291906110b8565b6005546040516001600160a01b03909116815260200161018d565b61018061058f565b61018061059e565b6101a96102e036600461101e565b6105ab565b6102206102f3366004611151565b6105b9565b6101806106f8565b6101cd61030e3660046111c4565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b610180610705565b61022061034f36600461109d565b610714565b606060038054610363906111f7565b80601f016020809104026020016040519081016040528092919081815260200182805461038f906111f7565b80156103dc5780601f106103b1576101008083540402835291602001916103dc565b820191906000526020600020905b8154815290600101906020018083116103bf57829003601f168201915b5050505050905090565b6000336103f481858561074f565b60019150505b92915050565b6009805461040d906111f7565b80601f0160208091040260200160405190810160405280929190818152602001828054610439906111f7565b80156104865780601f1061045b57610100808354040283529160200191610486565b820191906000526020600020905b81548152906001019060200180831161046957829003601f168201915b505050505081565b606060098054610363906111f7565b6000336104ab858285610761565b6104b68585856107df565b506001949350505050565b60006104cb61083e565b905090565b6060600a8054610363906111f7565b6104e7610969565b6104f18282610996565b5050565b6104ff33826109cc565b50565b61050a610969565b6105146000610a02565b565b610521823383610761565b6104f182826109cc565b6001600160a01b0381166000908152600860205260408120546103fa565b60006060806000806000606061055d610a54565b610565610a81565b60408051600080825260208201909252600f60f81b9b939a50919850469750309650945092509050565b606060048054610363906111f7565b600b805461040d906111f7565b6000336103f48185856107df565b834211156105e25760405163313c898160e11b8152600481018590526024015b60405180910390fd5b60007f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c988888861062f8c6001600160a01b0316600090815260086020526040902080546001810190915590565b6040805160208101969096526001600160a01b0394851690860152929091166060840152608083015260a082015260c0810186905260e001604051602081830303815290604052805190602001209050600061068a82610aae565b9050600061069a82878787610adb565b9050896001600160a01b0316816001600160a01b0316146106e1576040516325c0072360e11b81526001600160a01b0380831660048301528b1660248201526044016105d9565b6106ec8a8a8a61074f565b50505050505050505050565b600a805461040d906111f7565b6060600b8054610363906111f7565b61071c610969565b6001600160a01b03811661074657604051631e4fbdf760e01b8152600060048201526024016105d9565b6104ff81610a02565b61075c8383836001610b09565b505050565b6001600160a01b0383811660009081526001602090815260408083209386168352929052205460001981146107d957818110156107ca57604051637dc7a0d960e11b81526001600160a01b038416600482015260248101829052604481018390526064016105d9565b6107d984848484036000610b09565b50505050565b6001600160a01b03831661080957604051634b637e8f60e11b8152600060048201526024016105d9565b6001600160a01b0382166108335760405163ec442f0560e01b8152600060048201526024016105d9565b61075c838383610bde565b6000306001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614801561089757507f000000000000000000000000000000000000000000000000000000000000000046145b156108c157507f000000000000000000000000000000000000000000000000000000000000000090565b6104cb604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201527f0000000000000000000000000000000000000000000000000000000000000000918101919091527f000000000000000000000000000000000000000000000000000000000000000060608201524660808201523060a082015260009060c00160405160208183030381529060405280519060200120905090565b6005546001600160a01b031633146105145760405163118cdaa760e01b81523360048201526024016105d9565b6001600160a01b0382166109c05760405163ec442f0560e01b8152600060048201526024016105d9565b6104f160008383610bde565b6001600160a01b0382166109f657604051634b637e8f60e11b8152600060048201526024016105d9565b6104f182600083610bde565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b60606104cb7f00000000000000000000000000000000000000000000000000000000000000006006610d08565b60606104cb7f00000000000000000000000000000000000000000000000000000000000000006007610d08565b60006103fa610abb61083e565b8360405161190160f01b8152600281019290925260228201526042902090565b600080600080610aed88888888610db3565b925092509250610afd8282610e82565b50909695505050505050565b6001600160a01b038416610b335760405163e602df0560e01b8152600060048201526024016105d9565b6001600160a01b038316610b5d57604051634a1406b160e11b8152600060048201526024016105d9565b6001600160a01b03808516600090815260016020908152604080832093871683529290522082905580156107d957826001600160a01b0316846001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92584604051610bd091815260200190565b60405180910390a350505050565b6001600160a01b038316610c09578060026000828254610bfe9190611231565b90915550610c7b9050565b6001600160a01b03831660009081526020819052604090205481811015610c5c5760405163391434e360e21b81526001600160a01b038516600482015260248101829052604481018390526064016105d9565b6001600160a01b03841660009081526020819052604090209082900390555b6001600160a01b038216610c9757600280548290039055610cb6565b6001600160a01b03821660009081526020819052604090208054820190555b816001600160a01b0316836001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef83604051610cfb91815260200190565b60405180910390a3505050565b606060ff8314610d2257610d1b83610f3b565b90506103fa565b818054610d2e906111f7565b80601f0160208091040260200160405190810160405280929190818152602001828054610d5a906111f7565b8015610da75780601f10610d7c57610100808354040283529160200191610da7565b820191906000526020600020905b815481529060010190602001808311610d8a57829003601f168201915b505050505090506103fa565b600080807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0841115610dee5750600091506003905082610e78565b604080516000808252602082018084528a905260ff891692820192909252606081018790526080810186905260019060a0016020604051602081039080840390855afa158015610e42573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116610e6e57506000925060019150829050610e78565b9250600091508190505b9450945094915050565b6000826003811115610e9657610e96611252565b03610e9f575050565b6001826003811115610eb357610eb3611252565b03610ed15760405163f645eedf60e01b815260040160405180910390fd5b6002826003811115610ee557610ee5611252565b03610f065760405163fce698f760e01b8152600481018290526024016105d9565b6003826003811115610f1a57610f1a611252565b036104f1576040516335e2f38360e21b8152600481018290526024016105d9565b60606000610f4883610f7a565b604080516020808252818301909252919250600091906020820181803683375050509182525060208101929092525090565b600060ff8216601f8111156103fa57604051632cd44ac360e21b815260040160405180910390fd5b6000815180845260005b81811015610fc857602081850181015186830182015201610fac565b506000602082860101526020601f19601f83011685010191505092915050565b602081526000610ffb6020830184610fa2565b9392505050565b80356001600160a01b038116811461101957600080fd5b919050565b6000806040838503121561103157600080fd5b61103a83611002565b946020939093013593505050565b60008060006060848603121561105d57600080fd5b61106684611002565b925061107460208501611002565b9150604084013590509250925092565b60006020828403121561109657600080fd5b5035919050565b6000602082840312156110af57600080fd5b610ffb82611002565b60ff60f81b881681526000602060e060208401526110d960e084018a610fa2565b83810360408501526110eb818a610fa2565b606085018990526001600160a01b038816608086015260a0850187905284810360c08601528551808252602080880193509091019060005b8181101561113f57835183529284019291840191600101611123565b50909c9b505050505050505050505050565b600080600080600080600060e0888a03121561116c57600080fd5b61117588611002565b965061118360208901611002565b95506040880135945060608801359350608088013560ff811681146111a757600080fd5b9699959850939692959460a0840135945060c09093013592915050565b600080604083850312156111d757600080fd5b6111e083611002565b91506111ee60208401611002565b90509250929050565b600181811c9082168061120b57607f821691505b60208210810361122b57634e487b7160e01b600052602260045260246000fd5b50919050565b808201808211156103fa57634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052602160045260246000fdfea26469706673582212205a8199658d4eaad2b10696323e0bc0215d35ed43fe73c3637316e44e6d8ca31864736f6c6343000817003360806040523480156200001157600080fd5b5060405162001eb738038062001eb7833981016040819052620000349162000202565b858585600062000045838262000386565b50600162000054828262000386565b5050506001600160a01b0381166200008657604051631e4fbdf760e01b81526000600482015260240160405180910390fd5b6200009181620000cb565b50600c620000a0848262000386565b50600d620000af838262000386565b50600e620000be828262000386565b5050505050505062000452565b600b80546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b80516001600160a01b03811681146200013557600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126200016257600080fd5b81516001600160401b03808211156200017f576200017f6200013a565b604051601f8301601f19908116603f01168101908282118183101715620001aa57620001aa6200013a565b8160405283815260209250866020858801011115620001c857600080fd5b600091505b83821015620001ec5785820183015181830184015290820190620001cd565b6000602085830101528094505050505092915050565b60008060008060008060c087890312156200021c57600080fd5b62000227876200011d565b60208801519096506001600160401b03808211156200024557600080fd5b620002538a838b0162000150565b965060408901519150808211156200026a57600080fd5b620002788a838b0162000150565b955060608901519150808211156200028f57600080fd5b6200029d8a838b0162000150565b94506080890151915080821115620002b457600080fd5b620002c28a838b0162000150565b935060a0890151915080821115620002d957600080fd5b50620002e889828a0162000150565b9150509295509295509295565b600181811c908216806200030a57607f821691505b6020821081036200032b57634e487b7160e01b600052602260045260246000fd5b50919050565b601f82111562000381576000816000526020600020601f850160051c810160208610156200035c5750805b601f850160051c820191505b818110156200037d5782815560010162000368565b5050505b505050565b81516001600160401b03811115620003a257620003a26200013a565b620003ba81620003b38454620002f5565b8462000331565b602080601f831160018114620003f25760008415620003d95750858301515b600019600386901b1c1916600185901b1785556200037d565b600085815260208120601f198616915b82811015620004235788860151825594840194600190910190840162000402565b5085821015620004425787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b611a5580620004626000396000f3fe608060405234801561001057600080fd5b50600436106101cf5760003560e01c806370a0823111610104578063a76b4d56116100a2578063cd279c7c11610071578063cd279c7c146103a8578063e8a3d485146103bb578063e985e9c5146103c3578063f2fde38b146103d657600080fd5b8063a76b4d5614610372578063b49bbd941461037a578063b88d4fde14610382578063c87b56dd1461039557600080fd5b806394e29329116100de57806394e293291461034757806395d89b411461034f578063a159047b14610357578063a22cb4651461035f57600080fd5b806370a082311461031b578063715018a61461032e5780638da5cb5b1461033657600080fd5b80632f745c59116101715780634f558e791161014b5780634f558e79146102c25780634f6ccce7146102ed5780635e0a9661146103005780636352211e1461030857600080fd5b80632f745c591461028957806342842e0e1461029c57806342966c68146102af57600080fd5b8063095ea7b3116101ad578063095ea7b31461023c57806318160ddd1461025157806318e97fd11461026357806323b872dd1461027657600080fd5b806301ffc9a7146101d457806306fdde03146101fc578063081812fc14610211575b600080fd5b6101e76101e2366004611494565b6103e9565b60405190151581526020015b60405180910390f35b6102046103fa565b6040516101f39190611501565b61022461021f366004611514565b61048c565b6040516001600160a01b0390911681526020016101f3565b61024f61024a366004611549565b6104b5565b005b6009545b6040519081526020016101f3565b61024f61027136600461161f565b6104c4565b61024f610284366004611666565b6104d6565b610255610297366004611549565b610566565b61024f6102aa366004611666565b6105cb565b61024f6102bd366004611514565b6105eb565b6101e76102d0366004611514565b6000908152600260205260409020546001600160a01b0316151590565b6102556102fb366004611514565b6105f7565b610204610650565b610224610316366004611514565b61065f565b6102556103293660046116a2565b61066a565b61024f6106b2565b600b546001600160a01b0316610224565b6102046106c6565b6102046106d5565b6102046106e4565b61024f61036d3660046116bd565b610772565b61020461077d565b61020461078a565b61024f6103903660046116f9565b610797565b6102046103a3366004611514565b6107ae565b61024f6103b6366004611775565b6107b9565b6102046107d5565b6101e76103d13660046117cc565b6107e4565b61024f6103e43660046116a2565b610812565b60006103f482610850565b92915050565b606060008054610409906117ff565b80601f0160208091040260200160405190810160405280929190818152602001828054610435906117ff565b80156104825780601f1061045757610100808354040283529160200191610482565b820191906000526020600020905b81548152906001019060200180831161046557829003601f168201915b5050505050905090565b600061049782610875565b506000828152600460205260409020546001600160a01b03166103f4565b6104c08282336108ae565b5050565b6104cc6108bb565b6104c082826108e8565b6001600160a01b03821661050557604051633250574960e11b8152600060048201526024015b60405180910390fd5b6000610512838333610938565b9050836001600160a01b0316816001600160a01b031614610560576040516364283d7b60e01b81526001600160a01b03808616600483015260248201849052821660448201526064016104fc565b50505050565b60006105718361066a565b82106105a25760405163295f44f760e21b81526001600160a01b0384166004820152602481018390526044016104fc565b506001600160a01b03919091166000908152600760209081526040808320938352929052205490565b6105e683838360405180602001604052806000815250610797565b505050565b6104c060008233610938565b600061060260095490565b821061062b5760405163295f44f760e21b815260006004820152602481018390526044016104fc565b6009828154811061063e5761063e611839565b90600052602060002001549050919050565b6060600d8054610409906117ff565b60006103f482610875565b60006001600160a01b038216610696576040516322718ad960e21b8152600060048201526024016104fc565b506001600160a01b031660009081526003602052604090205490565b6106ba6108bb565b6106c4600061094d565b565b6060600c8054610409906117ff565b606060018054610409906117ff565b600d80546106f1906117ff565b80601f016020809104026020016040519081016040528092919081815260200182805461071d906117ff565b801561076a5780601f1061073f5761010080835404028352916020019161076a565b820191906000526020600020905b81548152906001019060200180831161074d57829003601f168201915b505050505081565b6104c033838361099f565b600e80546106f1906117ff565b600c80546106f1906117ff565b6107a28484846104d6565b61056084848484610a3e565b60606103f482610b67565b6107c16108bb565b6107cb8383610c70565b6105e682826108e8565b6060600e8054610409906117ff565b6001600160a01b03918216600090815260056020908152604080832093909416825291909152205460ff1690565b61081a6108bb565b6001600160a01b03811661084457604051631e4fbdf760e01b8152600060048201526024016104fc565b61084d8161094d565b50565b60006001600160e01b0319821663780e9d6360e01b14806103f457506103f482610c8a565b6000818152600260205260408120546001600160a01b0316806103f457604051637e27328960e01b8152600481018490526024016104fc565b6105e68383836001610caf565b600b546001600160a01b031633146106c45760405163118cdaa760e01b81523360048201526024016104fc565b6000828152600660205260409020610900828261189f565b506040518281527ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79060200160405180910390a15050565b6000610945848484610db5565b949350505050565b600b80546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6001600160a01b0382166109d157604051630b61174360e31b81526001600160a01b03831660048201526024016104fc565b6001600160a01b03838116600081815260056020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b6001600160a01b0383163b1561056057604051630a85bd0160e11b81526001600160a01b0384169063150b7a0290610a8090339088908790879060040161195f565b6020604051808303816000875af1925050508015610abb575060408051601f3d908101601f19168201909252610ab89181019061199c565b60015b610b24573d808015610ae9576040519150601f19603f3d011682016040523d82523d6000602084013e610aee565b606091505b508051600003610b1c57604051633250574960e11b81526001600160a01b03851660048201526024016104fc565b805181602001fd5b6001600160e01b03198116630a85bd0160e11b14610b6057604051633250574960e11b81526001600160a01b03851660048201526024016104fc565b5050505050565b6060610b7282610875565b5060008281526006602052604081208054610b8c906117ff565b80601f0160208091040260200160405190810160405280929190818152602001828054610bb8906117ff565b8015610c055780601f10610bda57610100808354040283529160200191610c05565b820191906000526020600020905b815481529060010190602001808311610be857829003601f168201915b505050505090506000610c2360408051602081019091526000815290565b90508051600003610c35575092915050565b815115610c67578082604051602001610c4f9291906119b9565b60405160208183030381529060405292505050919050565b61094584610e82565b6104c0828260405180602001604052806000815250610ef7565b60006001600160e01b03198216632483248360e11b14806103f457506103f482610f0e565b8080610cc357506001600160a01b03821615155b15610d85576000610cd384610875565b90506001600160a01b03831615801590610cff5750826001600160a01b0316816001600160a01b031614155b8015610d125750610d1081846107e4565b155b15610d3b5760405163a9fbf51f60e01b81526001600160a01b03841660048201526024016104fc565b8115610d835783856001600160a01b0316826001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45b505b5050600090815260046020526040902080546001600160a01b0319166001600160a01b0392909216919091179055565b600080610dc3858585610f5e565b90506001600160a01b038116610e2057610e1b84600980546000838152600a60205260408120829055600182018355919091527f6e1540171b6c0c960b71a7020d9f60077f6af931a8bbf590da0223dacf75c7af0155565b610e43565b846001600160a01b0316816001600160a01b031614610e4357610e438185611057565b6001600160a01b038516610e5f57610e5a846110e8565b610945565b846001600160a01b0316816001600160a01b031614610945576109458585611197565b6060610e8d82610875565b506000610ea560408051602081019091526000815290565b90506000815111610ec55760405180602001604052806000815250610ef0565b80610ecf846111e7565b604051602001610ee09291906119b9565b6040516020818303038152906040525b9392505050565b610f01838361127a565b6105e66000848484610a3e565b60006001600160e01b031982166380ac58cd60e01b1480610f3f57506001600160e01b03198216635b5e139f60e01b145b806103f457506301ffc9a760e01b6001600160e01b03198316146103f4565b6000828152600260205260408120546001600160a01b0390811690831615610f8b57610f8b8184866112df565b6001600160a01b03811615610fc957610fa8600085600080610caf565b6001600160a01b038116600090815260036020526040902080546000190190555b6001600160a01b03851615610ff8576001600160a01b0385166000908152600360205260409020805460010190555b60008481526002602052604080822080546001600160a01b0319166001600160a01b0389811691821790925591518793918516917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4949350505050565b60006110628361066a565b6000838152600860205260409020549091508082146110b5576001600160a01b03841660009081526007602090815260408083208584528252808320548484528184208190558352600890915290208190555b5060009182526008602090815260408084208490556001600160a01b039094168352600781528383209183525290812055565b6009546000906110fa906001906119e8565b6000838152600a60205260408120546009805493945090928490811061112257611122611839565b90600052602060002001549050806009838154811061114357611143611839565b6000918252602080832090910192909255828152600a9091526040808220849055858252812055600980548061117b5761117b611a09565b6001900381819060005260206000200160009055905550505050565b600060016111a48461066a565b6111ae91906119e8565b6001600160a01b039093166000908152600760209081526040808320868452825280832085905593825260089052919091209190915550565b606060006111f483611343565b600101905060008167ffffffffffffffff81111561121457611214611573565b6040519080825280601f01601f19166020018201604052801561123e576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a850494508461124857509392505050565b6001600160a01b0382166112a457604051633250574960e11b8152600060048201526024016104fc565b60006112b283836000610938565b90506001600160a01b038116156105e6576040516339e3563760e11b8152600060048201526024016104fc565b6112ea83838361141b565b6105e6576001600160a01b03831661131857604051637e27328960e01b8152600481018290526024016104fc565b60405163177e802f60e01b81526001600160a01b0383166004820152602481018290526044016104fc565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b83106113825772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef810000000083106113ae576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc1000083106113cc57662386f26fc10000830492506010015b6305f5e10083106113e4576305f5e100830492506008015b61271083106113f857612710830492506004015b6064831061140a576064830492506002015b600a83106103f45760010192915050565b60006001600160a01b038316158015906109455750826001600160a01b0316846001600160a01b03161480611455575061145584846107e4565b806109455750506000908152600460205260409020546001600160a01b03908116911614919050565b6001600160e01b03198116811461084d57600080fd5b6000602082840312156114a657600080fd5b8135610ef08161147e565b60005b838110156114cc5781810151838201526020016114b4565b50506000910152565b600081518084526114ed8160208601602086016114b1565b601f01601f19169290920160200192915050565b602081526000610ef060208301846114d5565b60006020828403121561152657600080fd5b5035919050565b80356001600160a01b038116811461154457600080fd5b919050565b6000806040838503121561155c57600080fd5b6115658361152d565b946020939093013593505050565b634e487b7160e01b600052604160045260246000fd5b600067ffffffffffffffff808411156115a4576115a4611573565b604051601f8501601f19908116603f011681019082821181831017156115cc576115cc611573565b816040528093508581528686860111156115e557600080fd5b858560208301376000602087830101525050509392505050565b600082601f83011261161057600080fd5b610ef083833560208501611589565b6000806040838503121561163257600080fd5b82359150602083013567ffffffffffffffff81111561165057600080fd5b61165c858286016115ff565b9150509250929050565b60008060006060848603121561167b57600080fd5b6116848461152d565b92506116926020850161152d565b9150604084013590509250925092565b6000602082840312156116b457600080fd5b610ef08261152d565b600080604083850312156116d057600080fd5b6116d98361152d565b9150602083013580151581146116ee57600080fd5b809150509250929050565b6000806000806080858703121561170f57600080fd5b6117188561152d565b93506117266020860161152d565b925060408501359150606085013567ffffffffffffffff81111561174957600080fd5b8501601f8101871361175a57600080fd5b61176987823560208401611589565b91505092959194509250565b60008060006060848603121561178a57600080fd5b6117938461152d565b925060208401359150604084013567ffffffffffffffff8111156117b657600080fd5b6117c2868287016115ff565b9150509250925092565b600080604083850312156117df57600080fd5b6117e88361152d565b91506117f66020840161152d565b90509250929050565b600181811c9082168061181357607f821691505b60208210810361183357634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052603260045260246000fd5b601f8211156105e6576000816000526020600020601f850160051c810160208610156118785750805b601f850160051c820191505b8181101561189757828155600101611884565b505050505050565b815167ffffffffffffffff8111156118b9576118b9611573565b6118cd816118c784546117ff565b8461184f565b602080601f83116001811461190257600084156118ea5750858301515b600019600386901b1c1916600185901b178555611897565b600085815260208120601f198616915b8281101561193157888601518255948401946001909101908401611912565b508582101561194f5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6001600160a01b0385811682528416602082015260408101839052608060608201819052600090611992908301846114d5565b9695505050505050565b6000602082840312156119ae57600080fd5b8151610ef08161147e565b600083516119cb8184602088016114b1565b8351908301906119df8183602088016114b1565b01949350505050565b818103818111156103f457634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052603160045260246000fdfea26469706673582212206ebc33968f0bb2aac75fa88729c43c34a634938367a10e417cf26ce7e65b108764736f6c63430008170033a2646970667358221220a26f238ed62e7e34bbbb8acd7b64f9737843d19754822adfb4ce059e7e1743e064736f6c63430008170033" + "value": "608060405234801561001057600080fd5b50338061003757604051631e4fbdf760e01b81526000600482015260240160405180910390fd5b61004081610046565b50610096565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b611452806100a56000396000f3fe608060405234801561001057600080fd5b50600436106101005760003560e01c8063aff51c3e11610097578063daa09e5411610066578063daa09e5414610216578063db6d56cd14610229578063dfe1ac361461023c578063f2fde38b1461024f57600080fd5b8063aff51c3e146101bd578063b3d5dbdc146101d0578063cc435bf3146101f0578063d974d2381461020357600080fd5b806366cd5014116100d357806366cd50141461017e578063715018a61461019157806383843c9e146101995780638da5cb5b146101ac57600080fd5b806304433bbc1461010557806314902ad314610135578063263e0c1b1461014a5780635ab1bd531461016d575b600080fd5b610118610113366004611067565b610262565b6040516001600160a01b0390911681526020015b60405180910390f35b6101486101433660046110b9565b6102da565b005b61015d6101583660046110b9565b610354565b604051901515815260200161012c565b6001546001600160a01b0316610118565b61011861018c366004611067565b610744565b610148610775565b6101486101a7366004611067565b610789565b6000546001600160a01b0316610118565b6101486101cb3660046110d6565b61088b565b6101e36101de3660046110b9565b6109a4565b60405161012c9190611178565b61015d6101fe3660046110b9565b610a17565b6101486102113660046110d6565b610a37565b61015d6102243660046110b9565b610b08565b61011861023736600461118b565b610b7e565b61015d61024a3660046110b9565b610c53565b61014861025d3660046110b9565b610cc2565b600154604051630110ceef60e21b81526000916001600160a01b0316906304433bbc90610293908590600401611178565b602060405180830381865afa1580156102b0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102d49190611280565b92915050565b6102e2610d00565b6102eb81610d2d565b600154604080516001600160a01b03928316815291831660208301527f61dad6e94cd5c0b65c9265246706a09bd0d11d5330f3e6b659d328151a664e8c910160405180910390a1600180546001600160a01b0319166001600160a01b0392909216919091179055565b60408051600481526024810182526020810180516001600160e01b03166318160ddd60e01b1790529051600091829182916001600160a01b0386169161039a919061129d565b600060405180830381855afa9150503d80600081146103d5576040519150601f19603f3d011682016040523d82523d6000602084013e6103da565b606091505b50915091508115806103eb57508051155b156103fa575060009392505050565b604051600060248201526001600160a01b0385169060440160408051601f198184030181529181526020820180516001600160e01b03166370a0823160e01b17905251610447919061129d565b600060405180830381855afa9150503d8060008114610482576040519150601f19603f3d011682016040523d82523d6000602084013e610487565b606091505b50909250905081158061049957508051155b156104a8575060009392505050565b60405160006024820181905260448201526001600160a01b0385169060640160408051601f198184030181529181526020820180516001600160e01b0316636eb1769f60e11b179052516104fc919061129d565b600060405180830381855afa9150503d8060008114610537576040519150601f19603f3d011682016040523d82523d6000602084013e61053c565b606091505b50909250905081158061054e57508051155b1561055d575060009392505050565b60408051600481526024810182526020810180516001600160e01b03166306fdde0360e01b17905290516001600160a01b0386169161059b9161129d565b600060405180830381855afa9150503d80600081146105d6576040519150601f19603f3d011682016040523d82523d6000602084013e6105db565b606091505b5090925090508115806105ed57508051155b156105fc575060009392505050565b60408051600481526024810182526020810180516001600160e01b03166395d89b4160e01b17905290516001600160a01b0386169161063a9161129d565b600060405180830381855afa9150503d8060008114610675576040519150601f19603f3d011682016040523d82523d6000602084013e61067a565b606091505b50909250905081158061068c57508051155b1561069b575060009392505050565b60408051600481526024810182526020810180516001600160e01b031663313ce56760e01b17905290516001600160a01b038616916106d99161129d565b600060405180830381855afa9150503d8060008114610714576040519150601f19603f3d011682016040523d82523d6000602084013e610719565b606091505b50909250905081158061072b57508051155b1561073a575060009392505050565b5060019392505050565b6000600282604051610756919061129d565b908152604051908190036020019020546001600160a01b031692915050565b61077d610d00565b6107876000610d9f565b565b610791610d00565b60006002826040516107a3919061129d565b908152604051908190036020019020546001600160a01b03169050806108235760405162461bcd60e51b815260206004820152602a60248201527f466c6f77427269646765466163746f72793a204465706c6f796572206e6f74206044820152691c9959da5cdd195c995960b21b60648201526084015b60405180910390fd5b600282604051610833919061129d565b90815260405190819003602001812080546001600160a01b03191690557f03c7566b5f4959b890c1a6d38f39df053c6737c9965d9c0ddf612c86100a838b9061087f90849084906112b9565b60405180910390a15050565b610893610d00565b61089c81610def565b60006001600160a01b03166002836040516108b7919061129d565b908152604051908190036020019020546001600160a01b0316146109345760405162461bcd60e51b815260206004820152602e60248201527f466c6f77427269646765466163746f72793a204465706c6f79657220616c726560448201526d18591e481c9959da5cdd195c995960921b606482015260840161081a565b80600283604051610945919061129d565b90815260405190819003602001812080546001600160a01b03939093166001600160a01b0319909316929092179091557fc0c30f085f0b1397c8bf23f8b851b63b33e13d11832b8320a37fca1c07dcb40f9061087f90849084906112b9565b600154604051632cf576f760e21b81526001600160a01b038381166004830152606092169063b3d5dbdc90602401600060405180830381865afa1580156109ef573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526102d491908101906112e3565b6000610a2282610b08565b1515610a2d83610354565b1515141592915050565b610a3f610d00565b610a4881610def565b6000600283604051610a5a919061129d565b908152604051908190036020019020546001600160a01b0316905080610a8957610a84838361088b565b505050565b81600284604051610a9a919061129d565b90815260405190819003602001812080546001600160a01b03939093166001600160a01b0319909316929092179091557f848576f8a081c5af60d89f0215c8af528186670eefd6349c05014d5b2268864690610afb9085908490869061135a565b60405180910390a1505050565b6040516301ffc9a760e01b81526380ac58cd60e01b60048201526000906001600160a01b038316906301ffc9a790602401602060405180830381865afa925050508015610b72575060408051601f3d908101601f19168201909252610b6f9181019061138d565b60015b6102d457506000919050565b6000610b88610d00565b6000600288604051610b9a919061129d565b908152604051908190036020019020546001600160a01b03169050610bbe81610def565b60405163476d399760e01b815281906000906001600160a01b0383169063476d399790610bf7908c908c908c908c908c906004016113af565b6020604051808303816000875af1158015610c16573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c3a9190611280565b9050610c468682610e61565b9998505050505050505050565b60015460405163a6de610560e01b81526001600160a01b038381166004830152600092169063a6de610590602401602060405180830381865afa158015610c9e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102d4919061138d565b610cca610d00565b6001600160a01b038116610cf457604051631e4fbdf760e01b81526000600482015260240161081a565b610cfd81610d9f565b50565b6000546001600160a01b031633146107875760405163118cdaa760e01b815233600482015260240161081a565b610d3681610ecc565b610d478163976998cb60e01b610f22565b610cfd5760405162461bcd60e51b815260206004820152602360248201527f466c6f77427269646765466163746f72793a20496e76616c696420726567697360448201526274727960e81b606482015260840161081a565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b610df881610ecc565b610e098163476d399760e01b610f22565b610cfd5760405162461bcd60e51b815260206004820152602360248201527f466c6f77427269646765466163746f72793a20496e76616c6964206465706c6f6044820152623cb2b960e91b606482015260840161081a565b60015460405163522791d160e01b81526001600160a01b0390911690819063522791d190610e9590869086906004016112b9565b600060405180830381600087803b158015610eaf57600080fd5b505af1158015610ec3573d6000803e3d6000fd5b50505050505050565b6001600160a01b038116610cfd5760405162461bcd60e51b815260206004820152601f60248201527f466c6f77427269646765466163746f72793a205a65726f206164647265737300604482015260640161081a565b6040516301ffc9a760e01b81526001600160e01b0319821660048201526000906001600160a01b038416906301ffc9a790602401602060405180830381865afa925050508015610f8f575060408051601f3d908101601f19168201909252610f8c9181019061138d565b60015b610f9b575060006102d4565b9392505050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715610fe157610fe1610fa2565b604052919050565b600067ffffffffffffffff82111561100357611003610fa2565b50601f01601f191660200190565b600082601f83011261102257600080fd5b813561103561103082610fe9565b610fb8565b81815284602083860101111561104a57600080fd5b816020850160208301376000918101602001919091529392505050565b60006020828403121561107957600080fd5b813567ffffffffffffffff81111561109057600080fd5b61109c84828501611011565b949350505050565b6001600160a01b0381168114610cfd57600080fd5b6000602082840312156110cb57600080fd5b8135610f9b816110a4565b600080604083850312156110e957600080fd5b823567ffffffffffffffff81111561110057600080fd5b61110c85828601611011565b925050602083013561111d816110a4565b809150509250929050565b60005b8381101561114357818101518382015260200161112b565b50506000910152565b60008151808452611164816020860160208601611128565b601f01601f19169290920160200192915050565b602081526000610f9b602083018461114c565b60008060008060008060c087890312156111a457600080fd5b863567ffffffffffffffff808211156111bc57600080fd5b6111c88a838b01611011565b975060208901359150808211156111de57600080fd5b6111ea8a838b01611011565b9650604089013591508082111561120057600080fd5b61120c8a838b01611011565b9550606089013591508082111561122257600080fd5b61122e8a838b01611011565b9450608089013591508082111561124457600080fd5b6112508a838b01611011565b935060a089013591508082111561126657600080fd5b5061127389828a01611011565b9150509295509295509295565b60006020828403121561129257600080fd5b8151610f9b816110a4565b600082516112af818460208701611128565b9190910192915050565b6040815260006112cc604083018561114c565b905060018060a01b03831660208301529392505050565b6000602082840312156112f557600080fd5b815167ffffffffffffffff81111561130c57600080fd5b8201601f8101841361131d57600080fd5b805161132b61103082610fe9565b81815285602083850101111561134057600080fd5b611351826020830160208601611128565b95945050505050565b60608152600061136d606083018661114c565b6001600160a01b0394851660208401529290931660409091015292915050565b60006020828403121561139f57600080fd5b81518015158114610f9b57600080fd5b60a0815260006113c260a083018861114c565b82810360208401526113d4818861114c565b905082810360408401526113e8818761114c565b905082810360608401526113fc818661114c565b90508281036080840152611410818561114c565b9897505050505050505056fea264697066735822122026be7d4ef13534833344abdcc736e8876603e1f9d3463f0047ddca092a98cc2d64736f6c63430008170033" }, { "type": "UInt64", diff --git a/cadence/contracts/bridge/FlowEVMBridge.cdc b/cadence/contracts/bridge/FlowEVMBridge.cdc index 7c8af54d..3199bb23 100644 --- a/cadence/contracts/bridge/FlowEVMBridge.cdc +++ b/cadence/contracts/bridge/FlowEVMBridge.cdc @@ -550,7 +550,7 @@ contract FlowEVMBridge : IFlowEVMNFTBridge, IFlowEVMTokenBridge { /// access(all) view fun typeRequiresOnboarding(_ type: Type): Bool? { - if !FlowEVMBridgeUtils.isValidFlowAsset(type: type) { + if !FlowEVMBridgeUtils.isValidCadenceAsset(type: type) { return nil } return FlowEVMBridgeConfig.getEVMAddressAssociated(with: type) == nil && @@ -590,7 +590,7 @@ contract FlowEVMBridge : IFlowEVMNFTBridge, IFlowEVMTokenBridge { access(self) fun deployEVMContract(forAssetType: Type): FlowEVMBridgeUtils.EVMOnboardingValues { pre { - FlowEVMBridgeUtils.isValidFlowAsset(type: forAssetType): + FlowEVMBridgeUtils.isValidCadenceAsset(type: forAssetType): "Asset type is not supported by the bridge" } let isNFT = forAssetType.isSubtype(of: Type<@{NonFungibleToken.NFT}>()) diff --git a/cadence/contracts/bridge/FlowEVMBridgeUtils.cdc b/cadence/contracts/bridge/FlowEVMBridgeUtils.cdc index 7f7443b9..240139ef 100644 --- a/cadence/contracts/bridge/FlowEVMBridgeUtils.cdc +++ b/cadence/contracts/bridge/FlowEVMBridgeUtils.cdc @@ -21,7 +21,7 @@ contract FlowEVMBridgeUtils { /// Address of the bridge factory Solidity contract access(all) - let bridgeFactoryEVMAddress: EVM.EVMAddress + var bridgeFactoryEVMAddress: EVM.EVMAddress /// Delimeter used to derive contract names access(self) let delimiter: String @@ -188,7 +188,7 @@ contract FlowEVMBridgeUtils { fun isEVMContractBridgeOwned(evmContractAddress: EVM.EVMAddress): Bool { // Ask the bridge factory if the given contract address was deployed by the bridge let callResult = self.call( - signature: "isFactoryDeployed(address)", + signature: "isBridgeDeployed(address)", targetEVMAddress: self.bridgeFactoryEVMAddress, args: [evmContractAddress], gasLimit: 60000, @@ -256,9 +256,16 @@ contract FlowEVMBridgeUtils { /// access(all) fun isValidEVMAsset(evmContractAddress: EVM.EVMAddress): Bool { - let isERC721 = self.isERC721(evmContractAddress: evmContractAddress) - let isERC20 = self.isERC20(evmContractAddress: evmContractAddress) - return (isERC721 && !isERC20) || (!isERC721 && isERC20) + let callResult = self.call( + signature: "isValidAsset(address)", + targetEVMAddress: self.bridgeFactoryEVMAddress, + args: [evmContractAddress], + gasLimit: 100000, + value: 0.0 + ) + let decodedResult = EVM.decodeABI(types: [Type()], data: callResult.data) + assert(decodedResult.length == 1, message: "Invalid response length") + return decodedResult[0] as! Bool } /// Returns whether the given type is either an NFT or FT exclusively @@ -268,10 +275,10 @@ contract FlowEVMBridgeUtils { /// @return True if the type is either an NFT or FT, false otherwise /// access(all) - view fun isValidFlowAsset(type: Type): Bool { - let isFlowNFT = type.isSubtype(of: Type<@{NonFungibleToken.NFT}>()) - let isFlowToken = type.isSubtype(of: Type<@{FungibleToken.Vault}>()) - return (isFlowNFT && !isFlowToken) || (!isFlowNFT && isFlowToken) + view fun isValidCadenceAsset(type: Type): Bool { + let isCadenceNFT = type.isSubtype(of: Type<@{NonFungibleToken.NFT}>()) + let isCadenceFungibleToken = type.isSubtype(of: Type<@{FungibleToken.Vault}>()) + return isCadenceNFT != isCadenceFungibleToken } /// Retrieves the bridge contract's COA EVMAddress @@ -297,7 +304,7 @@ contract FlowEVMBridgeUtils { access(all) fun getCadenceOnboardingValues(forAssetType: Type): CadenceOnboardingValues { pre { - self.isValidFlowAsset(type: forAssetType): "This type is not a supported Flow asset type." + self.isValidCadenceAsset(type: forAssetType): "This type is not a supported Flow asset type." } // If not an NFT, assumed to be fungible token. let isNFT = forAssetType.isSubtype(of: Type<@{NonFungibleToken.NFT}>()) @@ -719,7 +726,7 @@ contract FlowEVMBridgeUtils { /// access(all) view fun deriveEscrowStoragePath(fromType: Type): StoragePath? { - if !self.isValidFlowAsset(type: fromType) { + if !self.isValidCadenceAsset(type: fromType) { return nil } var prefix = "" @@ -811,26 +818,6 @@ contract FlowEVMBridgeUtils { return r } - /// Converts a UInt256 to a UFix64 - /// - access(all) - view fun uint256ToUFix64(value: UInt256, decimals: UInt8): UFix64 { - // Calculate scale factors for the integer and fractional parts - let absoluteScaleFactor = self.pow(base: 10, exponent: decimals) - - // Separate the integer and fractional parts of the value - let scaledValue = value / absoluteScaleFactor - var fractional = value % absoluteScaleFactor - let scaledFractional = self.uint256FractionalToScaledUFix64Decimals(value: fractional, decimals: decimals) - - assert( - scaledValue < UInt256(UFix64.max), - message: "Scaled integer value ".concat(value.toString()).concat(" exceeds max UFix64 value") - ) - - return UFix64(scaledValue) + scaledFractional - } - /// Converts a UFix64 to a UInt256 // access(all) @@ -852,41 +839,59 @@ contract FlowEVMBridgeUtils { return integer * integerMultiplier + UInt256(fractional) * fractionalMultiplier } + /// Converts a UInt256 to a UFix64 + /// + access(all) + view fun uint256ToUFix64(value: UInt256, decimals: UInt8): UFix64 { + // Calculate scale factors for the integer and fractional parts + let absoluteScaleFactor = self.pow(base: 10, exponent: decimals) + + // Separate the integer and fractional parts of the value + let scaledValue = value / absoluteScaleFactor + var fractional = value % absoluteScaleFactor + // Scale the fractional part + let scaledFractional = self.uint256FractionalToScaledUFix64Decimals(value: fractional, decimals: decimals) + + // Ensure the parts do not exceed the max UFix64 value before conversion + assert( + scaledValue <= UInt256(UFix64.max), + message: "Scaled integer value ".concat(value.toString()).concat(" exceeds max UFix64 value") + ) + assert( + scaledValue == UInt256(UFix64.max) ? scaledFractional < 0.09551616 : true, + message: "Scaled integer value ".concat(value.toString()).concat(" exceeds max UFix64 value") + ) + + return UFix64(scaledValue) + scaledFractional + } + /// Converts a UInt256 fractional value with the given decimal places to a scaled UFix64. Note that UFix64 has /// decimal precision of 8 places so converted values may lose precision and be rounded down. /// access(all) view fun uint256FractionalToScaledUFix64Decimals(value: UInt256, decimals: UInt8): UFix64 { + pre { + self.getNumberOfDigits(value) <= decimals: "Fractional digits exceed the defined decimal places" + } post { - result < 1.0: "Scaled fractional exceeds 1.0" + result < 1.0: "Resulting scaled fractional exceeds 1.0" } + var fractional = value - // Reduce fractional values with trailing zeros - var e: UInt8 = 0 - while fractional > 0 { - if fractional % 10 == 0 { - fractional = fractional / 10 - e = e + 1 - } else { - break - } + // Truncate fractional to the first 8 decimal places which is the max precision for UFix64 + if decimals >= 8 { + fractional = fractional / self.pow(base: 10, exponent: decimals - 8) } - - // fractional is too long - since UFix64 has 8 decimal places, truncate to maintain only the first 8 digis - var fractionalReduction: UInt8 = 0 - while fractional > 99999999 { - fractional = fractional / 10 - fractionalReduction = fractionalReduction + 1 + // Return early if the truncated fractional part is now 0 + if fractional == 0 { + return 0.0 } // Scale the fractional part - let fractionalMultiplier = self.ufixPow(base: 0.1, exponent: decimals - e - fractionalReduction) - let scaledFractional = UFix64(fractional) * fractionalMultiplier - - return scaledFractional + let fractionalMultiplier = self.ufixPow(base: 0.1, exponent: decimals < 8 ? decimals : 8) + return UFix64(fractional) * fractionalMultiplier } - /// Returns the value as a UInt64 if it fits, otherwise panics /// access(all) @@ -894,6 +899,19 @@ contract FlowEVMBridgeUtils { return value <= UInt256(UInt64.max) ? UInt64(value) : panic("Value too large to fit into UInt64") } + /// Returns the number of digits in the given UInt256 + /// + access(all) + view fun getNumberOfDigits(_ value: UInt256): UInt8 { + var tmp = value + var digits: UInt8 = 0 + while tmp > 0 { + tmp = tmp / 10 + digits = digits + 1 + } + return digits + } + /*************************** Type Identifier Utils ***************************/ @@ -1241,11 +1259,11 @@ contract FlowEVMBridgeUtils { contractURI: String, isERC721: Bool ): EVM.EVMAddress { - let signature = isERC721 ? "deployERC721(string,string,string,string,string)" : "deployERC20(string,string,string,string,string)" + let deployerTag = isERC721 ? "ERC721" : "ERC20" let deployResult: EVM.Result = self.call( - signature: signature, + signature: "deploy(string,string,string,string,string,string)", targetEVMAddress: self.bridgeFactoryEVMAddress, - args: [name, symbol, cadenceAddress.toString(), flowIdentifier, contractURI], + args: [deployerTag, name, symbol, cadenceAddress.toString(), flowIdentifier, contractURI], gasLimit: 15000000, value: 0.0 ) diff --git a/cadence/tests/flow_evm_bridge_handler_tests.cdc b/cadence/tests/flow_evm_bridge_handler_tests.cdc index 1f8f00bb..3cf54d27 100644 --- a/cadence/tests/flow_evm_bridge_handler_tests.cdc +++ b/cadence/tests/flow_evm_bridge_handler_tests.cdc @@ -125,13 +125,12 @@ fun setup() { // Get the deployed contract address from the latest EVM event let evts = Test.eventsOfType(Type()) Test.assertEqual(2, evts.length) - let factoryDeploymentEvent = evts[0] as! EVM.TransactionExecuted - let factoryAddressHex = factoryDeploymentEvent.contractAddress + let factoryAddressHex = getEVMAddressHexFromEvents(evts, idx: 0) err = Test.deployContract( name: "FlowEVMBridgeUtils", path: "../contracts/bridge/FlowEVMBridgeUtils.cdc", - arguments: [factoryAddressHex.slice(from: 2, upTo: factoryAddressHex.length)] + arguments: [factoryAddressHex] ) Test.expect(err, Test.beNil()) err = Test.deployContract( @@ -205,7 +204,7 @@ fun setup() { Test.expect(err, Test.beNil()) let claimAccessorResult = executeTransaction( - "../transactions/bridge/admin/evm/claim_accessor_capability_and_save_router.cdc", + "../transactions/bridge/admin/evm-integration/claim_accessor_capability_and_save_router.cdc", ["FlowEVMBridgeAccessor", bridgeAccount.address], serviceAccount ) @@ -345,12 +344,7 @@ fun testDeployERC20Succeeds() { let evts = Test.eventsOfType(Type()) Test.assertEqual(7, evts.length) - let erc20DeploymentEvent = evts[6] as! EVM.TransactionExecuted - // remove 0x prefix - erc20AddressHex = erc20DeploymentEvent.contractAddress.slice( - from: 2, - upTo: erc20DeploymentEvent.contractAddress.length - ).toLower() + erc20AddressHex = getEVMAddressHexFromEvents(evts, idx: 6) } // Set the TokenHandler's targetEVMAddress to the deployed ERC20 contract address diff --git a/cadence/tests/flow_evm_bridge_tests.cdc b/cadence/tests/flow_evm_bridge_tests.cdc index 55f40460..de469faa 100644 --- a/cadence/tests/flow_evm_bridge_tests.cdc +++ b/cadence/tests/flow_evm_bridge_tests.cdc @@ -28,6 +28,11 @@ access(all) var mintedNFTID: UInt64 = 0 access(all) let exampleTokenIdentifier = "A.0000000000000010.ExampleToken.Vault" access(all) let exampleTokenMintAmount = 100.0 +// Bridge-related EVM contract values +access(all) var registryAddressHex: String = "" +access(all) var erc20DeployerAddressHex: String = "" +access(all) var erc721DeployerAddressHex: String = "" + // ERC721 values access(all) var erc721AddressHex: String = "" access(all) let erc721Name = "NAME" @@ -127,25 +132,102 @@ fun setup() { arguments: [] ) Test.expect(err, Test.beNil()) + + // Deploy registry + let registryDeploymentResult = executeTransaction( + "../transactions/evm/deploy.cdc", + [getRegistryBytecode(), UInt64(15_000_000), 0.0], + bridgeAccount + ) + Test.expect(registryDeploymentResult, Test.beSucceeded()) + // Deploy ERC20Deployer + let erc20DeployerDeploymentResult = executeTransaction( + "../transactions/evm/deploy.cdc", + [getERC20DeployerBytecode(), UInt64(15_000_000), 0.0], + bridgeAccount + ) + Test.expect(erc20DeployerDeploymentResult, Test.beSucceeded()) + // Deploy ERC721Deployer + let erc721DeployerDeploymentResult = executeTransaction( + "../transactions/evm/deploy.cdc", + [getERC721DeployerBytecode(), UInt64(15_000_000), 0.0], + bridgeAccount + ) + Test.expect(erc721DeployerDeploymentResult, Test.beSucceeded()) + // Assign contract addresses var evts = Test.eventsOfType(Type()) - Test.assertEqual(2, evts.length) + Test.assertEqual(5, evts.length) + registryAddressHex = getEVMAddressHexFromEvents(evts, idx: 2) + erc20DeployerAddressHex = getEVMAddressHexFromEvents(evts, idx: 3) + erc721DeployerAddressHex = getEVMAddressHexFromEvents(evts, idx: 4) + + // Deploy factory let deploymentResult = executeTransaction( "../transactions/evm/deploy.cdc", [getCompiledFactoryBytecode(), UInt64(15_000_000), 0.0], bridgeAccount ) Test.expect(deploymentResult, Test.beSucceeded()) + // Assign the factory contract address evts = Test.eventsOfType(Type()) - Test.assertEqual(3, evts.length) - let factoryDeploymentEvent = evts[2] as! EVM.TransactionExecuted + Test.assertEqual(6, evts.length) + let factoryAddressHex = getEVMAddressHexFromEvents(evts, idx: 5) + Test.assertEqual(factoryAddressHex.length, 40) - let factoryAddressHex = factoryDeploymentEvent.contractAddress err = Test.deployContract( name: "FlowEVMBridgeUtils", path: "../contracts/bridge/FlowEVMBridgeUtils.cdc", - arguments: [factoryAddressHex.slice(from: 2, upTo: factoryAddressHex.length).toLower()] + arguments: [factoryAddressHex] ) Test.expect(err, Test.beNil()) + + /* Integrate EVM bridge contract */ + + // Set factory as registrar in registry + let setRegistrarResult = executeTransaction( + "../transactions/bridge/admin/evm/set_registrar.cdc", + [registryAddressHex], + bridgeAccount + ) + Test.expect(setRegistrarResult, Test.beSucceeded()) + // Set registry as registry in factory + let setRegistryResult = executeTransaction( + "../transactions/bridge/admin/evm/set_deployment_registry.cdc", + [registryAddressHex], + bridgeAccount + ) + Test.expect(setRegistryResult, Test.beSucceeded()) + // Set factory as delegatedDeployer in erc20Deployer + var setDelegatedDeployerResult = executeTransaction( + "../transactions/bridge/admin/evm/set_delegated_deployer.cdc", + [erc20DeployerAddressHex], + bridgeAccount + ) + Test.expect(setDelegatedDeployerResult, Test.beSucceeded()) + // Set factory as delegatedDeployer in erc721Deployer + setDelegatedDeployerResult = executeTransaction( + "../transactions/bridge/admin/evm/set_delegated_deployer.cdc", + [erc721DeployerAddressHex], + bridgeAccount + ) + Test.expect(setDelegatedDeployerResult, Test.beSucceeded()) + // add erc20Deployer under "ERC20" tag to factory + var addDeployerResult = executeTransaction( + "../transactions/bridge/admin/evm/add_deployer.cdc", + ["ERC20", erc20DeployerAddressHex], + bridgeAccount + ) + Test.expect(addDeployerResult, Test.beSucceeded()) + // add erc721Deployer under "ERC721" tag to factory + addDeployerResult = executeTransaction( + "../transactions/bridge/admin/evm/add_deployer.cdc", + ["ERC721", erc721DeployerAddressHex], + bridgeAccount + ) + Test.expect(addDeployerResult, Test.beSucceeded()) + + /* End EVM bridge integration txns */ + err = Test.deployContract( name: "FlowEVMBridgeNFTEscrow", path: "../contracts/bridge/FlowEVMBridgeNFTEscrow.cdc", @@ -217,7 +299,7 @@ fun setup() { Test.expect(err, Test.beNil()) let claimAccessorResult = executeTransaction( - "../transactions/bridge/admin/evm/claim_accessor_capability_and_save_router.cdc", + "../transactions/bridge/admin/evm-integration/claim_accessor_capability_and_save_router.cdc", ["FlowEVMBridgeAccessor", bridgeAccount.address], serviceAccount ) @@ -254,14 +336,9 @@ fun testDeployERC721Succeeds() { // Get ERC721 & ERC20 deployed contract addresses let evts = Test.eventsOfType(Type()) - Test.assertEqual(6, evts.length) + Test.assertEqual(15, evts.length) + erc721AddressHex = getEVMAddressHexFromEvents(evts, idx: 14) - let erc721DeploymentEvent = evts[5] as! EVM.TransactionExecuted - erc721AddressHex = erc721DeploymentEvent.contractAddress.slice(from: 2, upTo: erc721DeploymentEvent.contractAddress.length).toLower() - - Test.assertEqual(40, erc721AddressHex.length) - - log("ERC721 Address: ".concat(erc721AddressHex)) } access(all) @@ -275,14 +352,9 @@ fun testDeployERC20Succeeds() { // Get ERC721 & ERC20 deployed contract addresses let evts = Test.eventsOfType(Type()) - Test.assertEqual(7, evts.length) - - let erc20DeploymentEvent = evts[6] as! EVM.TransactionExecuted - erc20AddressHex = erc20DeploymentEvent.contractAddress.slice(from: 2, upTo: erc20DeploymentEvent.contractAddress.length).toLower() - - Test.assertEqual(40, erc20AddressHex.length) + Test.assertEqual(16, evts.length) + erc20AddressHex = getEVMAddressHexFromEvents(evts, idx: 15) - log("ERC20 Address: ".concat(erc20AddressHex)) } access(all) @@ -728,7 +800,6 @@ fun testBatchOnboardByEVMAddressSucceeds() { Test.assert(snapshot != 0, message: "Expected snapshot to be taken before onboarding any EVM contracts") Test.reset(to: snapshot) - var erc721RequiresOnboarding = evmAddressRequiresOnboarding(erc721AddressHex) ?? panic("Problem getting onboarding requirement") var erc20RequiresOnboarding = evmAddressRequiresOnboarding(erc20AddressHex) diff --git a/cadence/tests/flow_evm_bridge_utils_tests.cdc b/cadence/tests/flow_evm_bridge_utils_tests.cdc index 0b33c935..aeae6a47 100644 --- a/cadence/tests/flow_evm_bridge_utils_tests.cdc +++ b/cadence/tests/flow_evm_bridge_utils_tests.cdc @@ -96,12 +96,11 @@ fun setup() { ) let evts = Test.eventsOfType(Type()) Test.assertEqual(2, evts.length) - let factoryDeploymentEvent = evts[0] as! EVM.TransactionExecuted - let factoryAddressHex = factoryDeploymentEvent.contractAddress + let factoryAddressHex = getEVMAddressHexFromEvents(evts, idx: 0) err = Test.deployContract( name: "FlowEVMBridgeUtils", path: "../contracts/bridge/FlowEVMBridgeUtils.cdc", - arguments: [factoryAddressHex.slice(from: 2, upTo: factoryAddressHex.length)] + arguments: [factoryAddressHex] ) Test.expect(err, Test.beNil()) } @@ -115,6 +114,15 @@ fun testReducedPrecisionUInt256ToUFix64Succeeds() { Test.assertEqual(ufixAmount, actualUFixAmount) } +access(all) +fun testReducedPrecisionUInt256SmallChangeToUFix64Succeeds() { + let uintAmount: UInt256 = 24_244_814_000_020 + let ufixAmount: UFix64 = 24_244_814.000020 + + let actualUFixAmount = uint256ToUFix64(uintAmount, decimals: 6) + Test.assertEqual(ufixAmount, actualUFixAmount) +} + // Converting from UFix64 to UInt256 with reduced point precision (6 vs. 8) should round down access(all) fun testReducedPrecisionUFix64ToUInt256Succeeds() { @@ -190,12 +198,82 @@ fun testLargeFractionalUInt256ToUFix64Succeeds() { Test.assertEqual(largeFractionalUFixAmount, actualUFixAmount) } +access(all) +fun testLargeFractionalTrailingZerosUInt256ToUFix64Succeeds() { + let largeFractionalUFixAmount: UFix64 = 1.99785982 + let largeFractionalUIntAmount: UInt256 = 1_997_859_829_999_000_000 + + let actualUFixAmount = uint256ToUFix64(largeFractionalUIntAmount, decimals: 18) + Test.assertEqual(largeFractionalUFixAmount, actualUFixAmount) +} + access(all) fun testlargeFractionalUFix64ToUInt256Succeeds() { let largeFractionalUFixAmount: UFix64 = 1.99785982 let largeFractionalUIntAmount: UInt256 = 1_997_859_820_000_000_000 - // let largeFractionalUIntAmount: UInt256 = 1,997,859,820,000,000,000 let actualUIntAmount = ufix64ToUInt256(largeFractionalUFixAmount, decimals: 18) Test.assertEqual(largeFractionalUIntAmount, actualUIntAmount) } + +access(all) +fun testIntegerAndLeadingZeroFractionalUInt256ToUFix64Succeeds() { + let ufixAmount: UFix64 = 100.00000500 + let uintAmount: UInt256 = 100_000_005_000_000_888_999 + + let actualUFixAmount = uint256ToUFix64(uintAmount, decimals: 18) + Test.assertEqual(ufixAmount, actualUFixAmount) +} + +access(all) +fun testIntegerAndLeadingZeroFractionalUFix64ToUInt256Succeeds() { + let ufixAmount: UFix64 = 100.00000500 + let uintAmount: UInt256 = 100_000_005_000_000_000_000 + + let actualUIntAmount = ufix64ToUInt256(ufixAmount, decimals: 18) + Test.assertEqual(uintAmount, actualUIntAmount) +} + +access(all) +fun testMaxUFix64ToUInt256Succeeds() { + let ufixAmount: UFix64 = UFix64.max + let uintAmount: UInt256 = 184467440737_095516150000000000 + + let actualUIntAmount = ufix64ToUInt256(ufixAmount, decimals: 18) + + Test.assertEqual(uintAmount, actualUIntAmount) +} + +access(all) +fun testMaxUFix64AsUInt256ToUFix64Succeds() { + let ufixAmount: UFix64 = UFix64.max + var uintAmount: UInt256 = 184467440737_095516150000000000 + + let actualUFixAmount = uint256ToUFix64(uintAmount, decimals: 18) + + Test.assertEqual(ufixAmount, actualUFixAmount) +} + +access(all) +fun testFractionalPartMaxUFix64AsUInt256ToUFix64Fails() { + let ufixAmount: UFix64 = UFix64.max + var uintAmount: UInt256 = 184467440737_095_516_150_000_000_000 + 10_000_000_000 + + let convertedResult = executeScript( + "../scripts/utils/uint256_to_ufix64.cdc", + [uintAmount, UInt8(18)] + ) + Test.expect(convertedResult, Test.beFailed()) +} + +access(all) +fun testIntegerPartMaxUFix64AsUInt256ToUFix64Fails() { + let ufixAmount: UFix64 = UFix64.max + var uintAmount: UInt256 = 184467440737_095_516_150_000_000_000 + 100_000_000_000_000_000_000_000 + + let convertedResult = executeScript( + "../scripts/utils/uint256_to_ufix64.cdc", + [uintAmount, UInt8(18)] + ) + Test.expect(convertedResult, Test.beFailed()) +} diff --git a/cadence/tests/test_helpers.cdc b/cadence/tests/test_helpers.cdc index 610370a8..af8e9c1a 100644 --- a/cadence/tests/test_helpers.cdc +++ b/cadence/tests/test_helpers.cdc @@ -5,12 +5,19 @@ import "NonFungibleToken" import "ExampleNFT" import "ExampleToken" import "FlowStorageFees" +import "EVM" /// This file contains constants for contract code which is used for bridge suite configuration. /// See the python util `get_code_hex.py` to retrieve the hex-encoded Cadence either with or /// without a separator (`{{CONTRACT_NAME}}` used in templates to "chunk" template code). -access(all) let compiledFactoryBytecode = "608060405234801561001057600080fd5b50338061003757604051631e4fbdf760e01b81526000600482015260240160405180910390fd5b61004081610046565b50610096565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b61484a806100a56000396000f3fe60806040523480156200001157600080fd5b5060043610620000c35760003560e01c8063715018a6116200007a578063715018a6146200018f5780638da5cb5b146200019b578063d56e0ccf14620001ad578063daa09e5414620001e4578063f2fde38b14620001fb578063f93241dd146200021257600080fd5b806304433bbc14620000c85780630a2c0ce914620000fc578063263e0c1b1462000122578063335f4c76146200014a57806340f8d42b146200016157806361a169051462000178575b600080fd5b620000df620000d936600462000c0a565b62000229565b6040516001600160a01b0390911681526020015b60405180910390f35b620001136200010d36600462000c4b565b6200025c565b604051620000f3919062000cd1565b620001396200013336600462000c4b565b62000310565b6040519015158152602001620000f3565b620001396200015b36600462000c4b565b62000724565b620000df6200017236600462000ce6565b62000752565b620000df6200018936600462000ce6565b62000853565b6200019962000942565b005b6000546001600160a01b0316620000df565b620000df620001be36600462000c0a565b80516020818301810180516001825292820191909301209152546001600160a01b031681565b62000139620001f536600462000c4b565b6200095a565b620001996200020c36600462000c4b565b620009da565b620001136200022336600462000c4b565b62000a22565b60006001826040516200023d919062000dc8565b908152604051908190036020019020546001600160a01b031692915050565b6001600160a01b0381166000908152600260205260409020805460609190620002859062000de6565b80601f0160208091040260200160405190810160405280929190818152602001828054620002b39062000de6565b8015620003045780601f10620002d85761010080835404028352916020019162000304565b820191906000526020600020905b815481529060010190602001808311620002e657829003601f168201915b50505050509050919050565b60408051600481526024810182526020810180516001600160e01b03166318160ddd60e01b1790529051600091829182916001600160a01b0386169162000358919062000dc8565b600060405180830381855afa9150503d806000811462000395576040519150601f19603f3d011682016040523d82523d6000602084013e6200039a565b606091505b5091509150811580620003ac57508051155b15620003bc575060009392505050565b604051600060248201526001600160a01b0385169060440160408051601f198184030181529181526020820180516001600160e01b03166370a0823160e01b179052516200040b919062000dc8565b600060405180830381855afa9150503d806000811462000448576040519150601f19603f3d011682016040523d82523d6000602084013e6200044d565b606091505b5090925090508115806200046057508051155b1562000470575060009392505050565b60405160006024820181905260448201526001600160a01b0385169060640160408051601f198184030181529181526020820180516001600160e01b0316636eb1769f60e11b17905251620004c6919062000dc8565b600060405180830381855afa9150503d806000811462000503576040519150601f19603f3d011682016040523d82523d6000602084013e62000508565b606091505b5090925090508115806200051b57508051155b156200052b575060009392505050565b60408051600481526024810182526020810180516001600160e01b03166306fdde0360e01b17905290516001600160a01b038616916200056b9162000dc8565b600060405180830381855afa9150503d8060008114620005a8576040519150601f19603f3d011682016040523d82523d6000602084013e620005ad565b606091505b509092509050811580620005c057508051155b15620005d0575060009392505050565b60408051600481526024810182526020810180516001600160e01b03166395d89b4160e01b17905290516001600160a01b03861691620006109162000dc8565b600060405180830381855afa9150503d80600081146200064d576040519150601f19603f3d011682016040523d82523d6000602084013e62000652565b606091505b5090925090508115806200066557508051155b1562000675575060009392505050565b60408051600481526024810182526020810180516001600160e01b031663313ce56760e01b17905290516001600160a01b03861691620006b59162000dc8565b600060405180830381855afa9150503d8060008114620006f2576040519150601f19603f3d011682016040523d82523d6000602084013e620006f7565b606091505b5090925090508115806200070a57508051155b156200071a575060009392505050565b5060019392505050565b6001600160a01b03811660009081526002602052604081208054620007499062000de6565b15159392505050565b60006200075e62000ac4565b600080546001600160a01b031687878787876040516200077e9062000b43565b6200078f9695949392919062000e22565b604051809103906000f080158015620007ac573d6000803e3d6000fd5b50905080600185604051620007c2919062000dc8565b908152604080516020928190038301902080546001600160a01b0319166001600160a01b03948516179055918316600090815260029091522062000807858262000f00565b507f99a64021330f1af36b3fd5f64a1d12b99b8ddf91fa553618c4df01ffba4c1cee81888888886040516200084195949392919062000fcd565b60405180910390a19695505050505050565b60006200085f62000ac4565b600080546001600160a01b031687878787876040516200087f9062000b51565b620008909695949392919062000e22565b604051809103906000f080158015620008ad573d6000803e3d6000fd5b50905080600185604051620008c3919062000dc8565b908152604080516020928190038301902080546001600160a01b0319166001600160a01b03948516179055918316600090815260029091522062000908858262000f00565b507fbebce54951ebf20c0dcd195a45bb2388d9ac8e38b5974e00bb63c5822dbe65f081888888886040516200084195949392919062000fcd565b6200094c62000ac4565b62000958600062000af3565b565b6040516301ffc9a760e01b81526380ac58cd60e01b60048201526000906001600160a01b038316906301ffc9a790602401602060405180830381865afa925050508015620009c7575060408051601f3d908101601f19168201909252620009c4918101906200103f565b60015b620009d457506000919050565b92915050565b620009e462000ac4565b6001600160a01b03811662000a1457604051631e4fbdf760e01b8152600060048201526024015b60405180910390fd5b62000a1f8162000af3565b50565b6002602052600090815260409020805462000a3d9062000de6565b80601f016020809104026020016040519081016040528092919081815260200182805462000a6b9062000de6565b801562000abc5780601f1062000a905761010080835404028352916020019162000abc565b820191906000526020600020905b81548152906001019060200180831162000a9e57829003601f168201915b505050505081565b6000546001600160a01b03163314620009585760405163118cdaa760e01b815233600482015260240162000a0b565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6118fa806200106483390190565b611eb7806200295e83390190565b634e487b7160e01b600052604160045260246000fd5b600082601f83011262000b8757600080fd5b813567ffffffffffffffff8082111562000ba55762000ba562000b5f565b604051601f8301601f19908116603f0116810190828211818310171562000bd05762000bd062000b5f565b8160405283815286602085880101111562000bea57600080fd5b836020870160208301376000602085830101528094505050505092915050565b60006020828403121562000c1d57600080fd5b813567ffffffffffffffff81111562000c3557600080fd5b62000c438482850162000b75565b949350505050565b60006020828403121562000c5e57600080fd5b81356001600160a01b038116811462000c7657600080fd5b9392505050565b60005b8381101562000c9a57818101518382015260200162000c80565b50506000910152565b6000815180845262000cbd81602086016020860162000c7d565b601f01601f19169290920160200192915050565b60208152600062000c76602083018462000ca3565b600080600080600060a0868803121562000cff57600080fd5b853567ffffffffffffffff8082111562000d1857600080fd5b62000d2689838a0162000b75565b9650602088013591508082111562000d3d57600080fd5b62000d4b89838a0162000b75565b9550604088013591508082111562000d6257600080fd5b62000d7089838a0162000b75565b9450606088013591508082111562000d8757600080fd5b62000d9589838a0162000b75565b9350608088013591508082111562000dac57600080fd5b5062000dbb8882890162000b75565b9150509295509295909350565b6000825162000ddc81846020870162000c7d565b9190910192915050565b600181811c9082168062000dfb57607f821691505b60208210810362000e1c57634e487b7160e01b600052602260045260246000fd5b50919050565b6001600160a01b038716815260c06020820181905260009062000e489083018862000ca3565b828103604084015262000e5c818862000ca3565b9050828103606084015262000e72818762000ca3565b9050828103608084015262000e88818662000ca3565b905082810360a084015262000e9e818562000ca3565b9998505050505050505050565b601f82111562000efb576000816000526020600020601f850160051c8101602086101562000ed65750805b601f850160051c820191505b8181101562000ef75782815560010162000ee2565b5050505b505050565b815167ffffffffffffffff81111562000f1d5762000f1d62000b5f565b62000f358162000f2e845462000de6565b8462000eab565b602080601f83116001811462000f6d576000841562000f545750858301515b600019600386901b1c1916600185901b17855562000ef7565b600085815260208120601f198616915b8281101562000f9e5788860151825594840194600190910190840162000f7d565b508582101562000fbd5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6001600160a01b038616815260a06020820181905260009062000ff39083018762000ca3565b828103604084015262001007818762000ca3565b905082810360608401526200101d818662000ca3565b9050828103608084015262001033818562000ca3565b98975050505050505050565b6000602082840312156200105257600080fd5b8151801515811462000c7657600080fdfe6101606040523480156200001257600080fd5b50604051620018fa380380620018fa833981016040819052620000359162000357565b6040805180820190915260018152603160f81b6020820152859081908882886003620000628382620004db565b506004620000718282620004db565b5050506001600160a01b038116620000a457604051631e4fbdf760e01b8152600060048201526024015b60405180910390fd5b620000af816200019f565b50620000bd826006620001f1565b61012052620000ce816007620001f1565b61014052815160208084019190912060e052815190820120610100524660a0526200015c60e05161010051604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201529081019290925260608201524660808201523060a082015260009060c00160405160208183030381529060405280519060200120905090565b60805250503060c052506009620001748482620004db565b50600a620001838382620004db565b50600b620001928282620004db565b5050505050505062000601565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6000602083511015620002115762000209836200022a565b905062000224565b816200021e8482620004db565b5060ff90505b92915050565b600080829050601f8151111562000258578260405163305a27a960e01b81526004016200009b9190620005a7565b80516200026582620005dc565b179392505050565b80516001600160a01b03811681146200028557600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60005b83811015620002bd578181015183820152602001620002a3565b50506000910152565b600082601f830112620002d857600080fd5b81516001600160401b0380821115620002f557620002f56200028a565b604051601f8301601f19908116603f011681019082821181831017156200032057620003206200028a565b816040528381528660208588010111156200033a57600080fd5b6200034d846020830160208901620002a0565b9695505050505050565b60008060008060008060c087890312156200037157600080fd5b6200037c876200026d565b60208801519096506001600160401b03808211156200039a57600080fd5b620003a88a838b01620002c6565b96506040890151915080821115620003bf57600080fd5b620003cd8a838b01620002c6565b95506060890151915080821115620003e457600080fd5b620003f28a838b01620002c6565b945060808901519150808211156200040957600080fd5b620004178a838b01620002c6565b935060a08901519150808211156200042e57600080fd5b506200043d89828a01620002c6565b9150509295509295509295565b600181811c908216806200045f57607f821691505b6020821081036200048057634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115620004d6576000816000526020600020601f850160051c81016020861015620004b15750805b601f850160051c820191505b81811015620004d257828155600101620004bd565b5050505b505050565b81516001600160401b03811115620004f757620004f76200028a565b6200050f816200050884546200044a565b8462000486565b602080601f8311600181146200054757600084156200052e5750858301515b600019600386901b1c1916600185901b178555620004d2565b600085815260208120601f198616915b82811015620005785788860151825594840194600190910190840162000557565b5085821015620005975787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6020815260008251806020840152620005c8816040850160208701620002a0565b601f01601f19169190910160400192915050565b80516020808301519190811015620004805760001960209190910360031b1b16919050565b60805160a05160c05160e05161010051610120516101405161129e6200065c6000396000610a8801526000610a5b01526000610918015260006108f00152600061084b015260006108750152600061089f015261129e6000f3fe608060405234801561001057600080fd5b50600436106101735760003560e01c8063715018a6116100de578063a76b4d5611610097578063dc9716eb11610071578063dc9716eb146102f8578063dd62ed3e14610300578063e8a3d48514610339578063f2fde38b1461034157600080fd5b8063a76b4d56146102ca578063a9059cbb146102d2578063d505accf146102e557600080fd5b8063715018a61461025e57806379cc6790146102665780637ecebe001461027957806384b0196e1461028c5780638da5cb5b146102a757806395d89b41146102c257600080fd5b8063313ce56711610130578063313ce567146101ee5780633644e515146101fd5780633fd4d4a81461020557806340c10f191461020d57806342966c681461022257806370a082311461023557600080fd5b806306fdde0314610178578063095ea7b3146101965780630cd9acb7146101b9578063120a88ad146101c157806318160ddd146101c957806323b872dd146101db575b600080fd5b610180610354565b60405161018d9190610fe8565b60405180910390f35b6101a96101a436600461101e565b6103e6565b604051901515815260200161018d565b610180610400565b61018061048e565b6002545b60405190815260200161018d565b6101a96101e9366004611048565b61049d565b6040516012815260200161018d565b6101cd6104c1565b6101806104d0565b61022061021b36600461101e565b6104df565b005b610220610230366004611084565b6104f5565b6101cd61024336600461109d565b6001600160a01b031660009081526020819052604090205490565b610220610502565b61022061027436600461101e565b610516565b6101cd61028736600461109d565b61052b565b610294610549565b60405161018d97969594939291906110b8565b6005546040516001600160a01b03909116815260200161018d565b61018061058f565b61018061059e565b6101a96102e036600461101e565b6105ab565b6102206102f3366004611151565b6105b9565b6101806106f8565b6101cd61030e3660046111c4565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b610180610705565b61022061034f36600461109d565b610714565b606060038054610363906111f7565b80601f016020809104026020016040519081016040528092919081815260200182805461038f906111f7565b80156103dc5780601f106103b1576101008083540402835291602001916103dc565b820191906000526020600020905b8154815290600101906020018083116103bf57829003601f168201915b5050505050905090565b6000336103f481858561074f565b60019150505b92915050565b6009805461040d906111f7565b80601f0160208091040260200160405190810160405280929190818152602001828054610439906111f7565b80156104865780601f1061045b57610100808354040283529160200191610486565b820191906000526020600020905b81548152906001019060200180831161046957829003601f168201915b505050505081565b606060098054610363906111f7565b6000336104ab858285610761565b6104b68585856107df565b506001949350505050565b60006104cb61083e565b905090565b6060600a8054610363906111f7565b6104e7610969565b6104f18282610996565b5050565b6104ff33826109cc565b50565b61050a610969565b6105146000610a02565b565b610521823383610761565b6104f182826109cc565b6001600160a01b0381166000908152600860205260408120546103fa565b60006060806000806000606061055d610a54565b610565610a81565b60408051600080825260208201909252600f60f81b9b939a50919850469750309650945092509050565b606060048054610363906111f7565b600b805461040d906111f7565b6000336103f48185856107df565b834211156105e25760405163313c898160e11b8152600481018590526024015b60405180910390fd5b60007f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c988888861062f8c6001600160a01b0316600090815260086020526040902080546001810190915590565b6040805160208101969096526001600160a01b0394851690860152929091166060840152608083015260a082015260c0810186905260e001604051602081830303815290604052805190602001209050600061068a82610aae565b9050600061069a82878787610adb565b9050896001600160a01b0316816001600160a01b0316146106e1576040516325c0072360e11b81526001600160a01b0380831660048301528b1660248201526044016105d9565b6106ec8a8a8a61074f565b50505050505050505050565b600a805461040d906111f7565b6060600b8054610363906111f7565b61071c610969565b6001600160a01b03811661074657604051631e4fbdf760e01b8152600060048201526024016105d9565b6104ff81610a02565b61075c8383836001610b09565b505050565b6001600160a01b0383811660009081526001602090815260408083209386168352929052205460001981146107d957818110156107ca57604051637dc7a0d960e11b81526001600160a01b038416600482015260248101829052604481018390526064016105d9565b6107d984848484036000610b09565b50505050565b6001600160a01b03831661080957604051634b637e8f60e11b8152600060048201526024016105d9565b6001600160a01b0382166108335760405163ec442f0560e01b8152600060048201526024016105d9565b61075c838383610bde565b6000306001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614801561089757507f000000000000000000000000000000000000000000000000000000000000000046145b156108c157507f000000000000000000000000000000000000000000000000000000000000000090565b6104cb604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201527f0000000000000000000000000000000000000000000000000000000000000000918101919091527f000000000000000000000000000000000000000000000000000000000000000060608201524660808201523060a082015260009060c00160405160208183030381529060405280519060200120905090565b6005546001600160a01b031633146105145760405163118cdaa760e01b81523360048201526024016105d9565b6001600160a01b0382166109c05760405163ec442f0560e01b8152600060048201526024016105d9565b6104f160008383610bde565b6001600160a01b0382166109f657604051634b637e8f60e11b8152600060048201526024016105d9565b6104f182600083610bde565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b60606104cb7f00000000000000000000000000000000000000000000000000000000000000006006610d08565b60606104cb7f00000000000000000000000000000000000000000000000000000000000000006007610d08565b60006103fa610abb61083e565b8360405161190160f01b8152600281019290925260228201526042902090565b600080600080610aed88888888610db3565b925092509250610afd8282610e82565b50909695505050505050565b6001600160a01b038416610b335760405163e602df0560e01b8152600060048201526024016105d9565b6001600160a01b038316610b5d57604051634a1406b160e11b8152600060048201526024016105d9565b6001600160a01b03808516600090815260016020908152604080832093871683529290522082905580156107d957826001600160a01b0316846001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92584604051610bd091815260200190565b60405180910390a350505050565b6001600160a01b038316610c09578060026000828254610bfe9190611231565b90915550610c7b9050565b6001600160a01b03831660009081526020819052604090205481811015610c5c5760405163391434e360e21b81526001600160a01b038516600482015260248101829052604481018390526064016105d9565b6001600160a01b03841660009081526020819052604090209082900390555b6001600160a01b038216610c9757600280548290039055610cb6565b6001600160a01b03821660009081526020819052604090208054820190555b816001600160a01b0316836001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef83604051610cfb91815260200190565b60405180910390a3505050565b606060ff8314610d2257610d1b83610f3b565b90506103fa565b818054610d2e906111f7565b80601f0160208091040260200160405190810160405280929190818152602001828054610d5a906111f7565b8015610da75780601f10610d7c57610100808354040283529160200191610da7565b820191906000526020600020905b815481529060010190602001808311610d8a57829003601f168201915b505050505090506103fa565b600080807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0841115610dee5750600091506003905082610e78565b604080516000808252602082018084528a905260ff891692820192909252606081018790526080810186905260019060a0016020604051602081039080840390855afa158015610e42573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116610e6e57506000925060019150829050610e78565b9250600091508190505b9450945094915050565b6000826003811115610e9657610e96611252565b03610e9f575050565b6001826003811115610eb357610eb3611252565b03610ed15760405163f645eedf60e01b815260040160405180910390fd5b6002826003811115610ee557610ee5611252565b03610f065760405163fce698f760e01b8152600481018290526024016105d9565b6003826003811115610f1a57610f1a611252565b036104f1576040516335e2f38360e21b8152600481018290526024016105d9565b60606000610f4883610f7a565b604080516020808252818301909252919250600091906020820181803683375050509182525060208101929092525090565b600060ff8216601f8111156103fa57604051632cd44ac360e21b815260040160405180910390fd5b6000815180845260005b81811015610fc857602081850181015186830182015201610fac565b506000602082860101526020601f19601f83011685010191505092915050565b602081526000610ffb6020830184610fa2565b9392505050565b80356001600160a01b038116811461101957600080fd5b919050565b6000806040838503121561103157600080fd5b61103a83611002565b946020939093013593505050565b60008060006060848603121561105d57600080fd5b61106684611002565b925061107460208501611002565b9150604084013590509250925092565b60006020828403121561109657600080fd5b5035919050565b6000602082840312156110af57600080fd5b610ffb82611002565b60ff60f81b881681526000602060e060208401526110d960e084018a610fa2565b83810360408501526110eb818a610fa2565b606085018990526001600160a01b038816608086015260a0850187905284810360c08601528551808252602080880193509091019060005b8181101561113f57835183529284019291840191600101611123565b50909c9b505050505050505050505050565b600080600080600080600060e0888a03121561116c57600080fd5b61117588611002565b965061118360208901611002565b95506040880135945060608801359350608088013560ff811681146111a757600080fd5b9699959850939692959460a0840135945060c09093013592915050565b600080604083850312156111d757600080fd5b6111e083611002565b91506111ee60208401611002565b90509250929050565b600181811c9082168061120b57607f821691505b60208210810361122b57634e487b7160e01b600052602260045260246000fd5b50919050565b808201808211156103fa57634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052602160045260246000fdfea26469706673582212205a8199658d4eaad2b10696323e0bc0215d35ed43fe73c3637316e44e6d8ca31864736f6c6343000817003360806040523480156200001157600080fd5b5060405162001eb738038062001eb7833981016040819052620000349162000202565b858585600062000045838262000386565b50600162000054828262000386565b5050506001600160a01b0381166200008657604051631e4fbdf760e01b81526000600482015260240160405180910390fd5b6200009181620000cb565b50600c620000a0848262000386565b50600d620000af838262000386565b50600e620000be828262000386565b5050505050505062000452565b600b80546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b80516001600160a01b03811681146200013557600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126200016257600080fd5b81516001600160401b03808211156200017f576200017f6200013a565b604051601f8301601f19908116603f01168101908282118183101715620001aa57620001aa6200013a565b8160405283815260209250866020858801011115620001c857600080fd5b600091505b83821015620001ec5785820183015181830184015290820190620001cd565b6000602085830101528094505050505092915050565b60008060008060008060c087890312156200021c57600080fd5b62000227876200011d565b60208801519096506001600160401b03808211156200024557600080fd5b620002538a838b0162000150565b965060408901519150808211156200026a57600080fd5b620002788a838b0162000150565b955060608901519150808211156200028f57600080fd5b6200029d8a838b0162000150565b94506080890151915080821115620002b457600080fd5b620002c28a838b0162000150565b935060a0890151915080821115620002d957600080fd5b50620002e889828a0162000150565b9150509295509295509295565b600181811c908216806200030a57607f821691505b6020821081036200032b57634e487b7160e01b600052602260045260246000fd5b50919050565b601f82111562000381576000816000526020600020601f850160051c810160208610156200035c5750805b601f850160051c820191505b818110156200037d5782815560010162000368565b5050505b505050565b81516001600160401b03811115620003a257620003a26200013a565b620003ba81620003b38454620002f5565b8462000331565b602080601f831160018114620003f25760008415620003d95750858301515b600019600386901b1c1916600185901b1785556200037d565b600085815260208120601f198616915b82811015620004235788860151825594840194600190910190840162000402565b5085821015620004425787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b611a5580620004626000396000f3fe608060405234801561001057600080fd5b50600436106101cf5760003560e01c806370a0823111610104578063a76b4d56116100a2578063cd279c7c11610071578063cd279c7c146103a8578063e8a3d485146103bb578063e985e9c5146103c3578063f2fde38b146103d657600080fd5b8063a76b4d5614610372578063b49bbd941461037a578063b88d4fde14610382578063c87b56dd1461039557600080fd5b806394e29329116100de57806394e293291461034757806395d89b411461034f578063a159047b14610357578063a22cb4651461035f57600080fd5b806370a082311461031b578063715018a61461032e5780638da5cb5b1461033657600080fd5b80632f745c59116101715780634f558e791161014b5780634f558e79146102c25780634f6ccce7146102ed5780635e0a9661146103005780636352211e1461030857600080fd5b80632f745c591461028957806342842e0e1461029c57806342966c68146102af57600080fd5b8063095ea7b3116101ad578063095ea7b31461023c57806318160ddd1461025157806318e97fd11461026357806323b872dd1461027657600080fd5b806301ffc9a7146101d457806306fdde03146101fc578063081812fc14610211575b600080fd5b6101e76101e2366004611494565b6103e9565b60405190151581526020015b60405180910390f35b6102046103fa565b6040516101f39190611501565b61022461021f366004611514565b61048c565b6040516001600160a01b0390911681526020016101f3565b61024f61024a366004611549565b6104b5565b005b6009545b6040519081526020016101f3565b61024f61027136600461161f565b6104c4565b61024f610284366004611666565b6104d6565b610255610297366004611549565b610566565b61024f6102aa366004611666565b6105cb565b61024f6102bd366004611514565b6105eb565b6101e76102d0366004611514565b6000908152600260205260409020546001600160a01b0316151590565b6102556102fb366004611514565b6105f7565b610204610650565b610224610316366004611514565b61065f565b6102556103293660046116a2565b61066a565b61024f6106b2565b600b546001600160a01b0316610224565b6102046106c6565b6102046106d5565b6102046106e4565b61024f61036d3660046116bd565b610772565b61020461077d565b61020461078a565b61024f6103903660046116f9565b610797565b6102046103a3366004611514565b6107ae565b61024f6103b6366004611775565b6107b9565b6102046107d5565b6101e76103d13660046117cc565b6107e4565b61024f6103e43660046116a2565b610812565b60006103f482610850565b92915050565b606060008054610409906117ff565b80601f0160208091040260200160405190810160405280929190818152602001828054610435906117ff565b80156104825780601f1061045757610100808354040283529160200191610482565b820191906000526020600020905b81548152906001019060200180831161046557829003601f168201915b5050505050905090565b600061049782610875565b506000828152600460205260409020546001600160a01b03166103f4565b6104c08282336108ae565b5050565b6104cc6108bb565b6104c082826108e8565b6001600160a01b03821661050557604051633250574960e11b8152600060048201526024015b60405180910390fd5b6000610512838333610938565b9050836001600160a01b0316816001600160a01b031614610560576040516364283d7b60e01b81526001600160a01b03808616600483015260248201849052821660448201526064016104fc565b50505050565b60006105718361066a565b82106105a25760405163295f44f760e21b81526001600160a01b0384166004820152602481018390526044016104fc565b506001600160a01b03919091166000908152600760209081526040808320938352929052205490565b6105e683838360405180602001604052806000815250610797565b505050565b6104c060008233610938565b600061060260095490565b821061062b5760405163295f44f760e21b815260006004820152602481018390526044016104fc565b6009828154811061063e5761063e611839565b90600052602060002001549050919050565b6060600d8054610409906117ff565b60006103f482610875565b60006001600160a01b038216610696576040516322718ad960e21b8152600060048201526024016104fc565b506001600160a01b031660009081526003602052604090205490565b6106ba6108bb565b6106c4600061094d565b565b6060600c8054610409906117ff565b606060018054610409906117ff565b600d80546106f1906117ff565b80601f016020809104026020016040519081016040528092919081815260200182805461071d906117ff565b801561076a5780601f1061073f5761010080835404028352916020019161076a565b820191906000526020600020905b81548152906001019060200180831161074d57829003601f168201915b505050505081565b6104c033838361099f565b600e80546106f1906117ff565b600c80546106f1906117ff565b6107a28484846104d6565b61056084848484610a3e565b60606103f482610b67565b6107c16108bb565b6107cb8383610c70565b6105e682826108e8565b6060600e8054610409906117ff565b6001600160a01b03918216600090815260056020908152604080832093909416825291909152205460ff1690565b61081a6108bb565b6001600160a01b03811661084457604051631e4fbdf760e01b8152600060048201526024016104fc565b61084d8161094d565b50565b60006001600160e01b0319821663780e9d6360e01b14806103f457506103f482610c8a565b6000818152600260205260408120546001600160a01b0316806103f457604051637e27328960e01b8152600481018490526024016104fc565b6105e68383836001610caf565b600b546001600160a01b031633146106c45760405163118cdaa760e01b81523360048201526024016104fc565b6000828152600660205260409020610900828261189f565b506040518281527ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79060200160405180910390a15050565b6000610945848484610db5565b949350505050565b600b80546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6001600160a01b0382166109d157604051630b61174360e31b81526001600160a01b03831660048201526024016104fc565b6001600160a01b03838116600081815260056020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b6001600160a01b0383163b1561056057604051630a85bd0160e11b81526001600160a01b0384169063150b7a0290610a8090339088908790879060040161195f565b6020604051808303816000875af1925050508015610abb575060408051601f3d908101601f19168201909252610ab89181019061199c565b60015b610b24573d808015610ae9576040519150601f19603f3d011682016040523d82523d6000602084013e610aee565b606091505b508051600003610b1c57604051633250574960e11b81526001600160a01b03851660048201526024016104fc565b805181602001fd5b6001600160e01b03198116630a85bd0160e11b14610b6057604051633250574960e11b81526001600160a01b03851660048201526024016104fc565b5050505050565b6060610b7282610875565b5060008281526006602052604081208054610b8c906117ff565b80601f0160208091040260200160405190810160405280929190818152602001828054610bb8906117ff565b8015610c055780601f10610bda57610100808354040283529160200191610c05565b820191906000526020600020905b815481529060010190602001808311610be857829003601f168201915b505050505090506000610c2360408051602081019091526000815290565b90508051600003610c35575092915050565b815115610c67578082604051602001610c4f9291906119b9565b60405160208183030381529060405292505050919050565b61094584610e82565b6104c0828260405180602001604052806000815250610ef7565b60006001600160e01b03198216632483248360e11b14806103f457506103f482610f0e565b8080610cc357506001600160a01b03821615155b15610d85576000610cd384610875565b90506001600160a01b03831615801590610cff5750826001600160a01b0316816001600160a01b031614155b8015610d125750610d1081846107e4565b155b15610d3b5760405163a9fbf51f60e01b81526001600160a01b03841660048201526024016104fc565b8115610d835783856001600160a01b0316826001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45b505b5050600090815260046020526040902080546001600160a01b0319166001600160a01b0392909216919091179055565b600080610dc3858585610f5e565b90506001600160a01b038116610e2057610e1b84600980546000838152600a60205260408120829055600182018355919091527f6e1540171b6c0c960b71a7020d9f60077f6af931a8bbf590da0223dacf75c7af0155565b610e43565b846001600160a01b0316816001600160a01b031614610e4357610e438185611057565b6001600160a01b038516610e5f57610e5a846110e8565b610945565b846001600160a01b0316816001600160a01b031614610945576109458585611197565b6060610e8d82610875565b506000610ea560408051602081019091526000815290565b90506000815111610ec55760405180602001604052806000815250610ef0565b80610ecf846111e7565b604051602001610ee09291906119b9565b6040516020818303038152906040525b9392505050565b610f01838361127a565b6105e66000848484610a3e565b60006001600160e01b031982166380ac58cd60e01b1480610f3f57506001600160e01b03198216635b5e139f60e01b145b806103f457506301ffc9a760e01b6001600160e01b03198316146103f4565b6000828152600260205260408120546001600160a01b0390811690831615610f8b57610f8b8184866112df565b6001600160a01b03811615610fc957610fa8600085600080610caf565b6001600160a01b038116600090815260036020526040902080546000190190555b6001600160a01b03851615610ff8576001600160a01b0385166000908152600360205260409020805460010190555b60008481526002602052604080822080546001600160a01b0319166001600160a01b0389811691821790925591518793918516917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4949350505050565b60006110628361066a565b6000838152600860205260409020549091508082146110b5576001600160a01b03841660009081526007602090815260408083208584528252808320548484528184208190558352600890915290208190555b5060009182526008602090815260408084208490556001600160a01b039094168352600781528383209183525290812055565b6009546000906110fa906001906119e8565b6000838152600a60205260408120546009805493945090928490811061112257611122611839565b90600052602060002001549050806009838154811061114357611143611839565b6000918252602080832090910192909255828152600a9091526040808220849055858252812055600980548061117b5761117b611a09565b6001900381819060005260206000200160009055905550505050565b600060016111a48461066a565b6111ae91906119e8565b6001600160a01b039093166000908152600760209081526040808320868452825280832085905593825260089052919091209190915550565b606060006111f483611343565b600101905060008167ffffffffffffffff81111561121457611214611573565b6040519080825280601f01601f19166020018201604052801561123e576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a850494508461124857509392505050565b6001600160a01b0382166112a457604051633250574960e11b8152600060048201526024016104fc565b60006112b283836000610938565b90506001600160a01b038116156105e6576040516339e3563760e11b8152600060048201526024016104fc565b6112ea83838361141b565b6105e6576001600160a01b03831661131857604051637e27328960e01b8152600481018290526024016104fc565b60405163177e802f60e01b81526001600160a01b0383166004820152602481018290526044016104fc565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b83106113825772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef810000000083106113ae576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc1000083106113cc57662386f26fc10000830492506010015b6305f5e10083106113e4576305f5e100830492506008015b61271083106113f857612710830492506004015b6064831061140a576064830492506002015b600a83106103f45760010192915050565b60006001600160a01b038316158015906109455750826001600160a01b0316846001600160a01b03161480611455575061145584846107e4565b806109455750506000908152600460205260409020546001600160a01b03908116911614919050565b6001600160e01b03198116811461084d57600080fd5b6000602082840312156114a657600080fd5b8135610ef08161147e565b60005b838110156114cc5781810151838201526020016114b4565b50506000910152565b600081518084526114ed8160208601602086016114b1565b601f01601f19169290920160200192915050565b602081526000610ef060208301846114d5565b60006020828403121561152657600080fd5b5035919050565b80356001600160a01b038116811461154457600080fd5b919050565b6000806040838503121561155c57600080fd5b6115658361152d565b946020939093013593505050565b634e487b7160e01b600052604160045260246000fd5b600067ffffffffffffffff808411156115a4576115a4611573565b604051601f8501601f19908116603f011681019082821181831017156115cc576115cc611573565b816040528093508581528686860111156115e557600080fd5b858560208301376000602087830101525050509392505050565b600082601f83011261161057600080fd5b610ef083833560208501611589565b6000806040838503121561163257600080fd5b82359150602083013567ffffffffffffffff81111561165057600080fd5b61165c858286016115ff565b9150509250929050565b60008060006060848603121561167b57600080fd5b6116848461152d565b92506116926020850161152d565b9150604084013590509250925092565b6000602082840312156116b457600080fd5b610ef08261152d565b600080604083850312156116d057600080fd5b6116d98361152d565b9150602083013580151581146116ee57600080fd5b809150509250929050565b6000806000806080858703121561170f57600080fd5b6117188561152d565b93506117266020860161152d565b925060408501359150606085013567ffffffffffffffff81111561174957600080fd5b8501601f8101871361175a57600080fd5b61176987823560208401611589565b91505092959194509250565b60008060006060848603121561178a57600080fd5b6117938461152d565b925060208401359150604084013567ffffffffffffffff8111156117b657600080fd5b6117c2868287016115ff565b9150509250925092565b600080604083850312156117df57600080fd5b6117e88361152d565b91506117f66020840161152d565b90509250929050565b600181811c9082168061181357607f821691505b60208210810361183357634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052603260045260246000fd5b601f8211156105e6576000816000526020600020601f850160051c810160208610156118785750805b601f850160051c820191505b8181101561189757828155600101611884565b505050505050565b815167ffffffffffffffff8111156118b9576118b9611573565b6118cd816118c784546117ff565b8461184f565b602080601f83116001811461190257600084156118ea5750858301515b600019600386901b1c1916600185901b178555611897565b600085815260208120601f198616915b8281101561193157888601518255948401946001909101908401611912565b508582101561194f5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6001600160a01b0385811682528416602082015260408101839052608060608201819052600090611992908301846114d5565b9695505050505050565b6000602082840312156119ae57600080fd5b8151610ef08161147e565b600083516119cb8184602088016114b1565b8351908301906119df8183602088016114b1565b01949350505050565b818103818111156103f457634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052603160045260246000fdfea26469706673582212206ebc33968f0bb2aac75fa88729c43c34a634938367a10e417cf26ce7e65b108764736f6c63430008170033a2646970667358221220a26f238ed62e7e34bbbb8acd7b64f9737843d19754822adfb4ce059e7e1743e064736f6c63430008170033" +access(all) let compiledFactoryBytecode = "608060405234801561001057600080fd5b50338061003757604051631e4fbdf760e01b81526000600482015260240160405180910390fd5b61004081610046565b50610096565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b611452806100a56000396000f3fe608060405234801561001057600080fd5b50600436106101005760003560e01c8063aff51c3e11610097578063daa09e5411610066578063daa09e5414610216578063db6d56cd14610229578063dfe1ac361461023c578063f2fde38b1461024f57600080fd5b8063aff51c3e146101bd578063b3d5dbdc146101d0578063cc435bf3146101f0578063d974d2381461020357600080fd5b806366cd5014116100d357806366cd50141461017e578063715018a61461019157806383843c9e146101995780638da5cb5b146101ac57600080fd5b806304433bbc1461010557806314902ad314610135578063263e0c1b1461014a5780635ab1bd531461016d575b600080fd5b610118610113366004611067565b610262565b6040516001600160a01b0390911681526020015b60405180910390f35b6101486101433660046110b9565b6102da565b005b61015d6101583660046110b9565b610354565b604051901515815260200161012c565b6001546001600160a01b0316610118565b61011861018c366004611067565b610744565b610148610775565b6101486101a7366004611067565b610789565b6000546001600160a01b0316610118565b6101486101cb3660046110d6565b61088b565b6101e36101de3660046110b9565b6109a4565b60405161012c9190611178565b61015d6101fe3660046110b9565b610a17565b6101486102113660046110d6565b610a37565b61015d6102243660046110b9565b610b08565b61011861023736600461118b565b610b7e565b61015d61024a3660046110b9565b610c53565b61014861025d3660046110b9565b610cc2565b600154604051630110ceef60e21b81526000916001600160a01b0316906304433bbc90610293908590600401611178565b602060405180830381865afa1580156102b0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102d49190611280565b92915050565b6102e2610d00565b6102eb81610d2d565b600154604080516001600160a01b03928316815291831660208301527f61dad6e94cd5c0b65c9265246706a09bd0d11d5330f3e6b659d328151a664e8c910160405180910390a1600180546001600160a01b0319166001600160a01b0392909216919091179055565b60408051600481526024810182526020810180516001600160e01b03166318160ddd60e01b1790529051600091829182916001600160a01b0386169161039a919061129d565b600060405180830381855afa9150503d80600081146103d5576040519150601f19603f3d011682016040523d82523d6000602084013e6103da565b606091505b50915091508115806103eb57508051155b156103fa575060009392505050565b604051600060248201526001600160a01b0385169060440160408051601f198184030181529181526020820180516001600160e01b03166370a0823160e01b17905251610447919061129d565b600060405180830381855afa9150503d8060008114610482576040519150601f19603f3d011682016040523d82523d6000602084013e610487565b606091505b50909250905081158061049957508051155b156104a8575060009392505050565b60405160006024820181905260448201526001600160a01b0385169060640160408051601f198184030181529181526020820180516001600160e01b0316636eb1769f60e11b179052516104fc919061129d565b600060405180830381855afa9150503d8060008114610537576040519150601f19603f3d011682016040523d82523d6000602084013e61053c565b606091505b50909250905081158061054e57508051155b1561055d575060009392505050565b60408051600481526024810182526020810180516001600160e01b03166306fdde0360e01b17905290516001600160a01b0386169161059b9161129d565b600060405180830381855afa9150503d80600081146105d6576040519150601f19603f3d011682016040523d82523d6000602084013e6105db565b606091505b5090925090508115806105ed57508051155b156105fc575060009392505050565b60408051600481526024810182526020810180516001600160e01b03166395d89b4160e01b17905290516001600160a01b0386169161063a9161129d565b600060405180830381855afa9150503d8060008114610675576040519150601f19603f3d011682016040523d82523d6000602084013e61067a565b606091505b50909250905081158061068c57508051155b1561069b575060009392505050565b60408051600481526024810182526020810180516001600160e01b031663313ce56760e01b17905290516001600160a01b038616916106d99161129d565b600060405180830381855afa9150503d8060008114610714576040519150601f19603f3d011682016040523d82523d6000602084013e610719565b606091505b50909250905081158061072b57508051155b1561073a575060009392505050565b5060019392505050565b6000600282604051610756919061129d565b908152604051908190036020019020546001600160a01b031692915050565b61077d610d00565b6107876000610d9f565b565b610791610d00565b60006002826040516107a3919061129d565b908152604051908190036020019020546001600160a01b03169050806108235760405162461bcd60e51b815260206004820152602a60248201527f466c6f77427269646765466163746f72793a204465706c6f796572206e6f74206044820152691c9959da5cdd195c995960b21b60648201526084015b60405180910390fd5b600282604051610833919061129d565b90815260405190819003602001812080546001600160a01b03191690557f03c7566b5f4959b890c1a6d38f39df053c6737c9965d9c0ddf612c86100a838b9061087f90849084906112b9565b60405180910390a15050565b610893610d00565b61089c81610def565b60006001600160a01b03166002836040516108b7919061129d565b908152604051908190036020019020546001600160a01b0316146109345760405162461bcd60e51b815260206004820152602e60248201527f466c6f77427269646765466163746f72793a204465706c6f79657220616c726560448201526d18591e481c9959da5cdd195c995960921b606482015260840161081a565b80600283604051610945919061129d565b90815260405190819003602001812080546001600160a01b03939093166001600160a01b0319909316929092179091557fc0c30f085f0b1397c8bf23f8b851b63b33e13d11832b8320a37fca1c07dcb40f9061087f90849084906112b9565b600154604051632cf576f760e21b81526001600160a01b038381166004830152606092169063b3d5dbdc90602401600060405180830381865afa1580156109ef573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526102d491908101906112e3565b6000610a2282610b08565b1515610a2d83610354565b1515141592915050565b610a3f610d00565b610a4881610def565b6000600283604051610a5a919061129d565b908152604051908190036020019020546001600160a01b0316905080610a8957610a84838361088b565b505050565b81600284604051610a9a919061129d565b90815260405190819003602001812080546001600160a01b03939093166001600160a01b0319909316929092179091557f848576f8a081c5af60d89f0215c8af528186670eefd6349c05014d5b2268864690610afb9085908490869061135a565b60405180910390a1505050565b6040516301ffc9a760e01b81526380ac58cd60e01b60048201526000906001600160a01b038316906301ffc9a790602401602060405180830381865afa925050508015610b72575060408051601f3d908101601f19168201909252610b6f9181019061138d565b60015b6102d457506000919050565b6000610b88610d00565b6000600288604051610b9a919061129d565b908152604051908190036020019020546001600160a01b03169050610bbe81610def565b60405163476d399760e01b815281906000906001600160a01b0383169063476d399790610bf7908c908c908c908c908c906004016113af565b6020604051808303816000875af1158015610c16573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c3a9190611280565b9050610c468682610e61565b9998505050505050505050565b60015460405163a6de610560e01b81526001600160a01b038381166004830152600092169063a6de610590602401602060405180830381865afa158015610c9e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102d4919061138d565b610cca610d00565b6001600160a01b038116610cf457604051631e4fbdf760e01b81526000600482015260240161081a565b610cfd81610d9f565b50565b6000546001600160a01b031633146107875760405163118cdaa760e01b815233600482015260240161081a565b610d3681610ecc565b610d478163976998cb60e01b610f22565b610cfd5760405162461bcd60e51b815260206004820152602360248201527f466c6f77427269646765466163746f72793a20496e76616c696420726567697360448201526274727960e81b606482015260840161081a565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b610df881610ecc565b610e098163476d399760e01b610f22565b610cfd5760405162461bcd60e51b815260206004820152602360248201527f466c6f77427269646765466163746f72793a20496e76616c6964206465706c6f6044820152623cb2b960e91b606482015260840161081a565b60015460405163522791d160e01b81526001600160a01b0390911690819063522791d190610e9590869086906004016112b9565b600060405180830381600087803b158015610eaf57600080fd5b505af1158015610ec3573d6000803e3d6000fd5b50505050505050565b6001600160a01b038116610cfd5760405162461bcd60e51b815260206004820152601f60248201527f466c6f77427269646765466163746f72793a205a65726f206164647265737300604482015260640161081a565b6040516301ffc9a760e01b81526001600160e01b0319821660048201526000906001600160a01b038416906301ffc9a790602401602060405180830381865afa925050508015610f8f575060408051601f3d908101601f19168201909252610f8c9181019061138d565b60015b610f9b575060006102d4565b9392505050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715610fe157610fe1610fa2565b604052919050565b600067ffffffffffffffff82111561100357611003610fa2565b50601f01601f191660200190565b600082601f83011261102257600080fd5b813561103561103082610fe9565b610fb8565b81815284602083860101111561104a57600080fd5b816020850160208301376000918101602001919091529392505050565b60006020828403121561107957600080fd5b813567ffffffffffffffff81111561109057600080fd5b61109c84828501611011565b949350505050565b6001600160a01b0381168114610cfd57600080fd5b6000602082840312156110cb57600080fd5b8135610f9b816110a4565b600080604083850312156110e957600080fd5b823567ffffffffffffffff81111561110057600080fd5b61110c85828601611011565b925050602083013561111d816110a4565b809150509250929050565b60005b8381101561114357818101518382015260200161112b565b50506000910152565b60008151808452611164816020860160208601611128565b601f01601f19169290920160200192915050565b602081526000610f9b602083018461114c565b60008060008060008060c087890312156111a457600080fd5b863567ffffffffffffffff808211156111bc57600080fd5b6111c88a838b01611011565b975060208901359150808211156111de57600080fd5b6111ea8a838b01611011565b9650604089013591508082111561120057600080fd5b61120c8a838b01611011565b9550606089013591508082111561122257600080fd5b61122e8a838b01611011565b9450608089013591508082111561124457600080fd5b6112508a838b01611011565b935060a089013591508082111561126657600080fd5b5061127389828a01611011565b9150509295509295509295565b60006020828403121561129257600080fd5b8151610f9b816110a4565b600082516112af818460208701611128565b9190910192915050565b6040815260006112cc604083018561114c565b905060018060a01b03831660208301529392505050565b6000602082840312156112f557600080fd5b815167ffffffffffffffff81111561130c57600080fd5b8201601f8101841361131d57600080fd5b805161132b61103082610fe9565b81815285602083850101111561134057600080fd5b611351826020830160208601611128565b95945050505050565b60608152600061136d606083018661114c565b6001600160a01b0394851660208401529290931660409091015292915050565b60006020828403121561139f57600080fd5b81518015158114610f9b57600080fd5b60a0815260006113c260a083018861114c565b82810360208401526113d4818861114c565b905082810360408401526113e8818761114c565b905082810360608401526113fc818661114c565b90508281036080840152611410818561114c565b9897505050505050505056fea264697066735822122026be7d4ef13534833344abdcc736e8876603e1f9d3463f0047ddca092a98cc2d64736f6c63430008170033" + +access(all) let erc20DeployerBytecode = "608060405234801561001057600080fd5b50338061003757604051631e4fbdf760e01b81526000600482015260240160405180910390fd5b61004081610046565b50610096565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b612096806100a56000396000f3fe60806040523480156200001157600080fd5b5060043610620000875760003560e01c8063715018a61162000062578063715018a614620000fc5780638da5cb5b1462000108578063ee2d8496146200011a578063f2fde38b146200013157600080fd5b806301ffc9a7146200008c578063476d399714620000b85780636418e6de14620000e8575b600080fd5b620000a36200009d36600462000438565b62000148565b60405190151581526020015b60405180910390f35b620000cf620000c936600462000516565b62000180565b6040516001600160a01b039091168152602001620000af565b600154620000cf906001600160a01b031681565b62000106620002a5565b005b6000546001600160a01b0316620000cf565b620001066200012b366004620005f8565b620002bd565b6200010662000142366004620005f8565b62000367565b60006001600160e01b0319821663476d399760e01b14806200017a57506301ffc9a760e01b6001600160e01b03198316145b92915050565b6001546000906001600160a01b03163314620002095760405162461bcd60e51b815260206004820152603f60248201527f466c6f7745564d4272696467656445524332304465706c6f7965723a204f6e6c60448201527f792064656c656761746564206465706c6f7965722063616e206465706c6f790060648201526084015b60405180910390fd5b600080546001600160a01b0316878787878760405162000229906200042a565b6200023a969594939291906200066b565b604051809103906000f08015801562000257573d6000803e3d6000fd5b5090507f99a64021330f1af36b3fd5f64a1d12b99b8ddf91fa553618c4df01ffba4c1cee818888888860405162000293959493929190620006f4565b60405180910390a19695505050505050565b620002af620003ab565b620002bb6000620003da565b565b620002c7620003ab565b6001600160a01b038116620003455760405162461bcd60e51b815260206004820152603f60248201527f466c6f7745564d4272696467656445524332304465706c6f7965723a20496e7660448201527f616c69642064656c656761746564206465706c6f796572206164647265737300606482015260840162000200565b600180546001600160a01b0319166001600160a01b0392909216919091179055565b62000371620003ab565b6001600160a01b0381166200039d57604051631e4fbdf760e01b81526000600482015260240162000200565b620003a881620003da565b50565b6000546001600160a01b03163314620002bb5760405163118cdaa760e01b815233600482015260240162000200565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6118fa806200076783390190565b6000602082840312156200044b57600080fd5b81356001600160e01b0319811681146200046457600080fd5b9392505050565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126200049357600080fd5b813567ffffffffffffffff80821115620004b157620004b16200046b565b604051601f8301601f19908116603f01168101908282118183101715620004dc57620004dc6200046b565b81604052838152866020858801011115620004f657600080fd5b836020870160208301376000602085830101528094505050505092915050565b600080600080600060a086880312156200052f57600080fd5b853567ffffffffffffffff808211156200054857600080fd5b6200055689838a0162000481565b965060208801359150808211156200056d57600080fd5b6200057b89838a0162000481565b955060408801359150808211156200059257600080fd5b620005a089838a0162000481565b94506060880135915080821115620005b757600080fd5b620005c589838a0162000481565b93506080880135915080821115620005dc57600080fd5b50620005eb8882890162000481565b9150509295509295909350565b6000602082840312156200060b57600080fd5b81356001600160a01b03811681146200046457600080fd5b6000815180845260005b818110156200064b576020818501810151868301820152016200062d565b506000602082860101526020601f19601f83011685010191505092915050565b6001600160a01b038716815260c060208201819052600090620006919083018862000623565b8281036040840152620006a5818862000623565b90508281036060840152620006bb818762000623565b90508281036080840152620006d1818662000623565b905082810360a0840152620006e7818562000623565b9998505050505050505050565b6001600160a01b038616815260a0602082018190526000906200071a9083018762000623565b82810360408401526200072e818762000623565b9050828103606084015262000744818662000623565b905082810360808401526200075a818562000623565b9897505050505050505056fe6101606040523480156200001257600080fd5b50604051620018fa380380620018fa833981016040819052620000359162000357565b6040805180820190915260018152603160f81b6020820152859081908882886003620000628382620004db565b506004620000718282620004db565b5050506001600160a01b038116620000a457604051631e4fbdf760e01b8152600060048201526024015b60405180910390fd5b620000af816200019f565b50620000bd826006620001f1565b61012052620000ce816007620001f1565b61014052815160208084019190912060e052815190820120610100524660a0526200015c60e05161010051604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201529081019290925260608201524660808201523060a082015260009060c00160405160208183030381529060405280519060200120905090565b60805250503060c052506009620001748482620004db565b50600a620001838382620004db565b50600b620001928282620004db565b5050505050505062000601565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6000602083511015620002115762000209836200022a565b905062000224565b816200021e8482620004db565b5060ff90505b92915050565b600080829050601f8151111562000258578260405163305a27a960e01b81526004016200009b9190620005a7565b80516200026582620005dc565b179392505050565b80516001600160a01b03811681146200028557600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60005b83811015620002bd578181015183820152602001620002a3565b50506000910152565b600082601f830112620002d857600080fd5b81516001600160401b0380821115620002f557620002f56200028a565b604051601f8301601f19908116603f011681019082821181831017156200032057620003206200028a565b816040528381528660208588010111156200033a57600080fd5b6200034d846020830160208901620002a0565b9695505050505050565b60008060008060008060c087890312156200037157600080fd5b6200037c876200026d565b60208801519096506001600160401b03808211156200039a57600080fd5b620003a88a838b01620002c6565b96506040890151915080821115620003bf57600080fd5b620003cd8a838b01620002c6565b95506060890151915080821115620003e457600080fd5b620003f28a838b01620002c6565b945060808901519150808211156200040957600080fd5b620004178a838b01620002c6565b935060a08901519150808211156200042e57600080fd5b506200043d89828a01620002c6565b9150509295509295509295565b600181811c908216806200045f57607f821691505b6020821081036200048057634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115620004d6576000816000526020600020601f850160051c81016020861015620004b15750805b601f850160051c820191505b81811015620004d257828155600101620004bd565b5050505b505050565b81516001600160401b03811115620004f757620004f76200028a565b6200050f816200050884546200044a565b8462000486565b602080601f8311600181146200054757600084156200052e5750858301515b600019600386901b1c1916600185901b178555620004d2565b600085815260208120601f198616915b82811015620005785788860151825594840194600190910190840162000557565b5085821015620005975787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6020815260008251806020840152620005c8816040850160208701620002a0565b601f01601f19169190910160400192915050565b80516020808301519190811015620004805760001960209190910360031b1b16919050565b60805160a05160c05160e05161010051610120516101405161129e6200065c6000396000610a8801526000610a5b01526000610918015260006108f00152600061084b015260006108750152600061089f015261129e6000f3fe608060405234801561001057600080fd5b50600436106101735760003560e01c8063715018a6116100de578063a76b4d5611610097578063dc9716eb11610071578063dc9716eb146102f8578063dd62ed3e14610300578063e8a3d48514610339578063f2fde38b1461034157600080fd5b8063a76b4d56146102ca578063a9059cbb146102d2578063d505accf146102e557600080fd5b8063715018a61461025e57806379cc6790146102665780637ecebe001461027957806384b0196e1461028c5780638da5cb5b146102a757806395d89b41146102c257600080fd5b8063313ce56711610130578063313ce567146101ee5780633644e515146101fd5780633fd4d4a81461020557806340c10f191461020d57806342966c681461022257806370a082311461023557600080fd5b806306fdde0314610178578063095ea7b3146101965780630cd9acb7146101b9578063120a88ad146101c157806318160ddd146101c957806323b872dd146101db575b600080fd5b610180610354565b60405161018d9190610fe8565b60405180910390f35b6101a96101a436600461101e565b6103e6565b604051901515815260200161018d565b610180610400565b61018061048e565b6002545b60405190815260200161018d565b6101a96101e9366004611048565b61049d565b6040516012815260200161018d565b6101cd6104c1565b6101806104d0565b61022061021b36600461101e565b6104df565b005b610220610230366004611084565b6104f5565b6101cd61024336600461109d565b6001600160a01b031660009081526020819052604090205490565b610220610502565b61022061027436600461101e565b610516565b6101cd61028736600461109d565b61052b565b610294610549565b60405161018d97969594939291906110b8565b6005546040516001600160a01b03909116815260200161018d565b61018061058f565b61018061059e565b6101a96102e036600461101e565b6105ab565b6102206102f3366004611151565b6105b9565b6101806106f8565b6101cd61030e3660046111c4565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b610180610705565b61022061034f36600461109d565b610714565b606060038054610363906111f7565b80601f016020809104026020016040519081016040528092919081815260200182805461038f906111f7565b80156103dc5780601f106103b1576101008083540402835291602001916103dc565b820191906000526020600020905b8154815290600101906020018083116103bf57829003601f168201915b5050505050905090565b6000336103f481858561074f565b60019150505b92915050565b6009805461040d906111f7565b80601f0160208091040260200160405190810160405280929190818152602001828054610439906111f7565b80156104865780601f1061045b57610100808354040283529160200191610486565b820191906000526020600020905b81548152906001019060200180831161046957829003601f168201915b505050505081565b606060098054610363906111f7565b6000336104ab858285610761565b6104b68585856107df565b506001949350505050565b60006104cb61083e565b905090565b6060600a8054610363906111f7565b6104e7610969565b6104f18282610996565b5050565b6104ff33826109cc565b50565b61050a610969565b6105146000610a02565b565b610521823383610761565b6104f182826109cc565b6001600160a01b0381166000908152600860205260408120546103fa565b60006060806000806000606061055d610a54565b610565610a81565b60408051600080825260208201909252600f60f81b9b939a50919850469750309650945092509050565b606060048054610363906111f7565b600b805461040d906111f7565b6000336103f48185856107df565b834211156105e25760405163313c898160e11b8152600481018590526024015b60405180910390fd5b60007f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c988888861062f8c6001600160a01b0316600090815260086020526040902080546001810190915590565b6040805160208101969096526001600160a01b0394851690860152929091166060840152608083015260a082015260c0810186905260e001604051602081830303815290604052805190602001209050600061068a82610aae565b9050600061069a82878787610adb565b9050896001600160a01b0316816001600160a01b0316146106e1576040516325c0072360e11b81526001600160a01b0380831660048301528b1660248201526044016105d9565b6106ec8a8a8a61074f565b50505050505050505050565b600a805461040d906111f7565b6060600b8054610363906111f7565b61071c610969565b6001600160a01b03811661074657604051631e4fbdf760e01b8152600060048201526024016105d9565b6104ff81610a02565b61075c8383836001610b09565b505050565b6001600160a01b0383811660009081526001602090815260408083209386168352929052205460001981146107d957818110156107ca57604051637dc7a0d960e11b81526001600160a01b038416600482015260248101829052604481018390526064016105d9565b6107d984848484036000610b09565b50505050565b6001600160a01b03831661080957604051634b637e8f60e11b8152600060048201526024016105d9565b6001600160a01b0382166108335760405163ec442f0560e01b8152600060048201526024016105d9565b61075c838383610bde565b6000306001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614801561089757507f000000000000000000000000000000000000000000000000000000000000000046145b156108c157507f000000000000000000000000000000000000000000000000000000000000000090565b6104cb604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201527f0000000000000000000000000000000000000000000000000000000000000000918101919091527f000000000000000000000000000000000000000000000000000000000000000060608201524660808201523060a082015260009060c00160405160208183030381529060405280519060200120905090565b6005546001600160a01b031633146105145760405163118cdaa760e01b81523360048201526024016105d9565b6001600160a01b0382166109c05760405163ec442f0560e01b8152600060048201526024016105d9565b6104f160008383610bde565b6001600160a01b0382166109f657604051634b637e8f60e11b8152600060048201526024016105d9565b6104f182600083610bde565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b60606104cb7f00000000000000000000000000000000000000000000000000000000000000006006610d08565b60606104cb7f00000000000000000000000000000000000000000000000000000000000000006007610d08565b60006103fa610abb61083e565b8360405161190160f01b8152600281019290925260228201526042902090565b600080600080610aed88888888610db3565b925092509250610afd8282610e82565b50909695505050505050565b6001600160a01b038416610b335760405163e602df0560e01b8152600060048201526024016105d9565b6001600160a01b038316610b5d57604051634a1406b160e11b8152600060048201526024016105d9565b6001600160a01b03808516600090815260016020908152604080832093871683529290522082905580156107d957826001600160a01b0316846001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92584604051610bd091815260200190565b60405180910390a350505050565b6001600160a01b038316610c09578060026000828254610bfe9190611231565b90915550610c7b9050565b6001600160a01b03831660009081526020819052604090205481811015610c5c5760405163391434e360e21b81526001600160a01b038516600482015260248101829052604481018390526064016105d9565b6001600160a01b03841660009081526020819052604090209082900390555b6001600160a01b038216610c9757600280548290039055610cb6565b6001600160a01b03821660009081526020819052604090208054820190555b816001600160a01b0316836001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef83604051610cfb91815260200190565b60405180910390a3505050565b606060ff8314610d2257610d1b83610f3b565b90506103fa565b818054610d2e906111f7565b80601f0160208091040260200160405190810160405280929190818152602001828054610d5a906111f7565b8015610da75780601f10610d7c57610100808354040283529160200191610da7565b820191906000526020600020905b815481529060010190602001808311610d8a57829003601f168201915b505050505090506103fa565b600080807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0841115610dee5750600091506003905082610e78565b604080516000808252602082018084528a905260ff891692820192909252606081018790526080810186905260019060a0016020604051602081039080840390855afa158015610e42573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116610e6e57506000925060019150829050610e78565b9250600091508190505b9450945094915050565b6000826003811115610e9657610e96611252565b03610e9f575050565b6001826003811115610eb357610eb3611252565b03610ed15760405163f645eedf60e01b815260040160405180910390fd5b6002826003811115610ee557610ee5611252565b03610f065760405163fce698f760e01b8152600481018290526024016105d9565b6003826003811115610f1a57610f1a611252565b036104f1576040516335e2f38360e21b8152600481018290526024016105d9565b60606000610f4883610f7a565b604080516020808252818301909252919250600091906020820181803683375050509182525060208101929092525090565b600060ff8216601f8111156103fa57604051632cd44ac360e21b815260040160405180910390fd5b6000815180845260005b81811015610fc857602081850181015186830182015201610fac565b506000602082860101526020601f19601f83011685010191505092915050565b602081526000610ffb6020830184610fa2565b9392505050565b80356001600160a01b038116811461101957600080fd5b919050565b6000806040838503121561103157600080fd5b61103a83611002565b946020939093013593505050565b60008060006060848603121561105d57600080fd5b61106684611002565b925061107460208501611002565b9150604084013590509250925092565b60006020828403121561109657600080fd5b5035919050565b6000602082840312156110af57600080fd5b610ffb82611002565b60ff60f81b881681526000602060e060208401526110d960e084018a610fa2565b83810360408501526110eb818a610fa2565b606085018990526001600160a01b038816608086015260a0850187905284810360c08601528551808252602080880193509091019060005b8181101561113f57835183529284019291840191600101611123565b50909c9b505050505050505050505050565b600080600080600080600060e0888a03121561116c57600080fd5b61117588611002565b965061118360208901611002565b95506040880135945060608801359350608088013560ff811681146111a757600080fd5b9699959850939692959460a0840135945060c09093013592915050565b600080604083850312156111d757600080fd5b6111e083611002565b91506111ee60208401611002565b90509250929050565b600181811c9082168061120b57607f821691505b60208210810361122b57634e487b7160e01b600052602260045260246000fd5b50919050565b808201808211156103fa57634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052602160045260246000fdfea26469706673582212206fb41458119173f9f1d07720d0b22fbfacf4726505008b5c43816c9902cd0fc464736f6c63430008170033a26469706673582212201df4bdff78560cbe320524756593933725001e7f7f8e2f575636163e3d9cc87d64736f6c63430008170033" + +access(all) let erc721DeployerBytecode = "608060405234801561001057600080fd5b50338061003757604051631e4fbdf760e01b81526000600482015260240160405180910390fd5b61004081610046565b50610096565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b612657806100a56000396000f3fe60806040523480156200001157600080fd5b5060043610620000875760003560e01c8063715018a61162000062578063715018a614620000fc5780638da5cb5b1462000108578063ee2d8496146200011a578063f2fde38b146200013157600080fd5b806301ffc9a7146200008c578063476d399714620000b85780636418e6de14620000e8575b600080fd5b620000a36200009d3660046200043c565b62000148565b60405190151581526020015b60405180910390f35b620000cf620000c93660046200051a565b62000180565b6040516001600160a01b039091168152602001620000af565b600154620000cf906001600160a01b031681565b62000106620002a7565b005b6000546001600160a01b0316620000cf565b620001066200012b366004620005fc565b620002bf565b6200010662000142366004620005fc565b6200036b565b60006001600160e01b0319821663476d399760e01b14806200017a57506301ffc9a760e01b6001600160e01b03198316145b92915050565b6001546000906001600160a01b031633146200020b576040805162461bcd60e51b81526020600482015260248101919091527f466c6f7745564d427269646765644552433732314465706c6f7965723a204f6e60448201527f6c792064656c656761746564206465706c6f7965722063616e206465706c6f7960648201526084015b60405180910390fd5b600080546001600160a01b031687878787876040516200022b906200042e565b6200023c969594939291906200066f565b604051809103906000f08015801562000259573d6000803e3d6000fd5b5090507fbebce54951ebf20c0dcd195a45bb2388d9ac8e38b5974e00bb63c5822dbe65f0818888888860405162000295959493929190620006f8565b60405180910390a19695505050505050565b620002b1620003af565b620002bd6000620003de565b565b620002c9620003af565b6001600160a01b03811662000349576040805162461bcd60e51b81526020600482015260248101919091527f466c6f7745564d427269646765644552433732314465706c6f7965723a20496e60448201527f76616c69642064656c656761746564206465706c6f7965722061646472657373606482015260840162000202565b600180546001600160a01b0319166001600160a01b0392909216919091179055565b62000375620003af565b6001600160a01b038116620003a157604051631e4fbdf760e01b81526000600482015260240162000202565b620003ac81620003de565b50565b6000546001600160a01b03163314620002bd5760405163118cdaa760e01b815233600482015260240162000202565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b611eb7806200076b83390190565b6000602082840312156200044f57600080fd5b81356001600160e01b0319811681146200046857600080fd5b9392505050565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126200049757600080fd5b813567ffffffffffffffff80821115620004b557620004b56200046f565b604051601f8301601f19908116603f01168101908282118183101715620004e057620004e06200046f565b81604052838152866020858801011115620004fa57600080fd5b836020870160208301376000602085830101528094505050505092915050565b600080600080600060a086880312156200053357600080fd5b853567ffffffffffffffff808211156200054c57600080fd5b6200055a89838a0162000485565b965060208801359150808211156200057157600080fd5b6200057f89838a0162000485565b955060408801359150808211156200059657600080fd5b620005a489838a0162000485565b94506060880135915080821115620005bb57600080fd5b620005c989838a0162000485565b93506080880135915080821115620005e057600080fd5b50620005ef8882890162000485565b9150509295509295909350565b6000602082840312156200060f57600080fd5b81356001600160a01b03811681146200046857600080fd5b6000815180845260005b818110156200064f5760208185018101518683018201520162000631565b506000602082860101526020601f19601f83011685010191505092915050565b6001600160a01b038716815260c060208201819052600090620006959083018862000627565b8281036040840152620006a9818862000627565b90508281036060840152620006bf818762000627565b90508281036080840152620006d5818662000627565b905082810360a0840152620006eb818562000627565b9998505050505050505050565b6001600160a01b038616815260a0602082018190526000906200071e9083018762000627565b828103604084015262000732818762000627565b9050828103606084015262000748818662000627565b905082810360808401526200075e818562000627565b9897505050505050505056fe60806040523480156200001157600080fd5b5060405162001eb738038062001eb7833981016040819052620000349162000202565b858585600062000045838262000386565b50600162000054828262000386565b5050506001600160a01b0381166200008657604051631e4fbdf760e01b81526000600482015260240160405180910390fd5b6200009181620000cb565b50600c620000a0848262000386565b50600d620000af838262000386565b50600e620000be828262000386565b5050505050505062000452565b600b80546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b80516001600160a01b03811681146200013557600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126200016257600080fd5b81516001600160401b03808211156200017f576200017f6200013a565b604051601f8301601f19908116603f01168101908282118183101715620001aa57620001aa6200013a565b8160405283815260209250866020858801011115620001c857600080fd5b600091505b83821015620001ec5785820183015181830184015290820190620001cd565b6000602085830101528094505050505092915050565b60008060008060008060c087890312156200021c57600080fd5b62000227876200011d565b60208801519096506001600160401b03808211156200024557600080fd5b620002538a838b0162000150565b965060408901519150808211156200026a57600080fd5b620002788a838b0162000150565b955060608901519150808211156200028f57600080fd5b6200029d8a838b0162000150565b94506080890151915080821115620002b457600080fd5b620002c28a838b0162000150565b935060a0890151915080821115620002d957600080fd5b50620002e889828a0162000150565b9150509295509295509295565b600181811c908216806200030a57607f821691505b6020821081036200032b57634e487b7160e01b600052602260045260246000fd5b50919050565b601f82111562000381576000816000526020600020601f850160051c810160208610156200035c5750805b601f850160051c820191505b818110156200037d5782815560010162000368565b5050505b505050565b81516001600160401b03811115620003a257620003a26200013a565b620003ba81620003b38454620002f5565b8462000331565b602080601f831160018114620003f25760008415620003d95750858301515b600019600386901b1c1916600185901b1785556200037d565b600085815260208120601f198616915b82811015620004235788860151825594840194600190910190840162000402565b5085821015620004425787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b611a5580620004626000396000f3fe608060405234801561001057600080fd5b50600436106101cf5760003560e01c806370a0823111610104578063a76b4d56116100a2578063cd279c7c11610071578063cd279c7c146103a8578063e8a3d485146103bb578063e985e9c5146103c3578063f2fde38b146103d657600080fd5b8063a76b4d5614610372578063b49bbd941461037a578063b88d4fde14610382578063c87b56dd1461039557600080fd5b806394e29329116100de57806394e293291461034757806395d89b411461034f578063a159047b14610357578063a22cb4651461035f57600080fd5b806370a082311461031b578063715018a61461032e5780638da5cb5b1461033657600080fd5b80632f745c59116101715780634f558e791161014b5780634f558e79146102c25780634f6ccce7146102ed5780635e0a9661146103005780636352211e1461030857600080fd5b80632f745c591461028957806342842e0e1461029c57806342966c68146102af57600080fd5b8063095ea7b3116101ad578063095ea7b31461023c57806318160ddd1461025157806318e97fd11461026357806323b872dd1461027657600080fd5b806301ffc9a7146101d457806306fdde03146101fc578063081812fc14610211575b600080fd5b6101e76101e2366004611494565b6103e9565b60405190151581526020015b60405180910390f35b6102046103fa565b6040516101f39190611501565b61022461021f366004611514565b61048c565b6040516001600160a01b0390911681526020016101f3565b61024f61024a366004611549565b6104b5565b005b6009545b6040519081526020016101f3565b61024f61027136600461161f565b6104c4565b61024f610284366004611666565b6104d6565b610255610297366004611549565b610566565b61024f6102aa366004611666565b6105cb565b61024f6102bd366004611514565b6105eb565b6101e76102d0366004611514565b6000908152600260205260409020546001600160a01b0316151590565b6102556102fb366004611514565b6105f7565b610204610650565b610224610316366004611514565b61065f565b6102556103293660046116a2565b61066a565b61024f6106b2565b600b546001600160a01b0316610224565b6102046106c6565b6102046106d5565b6102046106e4565b61024f61036d3660046116bd565b610772565b61020461077d565b61020461078a565b61024f6103903660046116f9565b610797565b6102046103a3366004611514565b6107ae565b61024f6103b6366004611775565b6107b9565b6102046107d5565b6101e76103d13660046117cc565b6107e4565b61024f6103e43660046116a2565b610812565b60006103f482610850565b92915050565b606060008054610409906117ff565b80601f0160208091040260200160405190810160405280929190818152602001828054610435906117ff565b80156104825780601f1061045757610100808354040283529160200191610482565b820191906000526020600020905b81548152906001019060200180831161046557829003601f168201915b5050505050905090565b600061049782610875565b506000828152600460205260409020546001600160a01b03166103f4565b6104c08282336108ae565b5050565b6104cc6108bb565b6104c082826108e8565b6001600160a01b03821661050557604051633250574960e11b8152600060048201526024015b60405180910390fd5b6000610512838333610938565b9050836001600160a01b0316816001600160a01b031614610560576040516364283d7b60e01b81526001600160a01b03808616600483015260248201849052821660448201526064016104fc565b50505050565b60006105718361066a565b82106105a25760405163295f44f760e21b81526001600160a01b0384166004820152602481018390526044016104fc565b506001600160a01b03919091166000908152600760209081526040808320938352929052205490565b6105e683838360405180602001604052806000815250610797565b505050565b6104c060008233610938565b600061060260095490565b821061062b5760405163295f44f760e21b815260006004820152602481018390526044016104fc565b6009828154811061063e5761063e611839565b90600052602060002001549050919050565b6060600d8054610409906117ff565b60006103f482610875565b60006001600160a01b038216610696576040516322718ad960e21b8152600060048201526024016104fc565b506001600160a01b031660009081526003602052604090205490565b6106ba6108bb565b6106c4600061094d565b565b6060600c8054610409906117ff565b606060018054610409906117ff565b600d80546106f1906117ff565b80601f016020809104026020016040519081016040528092919081815260200182805461071d906117ff565b801561076a5780601f1061073f5761010080835404028352916020019161076a565b820191906000526020600020905b81548152906001019060200180831161074d57829003601f168201915b505050505081565b6104c033838361099f565b600e80546106f1906117ff565b600c80546106f1906117ff565b6107a28484846104d6565b61056084848484610a3e565b60606103f482610b67565b6107c16108bb565b6107cb8383610c70565b6105e682826108e8565b6060600e8054610409906117ff565b6001600160a01b03918216600090815260056020908152604080832093909416825291909152205460ff1690565b61081a6108bb565b6001600160a01b03811661084457604051631e4fbdf760e01b8152600060048201526024016104fc565b61084d8161094d565b50565b60006001600160e01b0319821663780e9d6360e01b14806103f457506103f482610c8a565b6000818152600260205260408120546001600160a01b0316806103f457604051637e27328960e01b8152600481018490526024016104fc565b6105e68383836001610caf565b600b546001600160a01b031633146106c45760405163118cdaa760e01b81523360048201526024016104fc565b6000828152600660205260409020610900828261189f565b506040518281527ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79060200160405180910390a15050565b6000610945848484610db5565b949350505050565b600b80546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6001600160a01b0382166109d157604051630b61174360e31b81526001600160a01b03831660048201526024016104fc565b6001600160a01b03838116600081815260056020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b6001600160a01b0383163b1561056057604051630a85bd0160e11b81526001600160a01b0384169063150b7a0290610a8090339088908790879060040161195f565b6020604051808303816000875af1925050508015610abb575060408051601f3d908101601f19168201909252610ab89181019061199c565b60015b610b24573d808015610ae9576040519150601f19603f3d011682016040523d82523d6000602084013e610aee565b606091505b508051600003610b1c57604051633250574960e11b81526001600160a01b03851660048201526024016104fc565b805181602001fd5b6001600160e01b03198116630a85bd0160e11b14610b6057604051633250574960e11b81526001600160a01b03851660048201526024016104fc565b5050505050565b6060610b7282610875565b5060008281526006602052604081208054610b8c906117ff565b80601f0160208091040260200160405190810160405280929190818152602001828054610bb8906117ff565b8015610c055780601f10610bda57610100808354040283529160200191610c05565b820191906000526020600020905b815481529060010190602001808311610be857829003601f168201915b505050505090506000610c2360408051602081019091526000815290565b90508051600003610c35575092915050565b815115610c67578082604051602001610c4f9291906119b9565b60405160208183030381529060405292505050919050565b61094584610e82565b6104c0828260405180602001604052806000815250610ef7565b60006001600160e01b03198216632483248360e11b14806103f457506103f482610f0e565b8080610cc357506001600160a01b03821615155b15610d85576000610cd384610875565b90506001600160a01b03831615801590610cff5750826001600160a01b0316816001600160a01b031614155b8015610d125750610d1081846107e4565b155b15610d3b5760405163a9fbf51f60e01b81526001600160a01b03841660048201526024016104fc565b8115610d835783856001600160a01b0316826001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45b505b5050600090815260046020526040902080546001600160a01b0319166001600160a01b0392909216919091179055565b600080610dc3858585610f5e565b90506001600160a01b038116610e2057610e1b84600980546000838152600a60205260408120829055600182018355919091527f6e1540171b6c0c960b71a7020d9f60077f6af931a8bbf590da0223dacf75c7af0155565b610e43565b846001600160a01b0316816001600160a01b031614610e4357610e438185611057565b6001600160a01b038516610e5f57610e5a846110e8565b610945565b846001600160a01b0316816001600160a01b031614610945576109458585611197565b6060610e8d82610875565b506000610ea560408051602081019091526000815290565b90506000815111610ec55760405180602001604052806000815250610ef0565b80610ecf846111e7565b604051602001610ee09291906119b9565b6040516020818303038152906040525b9392505050565b610f01838361127a565b6105e66000848484610a3e565b60006001600160e01b031982166380ac58cd60e01b1480610f3f57506001600160e01b03198216635b5e139f60e01b145b806103f457506301ffc9a760e01b6001600160e01b03198316146103f4565b6000828152600260205260408120546001600160a01b0390811690831615610f8b57610f8b8184866112df565b6001600160a01b03811615610fc957610fa8600085600080610caf565b6001600160a01b038116600090815260036020526040902080546000190190555b6001600160a01b03851615610ff8576001600160a01b0385166000908152600360205260409020805460010190555b60008481526002602052604080822080546001600160a01b0319166001600160a01b0389811691821790925591518793918516917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4949350505050565b60006110628361066a565b6000838152600860205260409020549091508082146110b5576001600160a01b03841660009081526007602090815260408083208584528252808320548484528184208190558352600890915290208190555b5060009182526008602090815260408084208490556001600160a01b039094168352600781528383209183525290812055565b6009546000906110fa906001906119e8565b6000838152600a60205260408120546009805493945090928490811061112257611122611839565b90600052602060002001549050806009838154811061114357611143611839565b6000918252602080832090910192909255828152600a9091526040808220849055858252812055600980548061117b5761117b611a09565b6001900381819060005260206000200160009055905550505050565b600060016111a48461066a565b6111ae91906119e8565b6001600160a01b039093166000908152600760209081526040808320868452825280832085905593825260089052919091209190915550565b606060006111f483611343565b600101905060008167ffffffffffffffff81111561121457611214611573565b6040519080825280601f01601f19166020018201604052801561123e576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a850494508461124857509392505050565b6001600160a01b0382166112a457604051633250574960e11b8152600060048201526024016104fc565b60006112b283836000610938565b90506001600160a01b038116156105e6576040516339e3563760e11b8152600060048201526024016104fc565b6112ea83838361141b565b6105e6576001600160a01b03831661131857604051637e27328960e01b8152600481018290526024016104fc565b60405163177e802f60e01b81526001600160a01b0383166004820152602481018290526044016104fc565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b83106113825772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef810000000083106113ae576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc1000083106113cc57662386f26fc10000830492506010015b6305f5e10083106113e4576305f5e100830492506008015b61271083106113f857612710830492506004015b6064831061140a576064830492506002015b600a83106103f45760010192915050565b60006001600160a01b038316158015906109455750826001600160a01b0316846001600160a01b03161480611455575061145584846107e4565b806109455750506000908152600460205260409020546001600160a01b03908116911614919050565b6001600160e01b03198116811461084d57600080fd5b6000602082840312156114a657600080fd5b8135610ef08161147e565b60005b838110156114cc5781810151838201526020016114b4565b50506000910152565b600081518084526114ed8160208601602086016114b1565b601f01601f19169290920160200192915050565b602081526000610ef060208301846114d5565b60006020828403121561152657600080fd5b5035919050565b80356001600160a01b038116811461154457600080fd5b919050565b6000806040838503121561155c57600080fd5b6115658361152d565b946020939093013593505050565b634e487b7160e01b600052604160045260246000fd5b600067ffffffffffffffff808411156115a4576115a4611573565b604051601f8501601f19908116603f011681019082821181831017156115cc576115cc611573565b816040528093508581528686860111156115e557600080fd5b858560208301376000602087830101525050509392505050565b600082601f83011261161057600080fd5b610ef083833560208501611589565b6000806040838503121561163257600080fd5b82359150602083013567ffffffffffffffff81111561165057600080fd5b61165c858286016115ff565b9150509250929050565b60008060006060848603121561167b57600080fd5b6116848461152d565b92506116926020850161152d565b9150604084013590509250925092565b6000602082840312156116b457600080fd5b610ef08261152d565b600080604083850312156116d057600080fd5b6116d98361152d565b9150602083013580151581146116ee57600080fd5b809150509250929050565b6000806000806080858703121561170f57600080fd5b6117188561152d565b93506117266020860161152d565b925060408501359150606085013567ffffffffffffffff81111561174957600080fd5b8501601f8101871361175a57600080fd5b61176987823560208401611589565b91505092959194509250565b60008060006060848603121561178a57600080fd5b6117938461152d565b925060208401359150604084013567ffffffffffffffff8111156117b657600080fd5b6117c2868287016115ff565b9150509250925092565b600080604083850312156117df57600080fd5b6117e88361152d565b91506117f66020840161152d565b90509250929050565b600181811c9082168061181357607f821691505b60208210810361183357634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052603260045260246000fd5b601f8211156105e6576000816000526020600020601f850160051c810160208610156118785750805b601f850160051c820191505b8181101561189757828155600101611884565b505050505050565b815167ffffffffffffffff8111156118b9576118b9611573565b6118cd816118c784546117ff565b8461184f565b602080601f83116001811461190257600084156118ea5750858301515b600019600386901b1c1916600185901b178555611897565b600085815260208120601f198616915b8281101561193157888601518255948401946001909101908401611912565b508582101561194f5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6001600160a01b0385811682528416602082015260408101839052608060608201819052600090611992908301846114d5565b9695505050505050565b6000602082840312156119ae57600080fd5b8151610ef08161147e565b600083516119cb8184602088016114b1565b8351908301906119df8183602088016114b1565b01949350505050565b818103818111156103f457634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052603160045260246000fdfea264697066735822122074d34aec07c0da793ce5cac74069bf4177b7594babf4fede87db849ea2f57b3764736f6c63430008170033a2646970667358221220953493586f5fb5670e80849013b6c27540a3f06c628c3046b81886afa405e0c664736f6c63430008170033" + +access(all) let registryBytecode = "608060405234801561001057600080fd5b50338061003757604051631e4fbdf760e01b81526000600482015260240160405180910390fd5b61004081610058565b50600080546001600160a01b031916331790556100aa565b600380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6108a5806100b96000396000f3fe608060405234801561001057600080fd5b50600436106100a95760003560e01c8063862119ae11610071578063862119ae146101315780638da5cb5b14610144578063a6de610514610155578063b3d5dbdc14610168578063f2fde38b14610188578063faab9d391461019b57600080fd5b806301ffc9a7146100ae57806304433bbc146100d65780632b20e39714610101578063522791d114610114578063715018a614610129575b600080fd5b6100c16100bc36600461051c565b6101ae565b60405190151581526020015b60405180910390f35b6100e96100e43660046105f0565b6101e5565b6040516001600160a01b0390911681526020016100cd565b6000546100e9906001600160a01b031681565b610127610122366004610649565b610216565b005b6101276102b7565b6100c161013f3660046105f0565b6102cb565b6003546001600160a01b03166100e9565b6100c1610163366004610697565b610308565b61017b610176366004610697565b610334565b6040516100cd91906106d6565b610127610196366004610697565b6103e0565b6101276101a9366004610697565b61041e565b60006001600160e01b0319821663976998cb60e01b14806101df57506301ffc9a760e01b6001600160e01b03198316145b92915050565b60006001826040516101f79190610709565b908152604051908190036020019020546001600160a01b031692915050565b6000546001600160a01b031633146102a95760405162461bcd60e51b815260206004820152604560248201527f466c6f774272696467654465706c6f796d656e7452656769737472793a204f6e60448201527f6c79207265676973747261722063616e207265676973746572206173736f636960648201526430ba34b7b760d91b608482015260a4015b60405180910390fd5b6102b38282610444565b5050565b6102bf61049d565b6102c960006104ca565b565b6000806001600160a01b03166001836040516102e79190610709565b908152604051908190036020019020546001600160a01b0316141592915050565b6001600160a01b0381166000908152600260205260408120805461032b90610725565b15159392505050565b6001600160a01b038116600090815260026020526040902080546060919061035b90610725565b80601f016020809104026020016040519081016040528092919081815260200182805461038790610725565b80156103d45780601f106103a9576101008083540402835291602001916103d4565b820191906000526020600020905b8154815290600101906020018083116103b757829003601f168201915b50505050509050919050565b6103e861049d565b6001600160a01b03811661041257604051631e4fbdf760e01b8152600060048201526024016102a0565b61041b816104ca565b50565b61042661049d565b600080546001600160a01b0319166001600160a01b03831617905550565b806001836040516104559190610709565b908152604080516020928190038301902080546001600160a01b0319166001600160a01b03948516179055918316600090815260029091522061049883826107af565b505050565b6003546001600160a01b031633146102c95760405163118cdaa760e01b81523360048201526024016102a0565b600380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b60006020828403121561052e57600080fd5b81356001600160e01b03198116811461054657600080fd5b9392505050565b634e487b7160e01b600052604160045260246000fd5b600082601f83011261057457600080fd5b813567ffffffffffffffff8082111561058f5761058f61054d565b604051601f8301601f19908116603f011681019082821181831017156105b7576105b761054d565b816040528381528660208588010111156105d057600080fd5b836020870160208301376000602085830101528094505050505092915050565b60006020828403121561060257600080fd5b813567ffffffffffffffff81111561061957600080fd5b61062584828501610563565b949350505050565b80356001600160a01b038116811461064457600080fd5b919050565b6000806040838503121561065c57600080fd5b823567ffffffffffffffff81111561067357600080fd5b61067f85828601610563565b92505061068e6020840161062d565b90509250929050565b6000602082840312156106a957600080fd5b6105468261062d565b60005b838110156106cd5781810151838201526020016106b5565b50506000910152565b60208152600082518060208401526106f58160408501602087016106b2565b601f01601f19169190910160400192915050565b6000825161071b8184602087016106b2565b9190910192915050565b600181811c9082168061073957607f821691505b60208210810361075957634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115610498576000816000526020600020601f850160051c810160208610156107885750805b601f850160051c820191505b818110156107a757828155600101610794565b505050505050565b815167ffffffffffffffff8111156107c9576107c961054d565b6107dd816107d78454610725565b8461075f565b602080601f83116001811461081257600084156107fa5750858301515b600019600386901b1c1916600185901b1785556107a7565b600085815260208120601f198616915b8281101561084157888601518255948401946001909101908401610822565b508582101561085f5787850151600019600388901b60f8161c191681555b5050505050600190811b0190555056fea26469706673582212204229c8738eb6a99e2fe8a2cd0be82f006719cf059ff7c5b2f748353eb7c5da4c64736f6c63430008170033" access(all) let compiledERC721Bytecode = "60806040523480156200001157600080fd5b5033604051806040016040528060048152602001634e414d4560e01b8152506040518060400160405280600681526020016514d6535093d360d21b8152508160009081620000609190620001ac565b5060016200006f8282620001ac565b5050506001600160a01b038116620000a157604051631e4fbdf760e01b81526000600482015260240160405180910390fd5b620000ac81620000b3565b5062000278565b600780546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b634e487b7160e01b600052604160045260246000fd5b600181811c908216806200013057607f821691505b6020821081036200015157634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115620001a7576000816000526020600020601f850160051c81016020861015620001825750805b601f850160051c820191505b81811015620001a3578281556001016200018e565b5050505b505050565b81516001600160401b03811115620001c857620001c862000105565b620001e081620001d984546200011b565b8462000157565b602080601f831160018114620002185760008415620001ff5750858301515b600019600386901b1c1916600185901b178555620001a3565b600085815260208120601f198616915b82811015620002495788860151825594840194600190910190840162000228565b5085821015620002685787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b61143080620002886000396000f3fe608060405234801561001057600080fd5b50600436106101165760003560e01c8063715018a6116100a2578063b88d4fde11610071578063b88d4fde14610239578063c87b56dd1461024c578063cd279c7c1461025f578063e985e9c514610272578063f2fde38b1461028557600080fd5b8063715018a6146102055780638da5cb5b1461020d57806395d89b411461021e578063a22cb4651461022657600080fd5b806323b872dd116100e957806323b872dd1461019857806342842e0e146101ab57806342966c68146101be5780636352211e146101d157806370a08231146101e457600080fd5b806301ffc9a71461011b57806306fdde0314610143578063081812fc14610158578063095ea7b314610183575b600080fd5b61012e610129366004610f0f565b610298565b60405190151581526020015b60405180910390f35b61014b6102a9565b60405161013a9190610f7c565b61016b610166366004610f8f565b61033b565b6040516001600160a01b03909116815260200161013a565b610196610191366004610fc4565b610364565b005b6101966101a6366004610fee565b610373565b6101966101b9366004610fee565b610403565b6101966101cc366004610f8f565b610423565b61016b6101df366004610f8f565b61042f565b6101f76101f236600461102a565b61043a565b60405190815260200161013a565b610196610482565b6007546001600160a01b031661016b565b61014b610496565b610196610234366004611045565b6104a5565b61019661024736600461110d565b6104b0565b61014b61025a366004610f8f565b6104c7565b61019661026d366004611189565b6104d2565b61012e6102803660046111f4565b6104ee565b61019661029336600461102a565b61051c565b60006102a38261055a565b92915050565b6060600080546102b890611227565b80601f01602080910402602001604051908101604052809291908181526020018280546102e490611227565b80156103315780601f1061030657610100808354040283529160200191610331565b820191906000526020600020905b81548152906001019060200180831161031457829003601f168201915b5050505050905090565b60006103468261057f565b506000828152600460205260409020546001600160a01b03166102a3565b61036f8282336105b8565b5050565b6001600160a01b0382166103a257604051633250574960e11b8152600060048201526024015b60405180910390fd5b60006103af8383336105c5565b9050836001600160a01b0316816001600160a01b0316146103fd576040516364283d7b60e01b81526001600160a01b0380861660048301526024820184905282166044820152606401610399565b50505050565b61041e838383604051806020016040528060008152506104b0565b505050565b61036f600082336105c5565b60006102a38261057f565b60006001600160a01b038216610466576040516322718ad960e21b815260006004820152602401610399565b506001600160a01b031660009081526003602052604090205490565b61048a6106be565b61049460006106eb565b565b6060600180546102b890611227565b61036f33838361073d565b6104bb848484610373565b6103fd848484846107dc565b60606102a382610905565b6104da6106be565b6104e48383610a16565b61041e8282610a30565b6001600160a01b03918216600090815260056020908152604080832093909416825291909152205460ff1690565b6105246106be565b6001600160a01b03811661054e57604051631e4fbdf760e01b815260006004820152602401610399565b610557816106eb565b50565b60006001600160e01b03198216632483248360e11b14806102a357506102a382610a80565b6000818152600260205260408120546001600160a01b0316806102a357604051637e27328960e01b815260048101849052602401610399565b61041e8383836001610ad0565b6000828152600260205260408120546001600160a01b03908116908316156105f2576105f2818486610bd6565b6001600160a01b038116156106305761060f600085600080610ad0565b6001600160a01b038116600090815260036020526040902080546000190190555b6001600160a01b0385161561065f576001600160a01b0385166000908152600360205260409020805460010190555b60008481526002602052604080822080546001600160a01b0319166001600160a01b0389811691821790925591518793918516917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4949350505050565b6007546001600160a01b031633146104945760405163118cdaa760e01b8152336004820152602401610399565b600780546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6001600160a01b03821661076f57604051630b61174360e31b81526001600160a01b0383166004820152602401610399565b6001600160a01b03838116600081815260056020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b6001600160a01b0383163b156103fd57604051630a85bd0160e11b81526001600160a01b0384169063150b7a029061081e903390889087908790600401611261565b6020604051808303816000875af1925050508015610859575060408051601f3d908101601f191682019092526108569181019061129e565b60015b6108c2573d808015610887576040519150601f19603f3d011682016040523d82523d6000602084013e61088c565b606091505b5080516000036108ba57604051633250574960e11b81526001600160a01b0385166004820152602401610399565b805181602001fd5b6001600160e01b03198116630a85bd0160e11b146108fe57604051633250574960e11b81526001600160a01b0385166004820152602401610399565b5050505050565b60606109108261057f565b506000828152600660205260408120805461092a90611227565b80601f016020809104026020016040519081016040528092919081815260200182805461095690611227565b80156109a35780601f10610978576101008083540402835291602001916109a3565b820191906000526020600020905b81548152906001019060200180831161098657829003601f168201915b5050505050905060006109c160408051602081019091526000815290565b905080516000036109d3575092915050565b815115610a055780826040516020016109ed9291906112bb565b60405160208183030381529060405292505050919050565b610a0e84610c3a565b949350505050565b61036f828260405180602001604052806000815250610caf565b6000828152600660205260409020610a48828261133a565b506040518281527ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79060200160405180910390a15050565b60006001600160e01b031982166380ac58cd60e01b1480610ab157506001600160e01b03198216635b5e139f60e01b145b806102a357506301ffc9a760e01b6001600160e01b03198316146102a3565b8080610ae457506001600160a01b03821615155b15610ba6576000610af48461057f565b90506001600160a01b03831615801590610b205750826001600160a01b0316816001600160a01b031614155b8015610b335750610b3181846104ee565b155b15610b5c5760405163a9fbf51f60e01b81526001600160a01b0384166004820152602401610399565b8115610ba45783856001600160a01b0316826001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45b505b5050600090815260046020526040902080546001600160a01b0319166001600160a01b0392909216919091179055565b610be1838383610cc6565b61041e576001600160a01b038316610c0f57604051637e27328960e01b815260048101829052602401610399565b60405163177e802f60e01b81526001600160a01b038316600482015260248101829052604401610399565b6060610c458261057f565b506000610c5d60408051602081019091526000815290565b90506000815111610c7d5760405180602001604052806000815250610ca8565b80610c8784610d29565b604051602001610c989291906112bb565b6040516020818303038152906040525b9392505050565b610cb98383610dbc565b61041e60008484846107dc565b60006001600160a01b03831615801590610a0e5750826001600160a01b0316846001600160a01b03161480610d005750610d0084846104ee565b80610a0e5750506000908152600460205260409020546001600160a01b03908116911614919050565b60606000610d3683610e21565b600101905060008167ffffffffffffffff811115610d5657610d56611081565b6040519080825280601f01601f191660200182016040528015610d80576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a8504945084610d8a57509392505050565b6001600160a01b038216610de657604051633250574960e11b815260006004820152602401610399565b6000610df4838360006105c5565b90506001600160a01b0381161561041e576040516339e3563760e11b815260006004820152602401610399565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b8310610e605772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef81000000008310610e8c576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc100008310610eaa57662386f26fc10000830492506010015b6305f5e1008310610ec2576305f5e100830492506008015b6127108310610ed657612710830492506004015b60648310610ee8576064830492506002015b600a83106102a35760010192915050565b6001600160e01b03198116811461055757600080fd5b600060208284031215610f2157600080fd5b8135610ca881610ef9565b60005b83811015610f47578181015183820152602001610f2f565b50506000910152565b60008151808452610f68816020860160208601610f2c565b601f01601f19169290920160200192915050565b602081526000610ca86020830184610f50565b600060208284031215610fa157600080fd5b5035919050565b80356001600160a01b0381168114610fbf57600080fd5b919050565b60008060408385031215610fd757600080fd5b610fe083610fa8565b946020939093013593505050565b60008060006060848603121561100357600080fd5b61100c84610fa8565b925061101a60208501610fa8565b9150604084013590509250925092565b60006020828403121561103c57600080fd5b610ca882610fa8565b6000806040838503121561105857600080fd5b61106183610fa8565b91506020830135801515811461107657600080fd5b809150509250929050565b634e487b7160e01b600052604160045260246000fd5b600067ffffffffffffffff808411156110b2576110b2611081565b604051601f8501601f19908116603f011681019082821181831017156110da576110da611081565b816040528093508581528686860111156110f357600080fd5b858560208301376000602087830101525050509392505050565b6000806000806080858703121561112357600080fd5b61112c85610fa8565b935061113a60208601610fa8565b925060408501359150606085013567ffffffffffffffff81111561115d57600080fd5b8501601f8101871361116e57600080fd5b61117d87823560208401611097565b91505092959194509250565b60008060006060848603121561119e57600080fd5b6111a784610fa8565b925060208401359150604084013567ffffffffffffffff8111156111ca57600080fd5b8401601f810186136111db57600080fd5b6111ea86823560208401611097565b9150509250925092565b6000806040838503121561120757600080fd5b61121083610fa8565b915061121e60208401610fa8565b90509250929050565b600181811c9082168061123b57607f821691505b60208210810361125b57634e487b7160e01b600052602260045260246000fd5b50919050565b6001600160a01b038581168252841660208201526040810183905260806060820181905260009061129490830184610f50565b9695505050505050565b6000602082840312156112b057600080fd5b8151610ca881610ef9565b600083516112cd818460208801610f2c565b8351908301906112e1818360208801610f2c565b01949350505050565b601f82111561041e576000816000526020600020601f850160051c810160208610156113135750805b601f850160051c820191505b818110156113325782815560010161131f565b505050505050565b815167ffffffffffffffff81111561135457611354611081565b611368816113628454611227565b846112ea565b602080601f83116001811461139d57600084156113855750858301515b600019600386901b1c1916600185901b178555611332565b600085815260208120601f198616915b828110156113cc578886015182559484019460019091019084016113ad565b50858210156113ea5787850151600019600388901b60f8161c191681555b5050505050600190811b0190555056fea264697066735822122046da1d9cfc7c225e4655204f464e2ecbb316a6284c51c9c338433a1abb5919f864736f6c63430008170033" @@ -68,11 +75,28 @@ access(all) let bridgedTokenCodeChunks = [ "2e5661756c743e28292c20776974683a2073656c662e65766d546f6b656e436f6e747261637441646472657373290a2020202020202020466c6f7745564d427269646765546f6b656e457363726f772e696e697469616c697a65457363726f77280a202020202020202020202020776974683a203c2d637265617465205661756c742862616c616e63653a20302e30292c0a2020202020202020202020206e616d653a206e616d652c0a20202020202020202020202073796d626f6c3a2073796d626f6c2c0a202020202020202020202020646563696d616c733a20646563696d616c732c0a20202020202020202020202065766d546f6b656e416464726573733a2073656c662e65766d546f6b656e436f6e7472616374416464726573730a2020202020202020290a202020207d0a7d0a" ] +/* --- Bytecode Getters --- */ + access(all) fun getCompiledFactoryBytecode(): String { return compiledFactoryBytecode } +access(all) +fun getERC20DeployerBytecode(): String { + return erc20DeployerBytecode +} + +access(all) +fun getERC721DeployerBytecode(): String { + return erc721DeployerBytecode +} + +access(all) +fun getRegistryBytecode(): String { + return registryBytecode +} + access(all) fun getCompiledERC721Bytecode(): String { return compiledERC721Bytecode @@ -98,6 +122,22 @@ fun getBridgedTokenCodeChunks(): [String] { return bridgedTokenCodeChunks } +/* --- Event Value Helpers --- */ + +access(all) +fun getEVMAddressHexFromEvents(_ evts: [AnyStruct], idx: Int): String { + Test.assert(evts.length > idx, message: "Event index out of bounds") + + let evt = evts[idx] as? EVM.TransactionExecuted + ?? panic("Event at index ".concat(idx.toString()).concat(" is not a TransactionExecuted event")) + let emittedAddress = evt.contractAddress + Test.assert(emittedAddress.length != 0, message: "Emitted .contractAddress value is empty") + + let hexAddress = emittedAddress.slice(from: 2, upTo: emittedAddress.length).toLower() + Test.assertEqual(40, hexAddress.length) + return hexAddress +} + /* --- Script Helpers --- */ access(all) diff --git a/cadence/transactions/bridge/admin/evm/claim_accessor_capability_and_save_router.cdc b/cadence/transactions/bridge/admin/evm-integration/claim_accessor_capability_and_save_router.cdc similarity index 100% rename from cadence/transactions/bridge/admin/evm/claim_accessor_capability_and_save_router.cdc rename to cadence/transactions/bridge/admin/evm-integration/claim_accessor_capability_and_save_router.cdc diff --git a/cadence/transactions/bridge/admin/evm/add_deployer.cdc b/cadence/transactions/bridge/admin/evm/add_deployer.cdc new file mode 100644 index 00000000..47ad13e7 --- /dev/null +++ b/cadence/transactions/bridge/admin/evm/add_deployer.cdc @@ -0,0 +1,36 @@ +import "EVM" + +import "EVMUtils" +import "FlowEVMBridgeUtils" + +/// This transaction adds the given EVM address as a deployer in the bridge factory contract, indexed on the +/// provided tag. +/// +/// @param deployerTag: The tag to index the deployer with - e.g. ERC20, ERC721, etc. +/// @param deployerEVMAddressHex: The EVM address of the deployer contract as a hex string, without the '0x' prefix +/// +transaction(deployerTag: String, deployerEVMAddressHex: String) { + + let coa: auth(EVM.Call) &EVM.CadenceOwnedAccount + + prepare(signer: auth(BorrowValue) &Account) { + self.coa = signer.storage.borrow(from: /storage/evm) + ?? panic("Could not borrow COA from provided gateway address") + } + + execute { + let deployerEVMAddress = EVMUtils.getEVMAddressFromHexString(address: deployerEVMAddressHex) + ?? panic("Could not convert deployer contract address to EVM address") + + let callResult = self.coa.call( + to: FlowEVMBridgeUtils.bridgeFactoryEVMAddress, + data: EVM.encodeABIWithSignature( + "addDeployer(string,address)", + [deployerTag, deployerEVMAddress] + ), + gasLimit: 15_000_000, + value: EVM.Balance(attoflow: 0) + ) + assert(callResult.status == EVM.Status.successful, message: "Failed to add deployer") + } +} diff --git a/cadence/transactions/bridge/admin/evm/set_delegated_deployer.cdc b/cadence/transactions/bridge/admin/evm/set_delegated_deployer.cdc new file mode 100644 index 00000000..945f00d7 --- /dev/null +++ b/cadence/transactions/bridge/admin/evm/set_delegated_deployer.cdc @@ -0,0 +1,35 @@ +import "EVM" + +import "EVMUtils" +import "FlowEVMBridgeUtils" + +/// Sets the bridge factory contract address as a delegated deployer in the provided deployer contract. This enables the +/// factory contract to deploy new contracts via the deployer contract. +/// +/// @param deployerEVMAddressHex The EVM address of the deployer contract as a hex string without the '0x' prefix +/// +transaction(deployerEVMAddressHex: String) { + + let coa: auth(EVM.Call) &EVM.CadenceOwnedAccount + + prepare(signer: auth(BorrowValue) &Account) { + self.coa = signer.storage.borrow(from: /storage/evm) + ?? panic("Could not borrow COA from provided gateway address") + } + + execute { + let deployerEVMAddress = EVMUtils.getEVMAddressFromHexString(address: deployerEVMAddressHex) + ?? panic("Could not convert deployer contract address to EVM address") + + let callResult = self.coa.call( + to: deployerEVMAddress, + data: EVM.encodeABIWithSignature( + "setDelegatedDeployer(address)", + [FlowEVMBridgeUtils.bridgeFactoryEVMAddress] + ), + gasLimit: 15_000_000, + value: EVM.Balance(attoflow: 0) + ) + assert(callResult.status == EVM.Status.successful, message: "Failed to set delegated deployer") + } +} diff --git a/cadence/transactions/bridge/admin/evm/set_deployment_registry.cdc b/cadence/transactions/bridge/admin/evm/set_deployment_registry.cdc new file mode 100644 index 00000000..cfd8c79a --- /dev/null +++ b/cadence/transactions/bridge/admin/evm/set_deployment_registry.cdc @@ -0,0 +1,39 @@ +import "EVM" + +import "EVMUtils" +import "FlowEVMBridgeUtils" + +/// This transaction sets the address of the registry contract in the bridge factory contract. The registry contract +/// is tasked with maintaining associations between bridge-deployed EVM contracts and their corresponding Cadence +/// implementations. +/// +/// NOTE: This is a sensitive operation as the registry contract serves as the source of truth for bridge-deployed +/// contracts. +/// +/// @param registryEVMAddressHex The EVM address of the registry contract as a hex string without the '0x' prefix. +/// +transaction(registryEVMAddressHex: String) { + + let coa: auth(EVM.Call) &EVM.CadenceOwnedAccount + + prepare(signer: auth(BorrowValue) &Account) { + self.coa = signer.storage.borrow(from: /storage/evm) + ?? panic("Could not borrow COA from provided gateway address") + } + + execute { + let registryEVMAddress = EVMUtils.getEVMAddressFromHexString(address: registryEVMAddressHex) + ?? panic("Could not convert registry address to EVM address") + + let callResult = self.coa.call( + to: FlowEVMBridgeUtils.bridgeFactoryEVMAddress, + data: EVM.encodeABIWithSignature( + "setDeploymentRegistry(address)", + [registryEVMAddress] + ), + gasLimit: 15_000_000, + value: EVM.Balance(attoflow: 0) + ) + assert(callResult.status == EVM.Status.successful, message: "Failed to set delegated deployer") + } +} diff --git a/cadence/transactions/bridge/admin/evm/set_registrar.cdc b/cadence/transactions/bridge/admin/evm/set_registrar.cdc new file mode 100644 index 00000000..25158e2e --- /dev/null +++ b/cadence/transactions/bridge/admin/evm/set_registrar.cdc @@ -0,0 +1,35 @@ +import "EVM" + +import "EVMUtils" +import "FlowEVMBridgeUtils" + +/// Sets the bridge factory contract address as the registrar for the provided FlowBridgeDeploymentRegistry address. +/// Should be called by the owner of the registry contract. +/// +/// @param registryEVMAddressHex The EVM address of the FlowBridgeDeploymentRegistry contract. +/// +transaction(registryEVMAddressHex: String) { + + let coa: auth(EVM.Call) &EVM.CadenceOwnedAccount + + prepare(signer: auth(BorrowValue) &Account) { + self.coa = signer.storage.borrow(from: /storage/evm) + ?? panic("Could not borrow COA from provided gateway address") + } + + execute { + let registryEVMAddress = EVMUtils.getEVMAddressFromHexString(address: registryEVMAddressHex) + ?? panic("Could not convert registry address to EVM address") + + let callResult = self.coa.call( + to: registryEVMAddress, + data: EVM.encodeABIWithSignature( + "setRegistrar(address)", + [FlowEVMBridgeUtils.bridgeFactoryEVMAddress] + ), + gasLimit: 15_000_000, + value: EVM.Balance(attoflow: 0) + ) + assert(callResult.status == EVM.Status.successful, message: "Failed to set registrar") + } +} diff --git a/cadence/transactions/evm/create_account.cdc b/cadence/transactions/evm/create_account.cdc index fe389d56..57d31241 100644 --- a/cadence/transactions/evm/create_account.cdc +++ b/cadence/transactions/evm/create_account.cdc @@ -21,7 +21,6 @@ transaction(amount: UFix64) { let coa <- EVM.createCadenceOwnedAccount() coa.deposit(from: <-self.sentVault) - log(coa.balance().inFLOW()) let storagePath = StoragePath(identifier: "evm")! let publicPath = PublicPath(identifier: "evm")! self.auth.storage.save<@EVM.CadenceOwnedAccount>(<-coa, to: storagePath) diff --git a/solidity/script/Counter.s.sol b/solidity/script/Counter.s.sol deleted file mode 100644 index 29938afe..00000000 --- a/solidity/script/Counter.s.sol +++ /dev/null @@ -1,12 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity ^0.8.17; - -import {Script, console2} from "forge-std/Script.sol"; - -contract CounterScript is Script { - function setUp() public {} - - function run() public { - vm.broadcast(); - } -} diff --git a/solidity/src/FlowBridgeDeploymentRegistry.sol b/solidity/src/FlowBridgeDeploymentRegistry.sol new file mode 100644 index 00000000..ff34f937 --- /dev/null +++ b/solidity/src/FlowBridgeDeploymentRegistry.sol @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.17; + +import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; +import {ERC165} from "@openzeppelin/contracts/utils/introspection/ERC165.sol"; +import {FlowEVMDeploymentRegistry} from "./interfaces/FlowEVMDeploymentRegistry.sol"; + +/** + * @title FlowBridgeDeploymentRegistry + * @dev A contract to manage the association between bridged Flow EVM contracts and a corresponding Cadence resource type. + * Deployment of new bridged Flow EVM contracts is handled in `FlowBridgeFactory`. + */ +contract FlowBridgeDeploymentRegistry is FlowEVMDeploymentRegistry, Ownable { + constructor() Ownable(msg.sender) { + registrar = msg.sender; + } + + /** + * @dev Set the registrar address as the entity that can register new deployments. Only the owner can call this + * function. + * + * @param _registrar The address of the registrar + */ + function setRegistrar(address _registrar) external onlyOwner { + _setRegistrar(_registrar); + } +} diff --git a/solidity/src/FlowBridgeFactory.sol b/solidity/src/FlowBridgeFactory.sol index 93361415..2e3a306c 100644 --- a/solidity/src/FlowBridgeFactory.sol +++ b/solidity/src/FlowBridgeFactory.sol @@ -1,76 +1,126 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.17; -import "@openzeppelin/contracts/access/Ownable.sol"; -import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; -import "@openzeppelin/contracts/utils/introspection/ERC165.sol"; -import "./templates/FlowBridgedERC721.sol"; -import "./templates/FlowBridgedERC20.sol"; -import "./interfaces/IBridgePermissions.sol"; +import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; +import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import {ERC165} from "@openzeppelin/contracts/utils/introspection/ERC165.sol"; +import {IBridgePermissions} from "./interfaces/IBridgePermissions.sol"; +import {IFlowEVMBridgeDeployer} from "./interfaces/IFlowEVMBridgeDeployer.sol"; +import {IFlowEVMDeploymentRegistry} from "./interfaces/IFlowEVMDeploymentRegistry.sol"; +import {FlowEVMDeploymentRegistry} from "./interfaces/FlowEVMDeploymentRegistry.sol"; +/** + * @title FlowBridgeFactory + * @dev Factory contract to deploy new FlowEVM bridge contracts, defining Cadence-native assets in EVM. Cadence & EVM + * contract associations are maintained in a deployment registry. This factory is enabled to deploy contracts via + * registered deployer implementations, each of which handle the deployment of a single templated contract indexed by + * a human-readable deployer tag. This setup modularizes each key component of the EVM side of the Flow EVM VM bridge, + * allowing new asset types to be added by simply adding a new deployer implementation or updated factory contract + * to be swapped out without affecting the underlying associations between Cadence and EVM contracts. + */ contract FlowBridgeFactory is Ownable { - mapping(string => address) public flowIdentifierToContract; - mapping(address => string) public contractToflowIdentifier; + // Address of the deployment registry where deployed contract associations are registered. Note that this is a + // registry for EVM contracts deployed by the bridge factory and does not include those EVM-native contracts that + // have been onboarded to the bridge via Cadence contracts. The global source of truth is found in the Cadence + // side of the bridge, however this registry and publicly accessible methods can serve as a source of truth + // within EVM. Given some EVM contract, its bridge-supported Cadence type association can be found (and vice-versa) + // by querying this contract, thus preventing impersonation attacks. + address private deploymentRegistry; + // Mapping of deployer tags to their implementation addresses + mapping(string => address) private deployers; - constructor() Ownable(msg.sender) {} - - event ERC20Deployed( - address contractAddress, string name, string symbol, string flowTokenAddress, string flowTokenIdentifier - ); - event ERC721Deployed( - address contractAddress, string name, string symbol, string flowNFTAddress, string flowNFTIdentifier - ); - - // Function to deploy a new ERC721 contract - function deployERC20( - string memory name, - string memory symbol, - string memory flowTokenAddress, - string memory flowTokenIdentifier, - string memory contractURI - ) public onlyOwner returns (address) { - FlowBridgedERC20 newERC20 = - new FlowBridgedERC20(super.owner(), name, symbol, flowTokenAddress, flowTokenIdentifier, contractURI); - - flowIdentifierToContract[flowTokenIdentifier] = address(newERC20); - contractToflowIdentifier[address(newERC20)] = flowTokenIdentifier; - - emit ERC20Deployed(address(newERC20), name, symbol, flowTokenAddress, flowTokenIdentifier); + /** + * @dev Emitted when a deployer is added to the factory + */ + event DeployerAdded(string tag, address deployerAddress); + /** + * @dev Emitted when a deployer is updated in the factory + */ + event DeployerUpdated(string tag, address oldAddress, address newAddress); + /** + * @dev Emitted when a deployer is removed from the factory + */ + event DeployerRemoved(string tag, address oldAddress); + /** + * @dev Emitted when the deployment registry is updated + */ + event DeploymentRegistryUpdated(address oldAddress, address newAddress); - return address(newERC20); - } + constructor() Ownable(msg.sender) {} - // Function to deploy a new ERC721 contract - function deployERC721( + /** + * @dev Deploys a new asset contract via a registered deployer + * + * @param deployerTag The tag of the deployer to use as set by the owner + * @param name The name of the asset + * @param symbol The symbol of the asset + * @param cadenceAddress The Flow account address of the Cadence implementation + * @param cadenceIdentifier The Cadence identifier of the asset type + * @param contractURI The URI of the contract metadata for the asset + * + * @return The address of the newly deployed contract + */ + function deploy( + string memory deployerTag, string memory name, string memory symbol, - string memory flowNFTAddress, - string memory flowNFTIdentifier, + string memory cadenceAddress, + string memory cadenceIdentifier, string memory contractURI ) public onlyOwner returns (address) { - FlowBridgedERC721 newERC721 = - new FlowBridgedERC721(super.owner(), name, symbol, flowNFTAddress, flowNFTIdentifier, contractURI); + address deployerAddress = deployers[deployerTag]; + _requireIsValidDeployer(deployerAddress); + IFlowEVMBridgeDeployer deployer = IFlowEVMBridgeDeployer(deployerAddress); - flowIdentifierToContract[flowNFTIdentifier] = address(newERC721); - contractToflowIdentifier[address(newERC721)] = flowNFTIdentifier; + address newContract = deployer.deploy(name, symbol, cadenceAddress, cadenceIdentifier, contractURI); - emit ERC721Deployed(address(newERC721), name, symbol, flowNFTAddress, flowNFTIdentifier); + _registerDeployment(cadenceIdentifier, newContract); - return address(newERC721); + return newContract; } - function getFlowAssetIdentifier(address contractAddr) public view returns (string memory) { - return contractToflowIdentifier[contractAddr]; + /** + * @dev Retrieves the Cadence type identifier associated with the bridge-deployed contract + * + * @param contractAddr The address of the deployed contract + * + * @return The Cadence identifier of the contract + */ + function getCadenceIdentifier(address contractAddr) public view returns (string memory) { + return FlowEVMDeploymentRegistry(deploymentRegistry).getCadenceIdentifier(contractAddr); } - function getContractAddress(string memory flowNFTIdentifier) public view returns (address) { - return flowIdentifierToContract[flowNFTIdentifier]; + /** + * @dev Retrieves the address of a bridge-deployed contract by its associated Cadence type identifier + * + * @param cadenceIdentifier The Cadence type identifier of the contract + * + * @return The address of the deployed contract + */ + function getContractAddress(string memory cadenceIdentifier) public view returns (address) { + return FlowEVMDeploymentRegistry(deploymentRegistry).getContractAddress(cadenceIdentifier); } - function isFactoryDeployed(address contractAddr) public view returns (bool) { - return bytes(contractToflowIdentifier[contractAddr]).length != 0; + /** + * @dev Checks if a contract address is associated with a registered deployment + * + * @param contractAddr The address of the deployed contract + * + * @return True if the contract is a registered deployment, false otherwise + */ + function isBridgeDeployed(address contractAddr) public view returns (bool) { + return FlowEVMDeploymentRegistry(deploymentRegistry).isRegisteredDeployment(contractAddr); } + /** + * @dev Makes a best guess if the contract address is an ERC20 token by calling the publicly accessible ERC20 + * interface methods on the contract via staticcall to prevent reverts. Note, since ERC20 does not implement + * ERC165, this is a best guess and may result in false positives. + * + * @param contractAddr The address of the contract to check + * + * @return True if the contract is an ERC20 token, false otherwise + */ function isERC20(address contractAddr) public view returns (bool) { (bool success, bytes memory data) = contractAddr.staticcall(abi.encodeWithSignature("totalSupply()")); if (!success || data.length == 0) { @@ -100,6 +150,14 @@ contract FlowBridgeFactory is Ownable { return true; } + /** + * @dev Determines if a contract is an ERC721 token by checking if it implements the ERC721 interface via ERC165 + * supportsInterface call. + * + * @param contractAddr The address of the contract to check + * + * @return True if the contract is an ERC721 token, false otherwise + */ function isERC721(address contractAddr) public view returns (bool) { try ERC165(contractAddr).supportsInterface(0x80ac58cd) returns (bool support) { return support; @@ -107,4 +165,162 @@ contract FlowBridgeFactory is Ownable { return false; } } + + /** + * @dev Determines if a contract is a valid asset by checking if it is either an ERC20 or ERC721 implementation + * + * @param contractAddr The address of the contract to check + * + * @return True if the contract is a valid asset, false otherwise + */ + function isValidAsset(address contractAddr) public view returns (bool) { + return isERC20(contractAddr) != isERC721(contractAddr); + } + + /** + * @dev Retrieves the address of the deployment registry + * + * @return The address of the deployment registry + */ + function getRegistry() public view returns (address) { + return deploymentRegistry; + } + + /** + * @dev Retrieves the address of a deployer by its tag + * + * @param tag The tag of the deployer + * + * @return The address of the deployer + */ + function getDeployer(string memory tag) public view returns (address) { + return deployers[tag]; + } + + /** + * @dev Sets the address of the deployment registry + * + * @param _deploymentRegistry The address of the deployment registry + */ + function setDeploymentRegistry(address _deploymentRegistry) public onlyOwner { + _requireIsValidRegistry(_deploymentRegistry); + + emit DeploymentRegistryUpdated(deploymentRegistry, _deploymentRegistry); + + deploymentRegistry = _deploymentRegistry; + } + + /** + * @dev Adds a new deployer to the factory + * + * @param tag The tag of the deployer + * @param deployerAddress The address of the deployer + * + * emits a {DeployerAdded} event + */ + function addDeployer(string memory tag, address deployerAddress) public onlyOwner { + _requireIsValidDeployer(deployerAddress); + require(deployers[tag] == address(0), "FlowBridgeFactory: Deployer already registered"); + deployers[tag] = deployerAddress; + + emit DeployerAdded(tag, deployerAddress); + } + + /** + * @dev Adds a deployer to the factory, or updates the address of an existing deployer + * + * @param tag The tag of the deployer + * + * emits a {DeployerUpdated} event if the deployer already exists otherwise a {DeployerAdded} event + */ + function upsertDeployer(string memory tag, address deployerAddress) public onlyOwner { + _requireIsValidDeployer(deployerAddress); + + address oldAddress = deployers[tag]; + if (oldAddress == address(0)) { + addDeployer(tag, deployerAddress); + return; + } + + deployers[tag] = deployerAddress; + + emit DeployerUpdated(tag, oldAddress, deployerAddress); + } + + /** + * @dev Removes a deployer from the factory + * + * @param tag The tag of the deployer + * + * emits a {DeployerRemoved} event + */ + function removeDeployer(string memory tag) public onlyOwner { + address oldAddress = deployers[tag]; + require(oldAddress != address(0), "FlowBridgeFactory: Deployer not registered"); + + delete deployers[tag]; + + emit DeployerRemoved(tag, oldAddress); + } + + /** + * @dev Registers a new deployment in the deployment registry + * + * @param cadenceIdentifier The Cadence identifier of the deployed contract + * @param contractAddr The address of the deployed contract + */ + function _registerDeployment(string memory cadenceIdentifier, address contractAddr) internal { + FlowEVMDeploymentRegistry registry = FlowEVMDeploymentRegistry(deploymentRegistry); + registry.registerDeployment(cadenceIdentifier, contractAddr); + } + + /** + * @dev Asserts that the registry address is non-zero and implements the IFlowEVMDeploymentRegistry interface + * + * @param registryAddr The address of the registry to check + */ + function _requireIsValidRegistry(address registryAddr) internal view { + _requireNotZeroAddress(registryAddr); + require( + _implementsInterface(registryAddr, type(IFlowEVMDeploymentRegistry).interfaceId), + "FlowBridgeFactory: Invalid registry" + ); + } + + /** + * @dev Asserts that the contract address is non-zero and implements the IFlowEVMBridgeDeployer interface + * + * @param contractAddr The address of the contract to check + */ + function _requireIsValidDeployer(address contractAddr) internal view { + _requireNotZeroAddress(contractAddr); + require( + _implementsInterface(contractAddr, type(IFlowEVMBridgeDeployer).interfaceId), + "FlowBridgeFactory: Invalid deployer" + ); + } + + /** + * @dev Checks if a contract implements a specific interface + * + * @param contractAddr The address of the contract to check + * + * @return True if the contract implements the interface, false otherwise + */ + function _implementsInterface(address contractAddr, bytes4 interfaceId) internal view returns (bool) { + try ERC165(contractAddr).supportsInterface(interfaceId) returns (bool support) { + return support; + } catch { + return false; + } + } + + /** + * @dev Asserts that the address is non-zero + * + * @param addr The address to check + */ + function _requireNotZeroAddress(address addr) internal pure { + require(addr != address(0), "FlowBridgeFactory: Zero address"); + } } diff --git a/solidity/src/FlowEVMBridgedERC20Deployer.sol b/solidity/src/FlowEVMBridgedERC20Deployer.sol new file mode 100644 index 00000000..6d1aa8e2 --- /dev/null +++ b/solidity/src/FlowEVMBridgedERC20Deployer.sol @@ -0,0 +1,81 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.17; + +import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; +import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; +import {ERC165} from "@openzeppelin/contracts/utils/introspection/ERC165.sol"; +import {IFlowEVMBridgeDeployer} from "./interfaces/IFlowEVMBridgeDeployer.sol"; +import {FlowEVMBridgedERC20} from "./templates/FlowEVMBridgedERC20.sol"; + +/** + * @title FlowEVMBridgedERC20Deployer + * @dev A contract to deploy FlowEVMBridgedERC20 contracts with named associations to Cadence resources types. Only the + * delegated deployer can deploy new contracts. This contract is used by the Flow EVM bridge to deploy and define + * bridged ERC20 tokens which are defined natively in Cadence. + */ +contract FlowEVMBridgedERC20Deployer is IFlowEVMBridgeDeployer, ERC165, Ownable { + // The address of the delegated deployer who can deploy new contracts + address public delegatedDeployer; + + /** + * @dev Event emitted when a new ERC20 contract is deployed via this deployer + */ + event ERC20Deployed( + address contractAddress, string name, string symbol, string cadenceTokenAddress, string cadenceVaultIdentifier + ); + + constructor() Ownable(msg.sender) {} + + /** + * @dev Modifier to check if the caller is the delegated deployer + */ + modifier onlyDelegatedDeployer() { + require(msg.sender == delegatedDeployer, "FlowEVMBridgedERC20Deployer: Only delegated deployer can deploy"); + _; + } + + /** + * @dev ERC165 introspection + */ + function supportsInterface(bytes4 interfaceId) public view override(IERC165, ERC165) returns (bool) { + return interfaceId == type(IFlowEVMBridgeDeployer).interfaceId || super.supportsInterface(interfaceId); + } + + /** + * @dev Deploy a new FlowEVMBridgedERC20 contract with the given name, symbol, and association to a Cadence + * contract. + * + * @param name The name of the ERC20 + * @param symbol The symbol of the ERC20 + * @param cadenceAddress The address of the associated Cadence contract + * @param cadenceIdentifier The identifier of the associated Cadence asset type + * @param contractURI The URI of the contract metadata + * + * @return The address of the deployed EVM contract + */ + function deploy( + string memory name, + string memory symbol, + string memory cadenceAddress, + string memory cadenceIdentifier, + string memory contractURI + ) external onlyDelegatedDeployer returns (address) { + FlowEVMBridgedERC20 newERC20 = + new FlowEVMBridgedERC20(super.owner(), name, symbol, cadenceAddress, cadenceIdentifier, contractURI); + + emit ERC20Deployed(address(newERC20), name, symbol, cadenceAddress, cadenceIdentifier); + + return address(newERC20); + } + + /** + * @dev Set the delegated deployer address as the entity that can deploy new contracts. Only the owner can call this + * function. + * + * @param _delegatedDeployer The address of the delegated deployer + */ + function setDelegatedDeployer(address _delegatedDeployer) external onlyOwner { + require(_delegatedDeployer != address(0), "FlowEVMBridgedERC20Deployer: Invalid delegated deployer address"); + delegatedDeployer = _delegatedDeployer; + } +} diff --git a/solidity/src/FlowEVMBridgedERC721Deployer.sol b/solidity/src/FlowEVMBridgedERC721Deployer.sol new file mode 100644 index 00000000..7f55cde0 --- /dev/null +++ b/solidity/src/FlowEVMBridgedERC721Deployer.sol @@ -0,0 +1,81 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.17; + +import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; +import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; +import {ERC165} from "@openzeppelin/contracts/utils/introspection/ERC165.sol"; +import {IFlowEVMBridgeDeployer} from "./interfaces/IFlowEVMBridgeDeployer.sol"; +import {FlowEVMBridgedERC721} from "./templates/FlowEVMBridgedERC721.sol"; + +/** + * @title FlowEVMBridgedERC721Deployer + * @dev A contract to deploy FlowEVMBridgedERC721 contracts with named associations to Cadence resource types. Only the + * delegated deployer can deploy new contracts. This contract is used by the Flow EVM bridge to deploy and define + * bridged ERC721 tokens which are defined natively in Cadence. + */ +contract FlowEVMBridgedERC721Deployer is IFlowEVMBridgeDeployer, ERC165, Ownable { + // The address of the delegated deployer who can deploy new contracts + address public delegatedDeployer; + + /** + * @dev Event emitted when a new ERC721 contract is deployed via this deployer + */ + event ERC721Deployed( + address contractAddress, string name, string symbol, string cadenceNFTAddress, string cadenceNFTIdentifier + ); + + constructor() Ownable(msg.sender) {} + + /** + * @dev Modifier to check if the caller is the delegated deployer + */ + modifier onlyDelegatedDeployer() { + require(msg.sender == delegatedDeployer, "FlowEVMBridgedERC721Deployer: Only delegated deployer can deploy"); + _; + } + + /** + * @dev ERC165 introspection + */ + function supportsInterface(bytes4 interfaceId) public view override(IERC165, ERC165) returns (bool) { + return interfaceId == type(IFlowEVMBridgeDeployer).interfaceId || super.supportsInterface(interfaceId); + } + + /** + * @dev Deploy a new FlowEVMBridgedERC721 contract with the given name, symbol, and association to a Cadence + * contract. + * + * @param name The name of the ERC721 + * @param symbol The symbol of the ERC721 + * @param cadenceAddress The address of the associated Cadence contract + * @param cadenceIdentifier The identifier of the associated Cadence asset type + * @param contractURI The URI of the contract metadata + * + * @return The address of the deployed EVM contract + */ + function deploy( + string memory name, + string memory symbol, + string memory cadenceAddress, + string memory cadenceIdentifier, + string memory contractURI + ) external onlyDelegatedDeployer returns (address) { + FlowEVMBridgedERC721 newERC721 = + new FlowEVMBridgedERC721(super.owner(), name, symbol, cadenceAddress, cadenceIdentifier, contractURI); + + emit ERC721Deployed(address(newERC721), name, symbol, cadenceAddress, cadenceIdentifier); + + return address(newERC721); + } + + /** + * @dev Set the address of the delegated deployer + * + * @param _delegatedDeployer The address of the delegated deployer + */ + function setDelegatedDeployer(address _delegatedDeployer) external onlyOwner { + require(_delegatedDeployer != address(0), "FlowEVMBridgedERC721Deployer: Invalid delegated deployer address"); + delegatedDeployer = _delegatedDeployer; + } +} diff --git a/solidity/src/interfaces/BridgePermissions.sol b/solidity/src/interfaces/BridgePermissions.sol index a3504990..92069ac3 100644 --- a/solidity/src/interfaces/BridgePermissions.sol +++ b/solidity/src/interfaces/BridgePermissions.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.17; -import "@openzeppelin/contracts/utils/introspection/IERC165.sol"; -import "@openzeppelin/contracts/utils/introspection/ERC165.sol"; -import "./IBridgePermissions.sol"; +import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; +import {ERC165} from "@openzeppelin/contracts/utils/introspection/ERC165.sol"; +import {IBridgePermissions} from "./IBridgePermissions.sol"; /** * @dev Contract for which implementation is checked by the Flow VM bridge as an opt-out mechanism diff --git a/solidity/src/interfaces/FlowEVMDeploymentRegistry.sol b/solidity/src/interfaces/FlowEVMDeploymentRegistry.sol new file mode 100644 index 00000000..dcdfd7f8 --- /dev/null +++ b/solidity/src/interfaces/FlowEVMDeploymentRegistry.sol @@ -0,0 +1,106 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.17; + +import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; +import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; +import {ERC165} from "@openzeppelin/contracts/utils/introspection/ERC165.sol"; +import {IFlowEVMDeploymentRegistry} from "./IFlowEVMDeploymentRegistry.sol"; + +/** + * @title FlowEVMDeploymentRegistry + * @dev A contract to manage the deployment of Flow EVM contracts and their association with Cadence contracts. Only the + * registrar can register new deployments. + */ +abstract contract FlowEVMDeploymentRegistry is IFlowEVMDeploymentRegistry, ERC165 { + // The address of the registrar who can register new deployments + address public registrar; + // Association between Cadence type identifiers and deployed contract addresses + mapping(string => address) private cadenceIdentifierToContract; + // Reverse association between deployed contract addresses and Cadence type identifiers + mapping(address => string) private contractToCadenceIdentifier; + + modifier onlyRegistrar() { + require(msg.sender == registrar, "FlowBridgeDeploymentRegistry: Only registrar can register association"); + _; + } + + /** + * @dev ERC165 introspection + */ + function supportsInterface(bytes4 interfaceId) public view override(IERC165, ERC165) returns (bool) { + return interfaceId == type(IFlowEVMDeploymentRegistry).interfaceId || super.supportsInterface(interfaceId); + } + + /** + * @dev Get the Cadence type identifier associated with a contract address + * + * @param contractAddr The address of the deployed contract + * + * @return The Cadence type identifier + */ + function getCadenceIdentifier(address contractAddr) external view returns (string memory) { + return contractToCadenceIdentifier[contractAddr]; + } + + /** + * @dev Get the contract address associated with a Cadence type identifier + * + * @param cadenceIdentifier The Cadence type identifier + * + * @return The address of the associated contract + */ + function getContractAddress(string memory cadenceIdentifier) external view returns (address) { + return cadenceIdentifierToContract[cadenceIdentifier]; + } + + /** + * @dev Check if a contract address is a registered deployment + * + * @param cadenceIdentifier The Cadence type identifier in question + * + * @return True if the contract address is associated with a Cadence type identifier as a registered deployment + */ + function isRegisteredDeployment(string memory cadenceIdentifier) external view returns (bool) { + return cadenceIdentifierToContract[cadenceIdentifier] != address(0); + } + + /** + * @dev Check if a Cadence type identifier is associated with a registered deployment + * + * @param contractAddr The address of the contract in question + * + * @return True if the contract address is associated with a Cadence type identifier as a registered deployment + */ + function isRegisteredDeployment(address contractAddr) external view returns (bool) { + return bytes(contractToCadenceIdentifier[contractAddr]).length != 0; + } + + /** + * @dev Register a new deployment address with the given Cadence type identifier. Can only be called by the + * current registrar. + * + * @param cadenceIdentifier The Cadence type identifier + * @param contractAddr The address of the deployed contract + */ + function registerDeployment(string memory cadenceIdentifier, address contractAddr) external onlyRegistrar { + _registerDeployment(cadenceIdentifier, contractAddr); + } + + /** + * @dev Internal function to register a new deployment address with the given Cadence type identifier + * + * @param cadenceIdentifier The Cadence type identifier + * @param contractAddr The address of the deployed contract + */ + function _registerDeployment(string memory cadenceIdentifier, address contractAddr) internal { + cadenceIdentifierToContract[cadenceIdentifier] = contractAddr; + contractToCadenceIdentifier[contractAddr] = cadenceIdentifier; + } + + /** + * @dev Set the registrar address as the entity that can register new deployments. Only the owner can execute this. + */ + function _setRegistrar(address _registrar) internal { + registrar = _registrar; + } +} diff --git a/solidity/src/interfaces/IBridgePermissions.sol b/solidity/src/interfaces/IBridgePermissions.sol index ea8eed18..ccce6404 100644 --- a/solidity/src/interfaces/IBridgePermissions.sol +++ b/solidity/src/interfaces/IBridgePermissions.sol @@ -1,17 +1,16 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.17; -import "@openzeppelin/contracts/utils/introspection/IERC165.sol"; +import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; interface IBridgePermissions is IERC165 { - /** * @dev Emitted when the permissions for the contract are updated. */ event PermissionsUpdated(bool newPermissions); - + /** * @dev Returns true if the contract allows bridging of its assets. */ function allowsBridging() external view returns (bool); -} \ No newline at end of file +} diff --git a/solidity/src/interfaces/IFlowEVMBridgeDeployer.sol b/solidity/src/interfaces/IFlowEVMBridgeDeployer.sol new file mode 100644 index 00000000..6e65236a --- /dev/null +++ b/solidity/src/interfaces/IFlowEVMBridgeDeployer.sol @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.17; + +import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; + +/** + * @title IFlowEVMBridgeDeployer + * @dev Interface contracts on FlowEVM which deploys EVM contracts with named associations to Cadence contracts. + */ +interface IFlowEVMBridgeDeployer is IERC165 { + /** + * @dev Deploy a new EVM contract with the given name, symbol, and association to a Cadence contract. + * + * @param name The name of the EVM asset + * @param symbol The symbol of the EVM asset + * @param cadenceAddress The address of the associated Cadence contract + * @param cadenceIdentifier The identifier of the associated Cadence asset type + * @param contractURI The URI of the contract metadata + * + * @return The address of the deployed EVM contract + */ + function deploy( + string memory name, + string memory symbol, + string memory cadenceAddress, + string memory cadenceIdentifier, + string memory contractURI + ) external returns (address); +} diff --git a/solidity/src/interfaces/IFlowEVMDeploymentRegistry.sol b/solidity/src/interfaces/IFlowEVMDeploymentRegistry.sol new file mode 100644 index 00000000..110f8a0f --- /dev/null +++ b/solidity/src/interfaces/IFlowEVMDeploymentRegistry.sol @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.17; + +import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; + +/** + * @title IFlowEVMDeploymentRegistry + * @dev Interface for the FlowEVMDeploymentRegistry contract, intended to be used for contracts that need to manage + * associations between Flow EVM contracts and Cadence contracts. + */ +interface IFlowEVMDeploymentRegistry is IERC165 { + /** + * @dev Get the Cadence type identifier associated with a contract address + */ + function getCadenceIdentifier(address contractAddr) external view returns (string memory); + + /** + * @dev Get the contract address associated with a Cadence type identifier + */ + function getContractAddress(string memory cadenceIdentifier) external view returns (address); + + /** + * @dev Check if a contract address is associated with a Cadence type identifier + */ + function isRegisteredDeployment(address contractAddr) external view returns (bool); + + /** + * @dev Check if a Cadence type identifier is associated with a contract address + */ + function isRegisteredDeployment(string memory cadenceIdentifier) external view returns (bool); +} diff --git a/solidity/src/templates/FlowBridgedERC20.sol b/solidity/src/templates/FlowEVMBridgedERC20.sol similarity index 73% rename from solidity/src/templates/FlowBridgedERC20.sol rename to solidity/src/templates/FlowEVMBridgedERC20.sol index a8deb0a2..fca09940 100644 --- a/solidity/src/templates/FlowBridgedERC20.sol +++ b/solidity/src/templates/FlowEVMBridgedERC20.sol @@ -2,12 +2,12 @@ // Compatible with OpenZeppelin Contracts ^5.0.0 pragma solidity ^0.8.17; -import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; -import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol"; -import "@openzeppelin/contracts/access/Ownable.sol"; -import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Permit.sol"; +import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import {ERC20Burnable} from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol"; +import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; +import {ERC20Permit} from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Permit.sol"; -contract FlowBridgedERC20 is ERC20, ERC20Burnable, Ownable, ERC20Permit { +contract FlowEVMBridgedERC20 is ERC20, ERC20Burnable, Ownable, ERC20Permit { string public flowTokenAddress; string public flowTokenIdentifier; string public contractMetadata; diff --git a/solidity/src/templates/FlowBridgedERC721.sol b/solidity/src/templates/FlowEVMBridgedERC721.sol similarity index 79% rename from solidity/src/templates/FlowBridgedERC721.sol rename to solidity/src/templates/FlowEVMBridgedERC721.sol index 4742587c..a9ff920c 100644 --- a/solidity/src/templates/FlowBridgedERC721.sol +++ b/solidity/src/templates/FlowEVMBridgedERC721.sol @@ -1,13 +1,13 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.17; -import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; -import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol"; -import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol"; -import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Burnable.sol"; -import "@openzeppelin/contracts/access/Ownable.sol"; +import {ERC721} from "@openzeppelin/contracts/token/ERC721/ERC721.sol"; +import {ERC721URIStorage} from "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol"; +import {ERC721Enumerable} from "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol"; +import {ERC721Burnable} from "@openzeppelin/contracts/token/ERC721/extensions/ERC721Burnable.sol"; +import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; -contract FlowBridgedERC721 is ERC721, ERC721URIStorage, ERC721Burnable, ERC721Enumerable, Ownable { +contract FlowEVMBridgedERC721 is ERC721, ERC721URIStorage, ERC721Burnable, ERC721Enumerable, Ownable { string public flowNFTAddress; string public flowNFTIdentifier; string public contractMetadata; diff --git a/solidity/test/FlowBridgeFactory.t.sol b/solidity/test/FlowBridgeFactory.t.sol index 5b87090a..477d6f96 100644 --- a/solidity/test/FlowBridgeFactory.t.sol +++ b/solidity/test/FlowBridgeFactory.t.sol @@ -3,14 +3,20 @@ pragma solidity ^0.8.17; import {Test} from "forge-std/Test.sol"; +import {FlowBridgeDeploymentRegistry} from "../src/FlowBridgeDeploymentRegistry.sol"; +import {FlowEVMBridgedERC721Deployer} from "../src/FlowEVMBridgedERC721Deployer.sol"; +import {FlowEVMBridgedERC20Deployer} from "../src/FlowEVMBridgedERC20Deployer.sol"; import {FlowBridgeFactory} from "../src/FlowBridgeFactory.sol"; -import {FlowBridgedERC721} from "../src/templates/FlowBridgedERC721.sol"; -import {FlowBridgedERC20} from "../src/templates/FlowBridgedERC20.sol"; +import {FlowEVMBridgedERC721} from "../src/templates/FlowEVMBridgedERC721.sol"; +import {FlowEVMBridgedERC20} from "../src/templates/FlowEVMBridgedERC20.sol"; contract FlowBridgeFactoryTest is Test { FlowBridgeFactory internal factory; - FlowBridgedERC721 internal deployedERC721Contract; - FlowBridgedERC20 internal deployedERC20Contract; + FlowBridgeDeploymentRegistry internal registry; + FlowEVMBridgedERC20Deployer internal erc20Deployer; + FlowEVMBridgedERC721Deployer internal erc721Deployer; + FlowEVMBridgedERC20 internal deployedERC20Contract; + FlowEVMBridgedERC721 internal deployedERC721Contract; string name; string symbol; @@ -19,11 +25,10 @@ contract FlowBridgeFactoryTest is Test { string flowTokenAddress; string flowTokenIdentifier; string contractURI; - address deployedERC721Address; address deployedERC20Address; + address deployedERC721Address; function setUp() public virtual { - factory = new FlowBridgeFactory(); name = "name"; symbol = "symbol"; flowNFTAddress = "flowNFTAddress"; @@ -32,15 +37,46 @@ contract FlowBridgeFactoryTest is Test { flowTokenIdentifier = "flowTokenIdentifier"; contractURI = "contractURI"; - deployedERC721Address = factory.deployERC721(name, symbol, flowNFTAddress, flowNFTIdentifier, contractURI); - deployedERC20Address = factory.deployERC20(name, symbol, flowTokenAddress, flowTokenIdentifier, contractURI); - deployedERC721Contract = FlowBridgedERC721(deployedERC721Address); - deployedERC20Contract = FlowBridgedERC20(deployedERC20Address); + factory = new FlowBridgeFactory(); + + registry = new FlowBridgeDeploymentRegistry(); + erc20Deployer = new FlowEVMBridgedERC20Deployer(); + erc721Deployer = new FlowEVMBridgedERC721Deployer(); + + factory.setDeploymentRegistry(address(registry)); + registry.setRegistrar(address(factory)); + + erc20Deployer.setDelegatedDeployer(address(factory)); + erc721Deployer.setDelegatedDeployer(address(factory)); + + factory.addDeployer("ERC20", address(erc20Deployer)); + factory.addDeployer("ERC721", address(erc721Deployer)); + + deployedERC20Address = factory.deploy("ERC20", name, symbol, flowTokenAddress, flowTokenIdentifier, contractURI); + deployedERC721Address = factory.deploy("ERC721", name, symbol, flowNFTAddress, flowNFTIdentifier, contractURI); + + deployedERC20Contract = FlowEVMBridgedERC20(deployedERC20Address); + deployedERC721Contract = FlowEVMBridgedERC721(deployedERC721Address); + } + + function test_RegistryIsNonZero() public { + address registryAddress = factory.getRegistry(); + assertNotEq(registryAddress, address(0)); + } + + function test_GetERC20Deployer() public { + address erc20DeployerAddress = factory.getDeployer("ERC20"); + assertEq(erc20DeployerAddress, address(erc20Deployer)); + } + + function test_GetERC721Deployer() public { + address erc721DeployerAddress = factory.getDeployer("ERC721"); + assertEq(erc721DeployerAddress, address(erc721Deployer)); } function test_DeployERC721() public { - bool isFactoryDeployed = factory.isFactoryDeployed(deployedERC721Address); - assertEq(isFactoryDeployed, true); + bool isBridgeDeployed = factory.isBridgeDeployed(deployedERC721Address); + assertEq(isBridgeDeployed, true); } function test_IsERC721True() public { @@ -54,8 +90,8 @@ contract FlowBridgeFactoryTest is Test { } function test_DeployERC20() public { - bool isFactoryDeployed = factory.isFactoryDeployed(deployedERC20Address); - assertEq(isFactoryDeployed, true); + bool isBridgeDeployed = factory.isBridgeDeployed(deployedERC20Address); + assertEq(isBridgeDeployed, true); } function test_IsERC20True() public { @@ -104,7 +140,7 @@ contract FlowBridgeFactoryTest is Test { assertEq(factoryOwner, erc20Owner); } - function test_SuccessfulMint() public { + function test_MintERC721() public { address recipient = address(27); uint256 tokenId = 42; string memory uri = "MOCK_URI"; @@ -113,4 +149,13 @@ contract FlowBridgeFactoryTest is Test { address owner = deployedERC721Contract.ownerOf(tokenId); assertEq(owner, recipient); } + + function test_MintERC20() public { + address recipient = address(27); + uint256 amount = 100e18; + deployedERC20Contract.mint(recipient, amount); + + uint256 balance = deployedERC20Contract.balanceOf(recipient); + assertEq(balance, amount); + } }