diff --git a/.gitignore b/.gitignore index 0a5466db..11ad135a 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,7 @@ db/ # Cadence test framework coverage coverage.json coverage.lcov + +# Keys +*.pkey +*.pem \ No newline at end of file diff --git a/README.md b/README.md index 8c519cde..2c42ae09 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,6 @@ +![Tests](https://github.com/onflow/flow-evm-bridge/actions/workflows/cadence_test.yml/badge.svg) +[![codecov](https://codecov.io/gh/onflow/flow-evm-bridge/graph/badge.svg?token=C1vCK0t88F)](https://codecov.io/gh/onflow/flow-evm-bridge) + # [WIP] Flow EVM Bridge > :warning: This repo is a work in progress :building_construction: @@ -13,8 +16,7 @@ As the bridge contracts are still in development, builders should be aware that Install an EVM-compatible pre-release version of the Flow CLI (currently [v1.12.0-cadence-v1.0.0-M8-2](https://github.com/onflow/flow-cli/releases/tag/v1.12.0-cadence-v1.0.0-M8-2)): ```sh -sudo sh -ci "$(curl -fsSL https://raw.githubusercontent.com/onflow/flow-cli/master/install.sh)" \ - -- v1.12.0-cadence-v1.0.0-M8-2 +sudo sh -ci "$(curl -fsSL https://raw.githubusercontent.com/onflow/flow-cli/feature/stable-cadence/install.sh)" ``` If you wish to interact with the contracts from the EVM side, this repo is configured for use with Foundry. See [Foundry's installation docs](https://book.getfoundry.sh/getting-started/installation) for more information. diff --git a/cadence/args/bridged-nft-code-chunks-args.json b/cadence/args/bridged-nft-code-chunks-args.json index fa46916b..96a56380 100644 --- a/cadence/args/bridged-nft-code-chunks-args.json +++ b/cadence/args/bridged-nft-code-chunks-args.json @@ -7,10 +7,19 @@ "value": [ { "type": "String", - "value": "696d706f7274204e6f6e46756e6769626c65546f6b656e2066726f6d203078663864366530353836623061323063370a696d706f7274204d6574616461746156696577732066726f6d203078663864366530353836623061323063370a696d706f727420566965775265736f6c7665722066726f6d203078663864366530353836623061323063370a696d706f72742046756e6769626c65546f6b656e2066726f6d203078656538323835366266323065326161360a696d706f727420466c6f77546f6b656e2066726f6d203078306165353363623665336634326137390a0a696d706f72742045564d2066726f6d203078663864366530353836623061323063370a0a696d706f7274204943726f7373564d2066726f6d203078663864366530353836623061323063370a696d706f7274204945564d4272696467654e46544d696e7465722066726f6d203078663864366530353836623061323063370a696d706f727420466c6f7745564d4272696467654e4654457363726f772066726f6d203078663864366530353836623061323063370a696d706f727420466c6f7745564d427269646765436f6e6669672066726f6d203078663864366530353836623061323063370a696d706f727420466c6f7745564d4272696467655574696c732066726f6d203078663864366530353836623061323063370a696d706f727420466c6f7745564d4272696467652066726f6d203078663864366530353836623061323063370a696d706f72742043726f7373564d4e46542066726f6d203078663864366530353836623061323063370a0a2f2f2f205468697320636f6e747261637420697320612074656d706c617465207573656420627920466c6f7745564d42726964676520746f20646566696e652045564d2d6e6174697665204e46547320627269646765642066726f6d20466c6f772045564d20746f20466c6f772e0a2f2f2f2055706f6e206465706c6f796d656e74206f66207468697320636f6e74726163742c2074686520636f6e7472616374206e616d65206973206465726976656420617320612066756e6374696f6e206f6620746865206173736574207479706520286865726520616e2045524337323120616b610a2f2f2f20616e204e46542920616e642074686520636f6e747261637427732045564d20616464726573732e20546865206465726976656420636f6e7472616374206e616d65206973207468656e206a6f696e65642077697468207468697320636f6e7472616374277320636f64652c0a2f2f2f207072657061726564206173206368756e6b7320696e20466c6f7745564d42726964676554656d706c61746573206265666f7265206265696e67206465706c6f79656420746f2074686520466c6f772045564d20427269646765206163636f756e742e0a2f2f2f0a2f2f2f204f6e206272696467696e672c2074686520455243373231206973207472616e7366657272656420746f2074686520627269646765277320436164656e63654f776e65644163636f756e742045564d206164647265737320616e642061206e6577204e4654206973206d696e7465642066726f6d0a2f2f2f207468697320636f6e747261637420746f20746865206272696467696e672063616c6c65722e204f6e2072657475726e20746f20466c6f772045564d2c2074686520726576657273652070726f6365737320697320666f6c6c6f776564202d2074686520746f6b656e206973206275726e65640a2f2f2f20696e207468697320636f6e747261637420616e642074686520455243373231206973207472616e7366657272656420746f2074686520646566696e656420726563697069656e742e20496e2074686973207761792c2074686520436164656e636520746f6b656e206163747320617320610a2f2f2f20726570726573656e746174696f6e206f6620626f7468207468652045564d204e465420616e642074687573206f776e6572736869702072696768747320746f2069742075706f6e206272696467696e67206261636b20746f20466c6f772045564d2e0a2f2f2f0a2f2f2f20546f20627269646765206265747765656e20564d732c20612063616c6c65722063616e20656974686572207573652074686520636f6e7472616374206d6574686f647320646566696e65642062656c6f772c206f72207573652074686520466c6f7745564d42726964676527730a2f2f2f206272696467696e67206d6574686f64732077686963682077696c6c2070726f6772616d61746963616c6c7920726f757465206272696467696e672063616c6c7320746f207468697320636f6e74726163742e0a2f2f2f0a2f2f20544f444f3a20496d706c656d656e74204e465420636f6e747261637420696e74657266616365206f6e636520763220617661696c61626c65206c6f63616c6c790a61636365737328616c6c2920636f6e747261637420" + "value": "696d706f7274204e6f6e46756e6769626c65546f6b656e2066726f6d203078663864366530353836623061323063370a696d706f7274204d6574616461746156696577732066726f6d203078663864366530353836623061323063370a696d706f727420566965775265736f6c7665722066726f6d203078663864366530353836623061323063370a696d706f72742046756e6769626c65546f6b656e2066726f6d203078656538323835366266323065326161360a696d706f727420466c6f77546f6b656e2066726f6d203078306165353363623665336634326137390a0a696d706f72742045564d2066726f6d203078663864366530353836623061323063370a0a696d706f7274204943726f7373564d2066726f6d203078663864366530353836623061323063370a696d706f7274204945564d4272696467654e46544d696e7465722066726f6d203078663864366530353836623061323063370a696d706f727420466c6f7745564d4272696467654e4654457363726f772066726f6d203078663864366530353836623061323063370a696d706f727420466c6f7745564d427269646765436f6e6669672066726f6d203078663864366530353836623061323063370a696d706f727420466c6f7745564d4272696467655574696c732066726f6d203078663864366530353836623061323063370a696d706f727420466c6f7745564d4272696467652066726f6d203078663864366530353836623061323063370a696d706f72742043726f7373564d4e46542066726f6d203078663864366530353836623061323063370a0a2f2f2f205468697320636f6e747261637420697320612074656d706c617465207573656420627920466c6f7745564d42726964676520746f20646566696e652045564d2d6e6174697665204e46547320627269646765642066726f6d20466c6f772045564d20746f20466c6f772e0a2f2f2f2055706f6e206465706c6f796d656e74206f66207468697320636f6e74726163742c2074686520636f6e7472616374206e616d65206973206465726976656420617320612066756e6374696f6e206f6620746865206173736574207479706520286865726520616e2045524337323120616b610a2f2f2f20616e204e46542920616e642074686520636f6e747261637427732045564d20616464726573732e20546865206465726976656420636f6e7472616374206e616d65206973207468656e206a6f696e65642077697468207468697320636f6e7472616374277320636f64652c0a2f2f2f207072657061726564206173206368756e6b7320696e20466c6f7745564d42726964676554656d706c61746573206265666f7265206265696e67206465706c6f79656420746f2074686520466c6f772045564d20427269646765206163636f756e742e0a2f2f2f0a2f2f2f204f6e206272696467696e672c2074686520455243373231206973207472616e7366657272656420746f2074686520627269646765277320436164656e63654f776e65644163636f756e742045564d206164647265737320616e642061206e6577204e4654206973206d696e7465642066726f6d0a2f2f2f207468697320636f6e747261637420746f20746865206272696467696e672063616c6c65722e204f6e2072657475726e20746f20466c6f772045564d2c2074686520726576657273652070726f6365737320697320666f6c6c6f776564202d2074686520746f6b656e206973206275726e65640a2f2f2f20696e207468697320636f6e747261637420616e642074686520455243373231206973207472616e7366657272656420746f2074686520646566696e656420726563697069656e742e20496e2074686973207761792c2074686520436164656e636520746f6b656e206163747320617320610a2f2f2f20726570726573656e746174696f6e206f6620626f7468207468652045564d204e465420616e642074687573206f776e6572736869702072696768747320746f2069742075706f6e206272696467696e67206261636b20746f20466c6f772045564d2e0a2f2f2f0a2f2f2f20546f20627269646765206265747765656e20564d732c20612063616c6c65722063616e20656974686572207573652074686520636f6e7472616374206d6574686f647320646566696e65642062656c6f772c206f72207573652074686520466c6f7745564d42726964676527730a2f2f2f206272696467696e67206d6574686f64732077686963682077696c6c2070726f6772616d61746963616c6c7920726f757465206272696467696e672063616c6c7320746f207468697320636f6e74726163742e0a2f2f2f0a61636365737328616c6c2920636f6e747261637420" }, { "type": "String", - "value": "203a204943726f7373564d2c204945564d4272696467654e46544d696e7465722c204e6f6e46756e6769626c65546f6b656e207b0a0a202020202f2f2f20506f696e74657220746f2074686520466163746f7279206465706c6f79656420536f6c696469747920636f6e7472616374206164647265737320646566696e696e672074686520627269646765642061737365740a2020202061636365737328616c6c29206c65742065766d4e4654436f6e7472616374416464726573733a2045564d2e45564d416464726573730a202020202f2f2f204e616d65206f6620746865204e465420636f6c6c656374696f6e20646566696e656420696e2074686520636f72726573706f6e64696e672045524337323120636f6e74726163740a2020202061636365737328616c6c29206c6574206e616d653a20537472696e670a202020202f2f2f2053796d626f6c206f6620746865204e465420636f6c6c656374696f6e20646566696e656420696e2074686520636f72726573706f6e64696e672045524337323120636f6e74726163740a2020202061636365737328616c6c29206c65742073796d626f6c3a20537472696e670a202020202f2f2f20555249206f662074686520636f6e74726163742c20696620617661696c61626c6520617320612076617220696e2063617365207468652062726964676520656e61626c65732063726f73732d564d204d657461646174612073796e63696e6720696e20746865206675747572650a2020202061636365737328616c6c292076617220636f6e74726163745552493a20537472696e673f0a202020202f2f2f2052657461696e206120436f6c6c656374696f6e20746f207265666572656e6365207768656e207265736f6c76696e6720436f6c6c656374696f6e204d657461646174610a202020206163636573732873656c6629206c657420636f6c6c656374696f6e3a2040436f6c6c656374696f6e0a202020202f2f2f204d617070696e67206f6620746f6b656e205552497320696e6465786564206f6e207468656972204552433732312049442e205468697320776f756c64206e6f74206e6f726d616c6c792062652072657461696e65642077697468696e206120436164656e6365204e46540a202020202f2f2f20636f6e74726163742c206275742073696e6365204e4654206d65746164617461206d6179206265207570646174656420696e2045564d2c20697427732072657461696e6564206865726520736f207468617420746865206272696467652063616e207570646174650a202020202f2f2f20697420616761696e73742074686520736f757263652045524337323120636f6e7472616374207768696368206973207472656174656420617320746865204e4654277320736f75726365206f662074727574682e0a2020202061636365737328616c6c29206c657420746f6b656e555249733a207b55496e743235363a20537472696e677d0a0a202020202f2f2f20546865204e4654207265736f7572636520726570726573656e74696e672074686520627269646765642045524337323120746f6b656e0a202020202f2f2f0a2020202061636365737328616c6c29207265736f75726365204e46543a2043726f7373564d4e46542e45564d4e4654207b0a20202020202020202f2f2f2054686520436164656e6365204944206f6620746865204e46540a202020202020202061636365737328616c6c29206c65742069643a2055496e7436340a20202020202020202f2f2f2054686520455243373231204944206f6620746865204e46540a202020202020202061636365737328616c6c29206c65742065766d49443a2055496e743235360a20202020202020202f2f2f20546865206e616d65206f6620746865204e465420617320646566696e656420696e207468652045524337323120636f6e74726163740a202020202020202061636365737328616c6c29206c6574206e616d653a20537472696e670a20202020202020202f2f2f205468652073796d626f6c206f6620746865204e465420617320646566696e656420696e207468652045524337323120636f6e74726163740a202020202020202061636365737328616c6c29206c65742073796d626f6c3a20537472696e670a20202020202020202f2f2f204164646974696f6e616c206f6e636861696e206d657461646174610a202020202020202061636365737328616c6c29206c6574206d657461646174613a207b537472696e673a20416e795374727563747d0a0a2020202020202020696e6974280a2020202020202020202020206e616d653a20537472696e672c0a20202020202020202020202073796d626f6c3a20537472696e672c0a20202020202020202020202065766d49443a2055496e743235362c0a2020202020202020202020206d657461646174613a207b537472696e673a20416e795374727563747d0a202020202020202029207b0a20202020202020202020202073656c662e6e616d65203d206e616d650a20202020202020202020202073656c662e73796d626f6c203d2073796d626f6c0a20202020202020202020202073656c662e6964203d2073656c662e757569640a20202020202020202020202073656c662e65766d4944203d2065766d49440a20202020202020202020202073656c662e6d65746164617461203d206d657461646174610a20202020202020207d0a0a20202020202020202f2f2f2052657475726e7320746865206d65746164617461207669657720747970657320737570706f727465642062792074686973204e46540a202020202020202061636365737328616c6c2920766965772066756e20676574566965777328293a205b547970655d207b0a20202020202020202020202072657475726e205b0a20202020202020202020202020202020547970653c43726f7373564d4e46542e45564d427269646765644d657461646174613e28292c0a20202020202020202020202020202020547970653c4d6574616461746156696577732e53657269616c3e28292c0a20202020202020202020202020202020547970653c4d6574616461746156696577732e4e4654436f6c6c656374696f6e446174613e28292c0a20202020202020202020202020202020547970653c4d6574616461746156696577732e4e4654436f6c6c656374696f6e446973706c61793e28290a2020202020202020202020205d0a20202020202020207d0a0a20202020202020202f2f2f205265736f6c7665732061206d65746164617461207669657720666f722074686973204e46540a202020202020202061636365737328616c6c292066756e207265736f6c766556696577285f20766965773a2054797065293a20416e795374727563743f207b0a2020202020202020202020207377697463682076696577207b0a202020202020202020202020202020202f2f20576520646f6e2774206b6e6f772077686174206b696e64206f662066696c65207468652055524920726570726573656e747320284950465320762048545450292c20736f2077652063616e2774207265736f6c766520446973706c617920766965770a202020202020202020202020202020202f2f20776974682074686520555249206173207468756d626e61696c202d207765206d61792061206e6577207374616e64617264207669657720666f722045564d204e465473202d207468697320697320696e746572696d0a202020202020202020202020202020206361736520547970653c43726f7373564d4e46542e45564d427269646765644d657461646174613e28293a0a202020202020202020202020202020202020202072657475726e2043726f7373564d4e46542e45564d427269646765644d65746164617461280a2020202020202020202020202020202020202020202020206e616d653a2073656c662e6e616d652c0a20202020202020202020202020202020202020202020202073796d626f6c3a2073656c662e73796d626f6c2c0a2020202020202020202020202020202020202020202020207572693a2043726f7373564d4e46542e55524928626173655552493a206e696c2c2076616c75653a2073656c662e746f6b656e5552492829290a2020202020202020202020202020202020202020290a202020202020202020202020202020206361736520547970653c4d6574616461746156696577732e53657269616c3e28293a0a202020202020202020202020202020202020202072657475726e204d6574616461746156696577732e53657269616c280a20202020202020202020202020202020202020202020202073656c662e69640a2020202020202020202020202020202020202020290a202020202020202020202020202020206361736520547970653c4d6574616461746156696577732e4e4654436f6c6c656374696f6e446174613e28293a0a202020202020202020202020202020202020202072657475726e20" + "value": "203a204943726f7373564d2c204945564d4272696467654e46544d696e7465722c204e6f6e46756e6769626c65546f6b656e207b0a0a202020202f2f2f20506f696e74657220746f2074686520466163746f7279206465706c6f79656420536f6c696469747920636f6e7472616374206164647265737320646566696e696e672074686520627269646765642061737365740a2020202061636365737328616c6c29206c65742065766d4e4654436f6e7472616374416464726573733a2045564d2e45564d416464726573730a202020202f2f2f204e616d65206f6620746865204e465420636f6c6c656374696f6e20646566696e656420696e2074686520636f72726573706f6e64696e672045524337323120636f6e74726163740a2020202061636365737328616c6c29206c6574206e616d653a20537472696e670a202020202f2f2f2053796d626f6c206f6620746865204e465420636f6c6c656374696f6e20646566696e656420696e2074686520636f72726573706f6e64696e672045524337323120636f6e74726163740a2020202061636365737328616c6c29206c65742073796d626f6c3a20537472696e670a202020202f2f2f20555249206f662074686520636f6e74726163742c20696620617661696c61626c6520617320612076617220696e2063617365207468652062726964676520656e61626c65732063726f73732d564d204d657461646174612073796e63696e6720696e20746865206675747572650a2020202061636365737328616c6c292076617220636f6e74726163745552493a20537472696e673f0a202020202f2f2f2052657461696e206120436f6c6c656374696f6e20746f207265666572656e6365207768656e207265736f6c76696e6720436f6c6c656374696f6e204d657461646174610a202020206163636573732873656c6629206c657420636f6c6c656374696f6e3a2040436f6c6c656374696f6e0a202020202f2f2f204d617070696e67206f6620746f6b656e205552497320696e6465786564206f6e207468656972204552433732312049442e205468697320776f756c64206e6f74206e6f726d616c6c792062652072657461696e65642077697468696e206120436164656e6365204e46540a202020202f2f2f20636f6e74726163742c206275742073696e6365204e4654206d65746164617461206d6179206265207570646174656420696e2045564d2c20697427732072657461696e6564206865726520736f207468617420746865206272696467652063616e207570646174650a202020202f2f2f20697420616761696e73742074686520736f757263652045524337323120636f6e7472616374207768696368206973207472656174656420617320746865204e4654277320736f75726365206f662074727574682e0a2020202061636365737328616c6c29206c657420746f6b656e555249733a207b55496e743235363a20537472696e677d0a0a202020202f2f2f20546865204e4654207265736f7572636520726570726573656e74696e672074686520627269646765642045524337323120746f6b656e0a202020202f2f2f0a2020202061636365737328616c6c29207265736f75726365204e4654203a2043726f7373564d4e46542e45564d4e4654207b0a20202020202020202f2f2f2054686520436164656e6365204944206f6620746865204e46540a202020202020202061636365737328616c6c29206c65742069643a2055496e7436340a20202020202020202f2f2f2054686520455243373231204944206f6620746865204e46540a202020202020202061636365737328616c6c29206c65742065766d49443a2055496e743235360a20202020202020202f2f2f204164646974696f6e616c206f6e636861696e206d657461646174610a202020202020202061636365737328616c6c29206c6574206d657461646174613a207b537472696e673a20416e795374727563747d0a0a2020202020202020696e6974280a20202020202020202020202065766d49443a2055496e743235362c0a2020202020202020202020206d657461646174613a207b537472696e673a20416e795374727563747d0a202020202020202029207b0a20202020202020202020202073656c662e6e616d65203d206e616d650a20202020202020202020202073656c662e73796d626f6c203d2073796d626f6c0a20202020202020202020202073656c662e6964203d2073656c662e757569640a20202020202020202020202073656c662e65766d4944203d2065766d49440a20202020202020202020202073656c662e6d65746164617461203d206d657461646174610a20202020202020207d0a0a20202020202020202f2f2f2052657475726e7320746865206d65746164617461207669657720747970657320737570706f727465642062792074686973204e46540a202020202020202061636365737328616c6c2920766965772066756e20676574566965777328293a205b547970655d207b0a20202020202020202020202072657475726e205b0a20202020202020202020202020202020547970653c43726f7373564d4e46542e45564d427269646765644d657461646174613e28292c0a20202020202020202020202020202020547970653c4d6574616461746156696577732e53657269616c3e28292c0a20202020202020202020202020202020547970653c4d6574616461746156696577732e4e4654436f6c6c656374696f6e446174613e28292c0a20202020202020202020202020202020547970653c4d6574616461746156696577732e4e4654436f6c6c656374696f6e446973706c61793e28290a2020202020202020202020205d0a20202020202020207d0a0a202020202020202061636365737328616c6c2920766965772066756e206765744e616d6528293a20537472696e67207b0a20202020202020202020202072657475726e20" + }, { + "type": "String", + "value": "2e6e616d650a20202020202020207d0a0a202020202020202061636365737328616c6c2920766965772066756e2067657453796d626f6c28293a20537472696e67207b0a20202020202020202020202072657475726e20" + }, { + "type": "String", + "value": "2e73796d626f6c0a20202020202020207d0a0a202020202020202061636365737328616c6c2920766965772066756e20746f6b656e55524928293a20537472696e67207b0a20202020202020202020202072657475726e20" + }, { + "type": "String", + "value": "2e746f6b656e5552495b73656c662e65766d49445d203f3f2022220a20202020202020207d0a0a20202020202020202f2f2f205265736f6c7665732061206d65746164617461207669657720666f722074686973204e46540a202020202020202061636365737328616c6c292066756e207265736f6c766556696577285f20766965773a2054797065293a20416e795374727563743f207b0a2020202020202020202020207377697463682076696577207b0a202020202020202020202020202020202f2f20576520646f6e2774206b6e6f772077686174206b696e64206f662066696c65207468652055524920726570726573656e747320284950465320762048545450292c20736f2077652063616e2774207265736f6c766520446973706c617920766965770a202020202020202020202020202020202f2f20776974682074686520555249206173207468756d626e61696c202d207765206d61792061206e6577207374616e64617264207669657720666f722045564d204e465473202d207468697320697320696e746572696d0a202020202020202020202020202020206361736520547970653c43726f7373564d4e46542e45564d427269646765644d657461646174613e28293a0a202020202020202020202020202020202020202072657475726e2043726f7373564d4e46542e45564d427269646765644d65746164617461280a2020202020202020202020202020202020202020202020206e616d653a2073656c662e6e616d652c0a20202020202020202020202020202020202020202020202073796d626f6c3a2073656c662e73796d626f6c2c0a2020202020202020202020202020202020202020202020207572693a2043726f7373564d4e46542e55524928626173655552493a206e696c2c2076616c75653a2073656c662e746f6b656e5552492829290a2020202020202020202020202020202020202020290a202020202020202020202020202020206361736520547970653c4d6574616461746156696577732e53657269616c3e28293a0a202020202020202020202020202020202020202072657475726e204d6574616461746156696577732e53657269616c280a20202020202020202020202020202020202020202020202073656c662e69640a2020202020202020202020202020202020202020290a202020202020202020202020202020206361736520547970653c4d6574616461746156696577732e4e4654436f6c6c656374696f6e446174613e28293a0a202020202020202020202020202020202020202072657475726e20" }, { "type": "String", "value": "2e7265736f6c7665436f6e747261637456696577280a2020202020202020202020202020202020202020202020207265736f75726365547970653a2073656c662e6765745479706528292c0a20202020202020202020202020202020202020202020202076696577547970653a20547970653c4d6574616461746156696577732e4e4654436f6c6c656374696f6e446174613e28290a2020202020202020202020202020202020202020290a202020202020202020202020202020206361736520547970653c4d6574616461746156696577732e4e4654436f6c6c656374696f6e446973706c61793e28293a0a202020202020202020202020202020202020202072657475726e20" @@ -25,7 +34,7 @@ "value": "2e67657445564d436f6e74726163744164647265737328290a20202020202020207d0a0a20202020202020202f2f2f2053696d696c617220746f204552433732312e746f6b656e555249206d6574686f642c2072657475726e732074686520555249206f6620746865204e465420776974682073656c662e65766d49442061742074696d65206f66206272696467696e670a202020202020202061636365737328616c6c2920766965772066756e20746f6b656e55524928293a20537472696e67207b0a20202020202020202020202072657475726e20" }, { "type": "String", - "value": "2e746f6b656e555249735b73656c662e65766d49445d203f3f2022220a20202020202020207d0a202020207d0a0a202020202f2f2f2054686973207265736f7572636520686f6c6473206173736f636961746564204e4654732c20616e642073657276657320717565726965732061626f75742073746f726564204e4654730a2020202061636365737328616c6c29207265736f7572636520436f6c6c656374696f6e3a204e6f6e46756e6769626c65546f6b656e2e436f6c6c656374696f6e2c2043726f7373564d4e46542e45564d4e4654436f6c6c656374696f6e207b0a20202020202020202f2f2f2064696374696f6e617279206f66204e465420636f6e666f726d696e6720746f6b656e7320696e6465786564206f6e2074686569722049440a202020202020202061636365737328636f6e74726163742920766172206f776e65644e4654733a20407b55496e7436343a20" + "value": "2e746f6b656e555249735b73656c662e65766d49445d203f3f2022220a20202020202020207d0a202020207d0a0a202020202f2f2f2054686973207265736f7572636520686f6c6473206173736f636961746564204e4654732c20616e642073657276657320717565726965732061626f75742073746f726564204e4654730a2020202061636365737328616c6c29207265736f7572636520436f6c6c656374696f6e203a2043726f7373564d4e46542e45564d4e4654436f6c6c656374696f6e207b0a20202020202020202f2f2f2064696374696f6e617279206f66204e465420636f6e666f726d696e6720746f6b656e7320696e6465786564206f6e2074686569722049440a202020202020202061636365737328636f6e74726163742920766172206f776e65644e4654733a20407b55496e7436343a20" }, { "type": "String", "value": "2e4e46547d0a20202020202020202f2f2f204d617070696e67206f662045564d2049447320746f20466c6f77204e4654204944730a202020202020202061636365737328636f6e747261637429206c65742065766d4944546f466c6f7749443a207b55496e743235363a2055496e7436347d0a0a202020202020202061636365737328616c6c29207661722073746f72616765506174683a2053746f72616765506174680a202020202020202061636365737328616c6c2920766172207075626c6963506174683a205075626c6963506174680a0a2020202020202020696e6974202829207b0a20202020202020202020202073656c662e6f776e65644e465473203c2d207b7d0a20202020202020202020202073656c662e65766d4944546f466c6f774944203d207b7d0a2020202020202020202020206c657420636f6c6c656374696f6e44617461203d20" @@ -34,13 +43,19 @@ "value": "2e7265736f6c7665436f6e747261637456696577280a20202020202020202020202020202020202020207265736f75726365547970653a20547970653c40" }, { "type": "String", - "value": "2e4e46543e28292c0a202020202020202020202020202020202020202076696577547970653a20547970653c4d6574616461746156696577732e4e4654436f6c6c656374696f6e446174613e28290a202020202020202020202020202020202920617321204d6574616461746156696577732e4e4654436f6c6c656374696f6e446174613f0a202020202020202020202020202020203f3f2070616e69632822436f756c64206e6f74207265736f6c76652074686520636f6c6c656374696f6e2064617461207669657720666f7220746865204e465420636f6c6c656374696f6e22290a20202020202020202020202073656c662e73746f7261676550617468203d20636f6c6c656374696f6e446174612e73746f72616765506174680a20202020202020202020202073656c662e7075626c696350617468203d20636f6c6c656374696f6e446174612e7075626c6963506174680a20202020202020207d0a0a20202020202020202f2f2f2052657475726e732061206c697374206f66204e46542074797065732074686174207468697320726563656976657220616363657074730a202020202020202061636365737328616c6c2920766965772066756e20676574537570706f727465644e4654547970657328293a207b547970653a20426f6f6c7d207b0a20202020202020202020202072657475726e207b20547970653c40" + "value": "2e4e46543e28292c0a202020202020202020202020202020202020202076696577547970653a20547970653c4d6574616461746156696577732e4e4654436f6c6c656374696f6e446174613e28290a202020202020202020202020202020202920617321204d6574616461746156696577732e4e4654436f6c6c656374696f6e446174613f0a202020202020202020202020202020203f3f2070616e69632822436f756c64206e6f74207265736f6c76652074686520636f6c6c656374696f6e2064617461207669657720666f7220746865204e465420636f6c6c656374696f6e22290a20202020202020202020202073656c662e73746f7261676550617468203d20636f6c6c656374696f6e446174612e73746f72616765506174680a20202020202020202020202073656c662e7075626c696350617468203d20636f6c6c656374696f6e446174612e7075626c6963506174680a20202020202020207d0a0a202020202020202061636365737328616c6c2920766965772066756e206765744e616d6528293a20537472696e67207b0a20202020202020202020202072657475726e20" + }, { + "type": "String", + "value": "2e6e616d650a20202020202020207d0a0a202020202020202061636365737328616c6c2920766965772066756e2067657453796d626f6c28293a20537472696e67207b0a20202020202020202020202072657475726e20" + }, { + "type": "String", + "value": "2e73796d626f6c0a20202020202020207d0a0a20202020202020202f2f2f2052657475726e732061206c697374206f66204e46542074797065732074686174207468697320726563656976657220616363657074730a202020202020202061636365737328616c6c2920766965772066756e20676574537570706f727465644e4654547970657328293a207b547970653a20426f6f6c7d207b0a20202020202020202020202072657475726e207b20547970653c40" }, { "type": "String", "value": "2e4e46543e28293a2074727565207d0a20202020202020207d0a0a20202020202020202f2f2f2052657475726e732077686574686572206f72206e6f742074686520676976656e20747970652069732061636365707465642062792074686520636f6c6c656374696f6e0a20202020202020202f2f2f204120636f6c6c656374696f6e20746861742063616e2061636365707420616e7920747970652073686f756c64206a7573742072657475726e20747275652062792064656661756c740a202020202020202061636365737328616c6c2920766965772066756e206973537570706f727465644e46545479706528747970653a2054797065293a20426f6f6c207b0a202020202020202020202072657475726e2074797065203d3d20547970653c40" }, { "type": "String", - "value": "2e4e46543e28290a20202020202020207d0a0a20202020202020202f2f2f2052656d6f76657320616e204e46542066726f6d2074686520636f6c6c656374696f6e20616e64206d6f76657320697420746f207468652063616c6c65720a2020202020202020616363657373284e6f6e46756e6769626c65546f6b656e2e5769746864726177207c204e6f6e46756e6769626c65546f6b656e2e4f776e6572292066756e20776974686472617728776974686472617749443a2055496e743634293a20407b4e6f6e46756e6769626c65546f6b656e2e4e46547d207b0a2020202020202020202020206c657420746f6b656e203c2d2073656c662e6f776e65644e4654732e72656d6f7665286b65793a2077697468647261774944290a202020202020202020202020202020203f3f2070616e69632822436f756c64206e6f7420776974686472617720616e204e46542077697468207468652070726f76696465642049442066726f6d2074686520636f6c6c656374696f6e22290a0a20202020202020202020202072657475726e203c2d746f6b656e0a20202020202020207d0a0a20202020202020202f2f2f2057697468647261777320616e204e46542066726f6d2074686520636f6c6c656374696f6e206279206974732045564d2049440a2020202020202020616363657373284e6f6e46756e6769626c65546f6b656e2e5769746864726177207c204e6f6e46756e6769626c65546f6b656e2e4f776e6572292066756e207769746864726177427945564d4944285f2069643a2055496e743634293a20407b4e6f6e46756e6769626c65546f6b656e2e4e46547d207b0a2020202020202020202020206c657420746f6b656e203c2d2073656c662e6f776e65644e4654732e72656d6f7665286b65793a206964290a202020202020202020202020202020203f3f2070616e69632822436f756c64206e6f7420776974686472617720616e204e46542077697468207468652070726f76696465642049442066726f6d2074686520636f6c6c656374696f6e22290a0a20202020202020202020202072657475726e203c2d746f6b656e0a20202020202020207d0a0a20202020202020202f2f2f205474616b65732061204e465420616e64206164647320697420746f2074686520636f6c6c656374696f6e732064696374696f6e61727920616e6420616464732074686520494420746f207468652065766d4944546f466c6f774944206d617070696e670a202020202020202061636365737328616c6c292066756e206465706f73697428746f6b656e3a20407b4e6f6e46756e6769626c65546f6b656e2e4e46547d29207b0a2020202020202020202020206c657420746f6b656e203c2d20746f6b656e206173212040" + "value": "2e4e46543e28290a20202020202020207d0a0a20202020202020202f2f2f2052656d6f76657320616e204e46542066726f6d2074686520636f6c6c656374696f6e20616e64206d6f76657320697420746f207468652063616c6c65720a2020202020202020616363657373284e6f6e46756e6769626c65546f6b656e2e5769746864726177207c204e6f6e46756e6769626c65546f6b656e2e4f776e6572292066756e20776974686472617728776974686472617749443a2055496e743634293a20407b4e6f6e46756e6769626c65546f6b656e2e4e46547d207b0a2020202020202020202020206c657420746f6b656e203c2d2073656c662e6f776e65644e4654732e72656d6f7665286b65793a2077697468647261774944290a202020202020202020202020202020203f3f2070616e69632822436f756c64206e6f7420776974686472617720616e204e46542077697468207468652070726f76696465642049442066726f6d2074686520636f6c6c656374696f6e22290a0a20202020202020202020202072657475726e203c2d746f6b656e0a20202020202020207d0a0a20202020202020202f2f2f2057697468647261777320616e204e46542066726f6d2074686520636f6c6c656374696f6e206279206974732045564d2049440a2020202020202020616363657373284e6f6e46756e6769626c65546f6b656e2e5769746864726177207c204e6f6e46756e6769626c65546f6b656e2e4f776e6572292066756e207769746864726177427945564d4944285f2069643a2055496e74323536293a20407b4e6f6e46756e6769626c65546f6b656e2e4e46547d207b0a20202020202020202020202072657475726e203c2d2073656c662e776974686472617728776974686472617749443a200a2020202020202020202020202020202073656c662e676574436164656e636549442866726f6d3a20696429203f3f2070616e69632822436f756c64206e6f7420776974686472617720616e204e46542077697468207468652070726f76696465642045564d2049442066726f6d2074686520636f6c6c656374696f6e22290a202020202020202020202020290a20202020202020207d0a0a20202020202020202f2f2f205474616b65732061204e465420616e64206164647320697420746f2074686520636f6c6c656374696f6e732064696374696f6e61727920616e6420616464732074686520494420746f207468652065766d4944546f466c6f774944206d617070696e670a202020202020202061636365737328616c6c292066756e206465706f73697428746f6b656e3a20407b4e6f6e46756e6769626c65546f6b656e2e4e46547d29207b0a2020202020202020202020206c657420746f6b656e203c2d20746f6b656e206173212040" }, { "type": "String", "value": "2e4e46540a0a2020202020202020202020202f2f2061646420746865206e657720746f6b656e20746f207468652064696374696f6e6172792077686963682072656d6f76657320746865206f6c64206f6e650a20202020202020202020202073656c662e65766d4944546f466c6f7749445b746f6b656e2e65766d49445d203d20746f6b656e2e69640a2020202020202020202020206c6574206f6c64546f6b656e203c2d2073656c662e6f776e65644e4654735b746f6b656e2e69645d203c2d20746f6b656e0a0a20202020202020202020202064657374726f79206f6c64546f6b656e0a20202020202020207d0a0a20202020202020202f2f2f2052657475726e7320616e206172726179206f66207468652049447320746861742061726520696e2074686520636f6c6c656374696f6e0a202020202020202061636365737328616c6c2920766965772066756e2067657449447328293a205b55496e7436345d207b0a20202020202020202020202072657475726e2073656c662e6f776e65644e4654732e6b6579730a20202020202020207d0a0a20202020202020202f2f2f2052657475726e7320616e206172726179206f66207468652045564d2049447320746861742061726520696e2074686520636f6c6c656374696f6e0a202020202020202061636365737328616c6c2920766965772066756e2067657445564d49447328293a205b55496e743235365d207b0a20202020202020202020202072657475726e2073656c662e65766d4944546f466c6f7749442e6b6579730a20202020202020207d0a0a20202020202020202f2f2f2052657475726e732074686520436164656e6365204e46542e696420666f722074686520676976656e2045564d204e46542049442069660a202020202020202061636365737328616c6c2920766965772066756e20676574436164656e636549442866726f6d2065766d49443a2055496e74323536293a2055496e7436343f207b0a20202020202020202020202072657475726e2073656c662e65766d4944546f466c6f7749445b65766d49445d203f3f2055496e7436342865766d4944290a20202020202020207d0a0a20202020202020202f2f2f2052657475726e73207468652045564d204e4654204944206173736f63696174656420776974682074686520436164656e6365204e46542049442e2054686520676f616c20697320746f20726574726965766520746865204552433732312049442076616c75652e0a20202020202020202f2f2f20417320666172206173207468652062726964676520697320636f6e6365726e65642c20616e2045524337323120646566696e6564206279207468652062726964676520697320746865204e46542773204944206174207468652074696d65206f66206272696467696e670a20202020202020202f2f2f206f72207468652076616c7565206f6620746865204e46542e65766d494420696620697420696d706c656d656e7473207468652043726f7373564d4e46542e45564d4e465420696e74657266616365207768656e20627269646765642e0a20202020202020202f2f2f20466f6c6c6f77696e672074686973207061747465726e2c206966206c6f636b65642c20746865204e465420697320636865636b656420666f722045564d4e465420636f6e666f726d616e63652072657475726e696e67202e65766d494420696620736f2c0a20202020202020202f2f2f206f746865727769736520746865204e465427732049442069732072657475726e656420617320612055496e743235362073696e63652074686174277320686f77207468652062726964676520776f756c642068616e646c65206d696e74696e6720696e207468650a20202020202020202f2f2f20636f72726573706f6e64696e672045524337323120636f6e74726163742e0a20202020202020202f2f2f0a202020202020202061636365737328616c6c2920766965772066756e2067657445564d49442866726f6d20636164656e636549443a2055496e743634293a2055496e743235363f207b0a2020202020202020202020206966206c6574206e6674203d2073656c662e626f72726f774e465428636164656e6365494429207b0a202020202020202020202020202020206966206c65742065766d4e4654203d2043726f7373564d4e46542e67657445564d49442866726f6d3a206e667429207b0a202020202020202020202020202020202020202072657475726e2065766d4e46540a202020202020202020202020202020207d0a2020202020202020202020202020202072657475726e2055496e74323536286e66742e6964290a2020202020202020202020207d0a20202020202020202020202072657475726e206e696c0a20202020202020207d0a0a20202020202020202f2f2f2052657475726e732074686520636f6e747261637455524920666f7220746865204e465420636f6c6c656374696f6e20617320646566696e656420696e2074686520736f757263652045524337323120636f6e74726163742e204966206e6f6e65207761730a20202020202020202f2f2f20646566696e6564206174207468652074696d65206f66206272696467696e672c20616e20656d70747920737472696e672069732072657475726e65642e0a202020202020202061636365737328616c6c2920766965772066756e20636f6e747261637455524928293a20537472696e673f207b0a20202020202020202020202072657475726e20" @@ -76,7 +91,7 @@ "value": "2e4e46543e28292c20776974683a2073656c662e65766d4e4654436f6e747261637441646472657373290a2020202020202020466c6f7745564d4272696467654e4654457363726f772e696e697469616c697a65457363726f77280a202020202020202020202020666f72547970653a20547970653c40" }, { "type": "String", - "value": "2e4e46543e28292c0a202020202020202020202020657263373231416464726573733a2073656c662e65766d4e4654436f6e7472616374416464726573730a2020202020202020290a202020207d0a7d0a" + "value": "2e4e46543e28292c0a2020202020202020202020206e616d653a206e616d652c0a20202020202020202020202073796d626f6c3a2073796d626f6c2c0a202020202020202020202020657263373231416464726573733a2073656c662e65766d4e4654436f6e7472616374416464726573730a2020202020202020290a202020207d0a7d0a" } ] } diff --git a/cadence/args/bridged-token-code-chunks-args.json b/cadence/args/bridged-token-code-chunks-args.json new file mode 100644 index 00000000..1e740ed7 --- /dev/null +++ b/cadence/args/bridged-token-code-chunks-args.json @@ -0,0 +1,65 @@ +[ + { + "type": "String", + "value": "bridgedToken" + }, { + "type": "Array", + "value": [ + { + "type": "String", + "value": "696d706f7274204e6f6e46756e6769626c65546f6b656e2066726f6d203078663864366530353836623061323063370a696d706f7274204d6574616461746156696577732066726f6d203078663864366530353836623061323063370a696d706f72742046756e6769626c65546f6b656e4d6574616461746156696577732066726f6d203078663864366530353836623061323063370a696d706f727420566965775265736f6c7665722066726f6d203078663864366530353836623061323063370a696d706f72742046756e6769626c65546f6b656e2066726f6d203078656538323835366266323065326161360a696d706f727420466c6f77546f6b656e2066726f6d203078306165353363623665336634326137390a0a696d706f72742045564d2066726f6d203078663864366530353836623061323063370a0a696d706f7274204943726f7373564d2066726f6d203078663864366530353836623061323063370a696d706f7274204945564d427269646765546f6b656e4d696e7465722066726f6d203078663864366530353836623061323063370a696d706f727420466c6f7745564d427269646765546f6b656e457363726f772066726f6d203078663864366530353836623061323063370a696d706f727420466c6f7745564d427269646765436f6e6669672066726f6d203078663864366530353836623061323063370a696d706f727420466c6f7745564d4272696467655574696c732066726f6d203078663864366530353836623061323063370a696d706f727420466c6f7745564d4272696467652066726f6d203078663864366530353836623061323063370a696d706f72742043726f7373564d4e46542066726f6d203078663864366530353836623061323063370a696d706f72742043726f7373564d546f6b656e2066726f6d203078663864366530353836623061323063370a0a2f2f2f205468697320636f6e747261637420697320612074656d706c617465207573656420627920466c6f7745564d42726964676520746f20646566696e652045564d2d6e61746976652066756e6769626c6520746f6b656e7320627269646765642066726f6d20466c6f772045564d20746f200a2f2f2f20436164656e63652e2055706f6e206465706c6f796d656e74206f66207468697320636f6e74726163742c2074686520636f6e7472616374206e616d65206973206465726976656420617320612066756e6374696f6e206f6620746865206173736574207479706520286865726520616e200a2f2f2f2045524332302920616e642074686520636f6e747261637427732045564d20616464726573732e20546865206465726976656420636f6e7472616374206e616d65206973207468656e206a6f696e65642077697468207468697320636f6e7472616374277320636f64652c0a2f2f2f207072657061726564206173206368756e6b7320696e20466c6f7745564d42726964676554656d706c61746573206265666f7265206265696e67206465706c6f79656420746f2074686520466c6f772045564d20427269646765206163636f756e742e0a2f2f2f0a2f2f2f204f6e206272696467696e672c20746865204552433230206973207472616e7366657272656420746f2074686520627269646765277320436164656e63654f776e65644163636f756e742045564d206164647265737320616e6420746f6b656e7320617265206d696e7465642066726f6d0a2f2f2f207468697320636f6e747261637420746f20746865206272696467696e672063616c6c65722e204f6e2072657475726e20746f20466c6f772045564d2c2074686520726576657273652070726f6365737320697320666f6c6c6f776564202d2074686520746f6b656e206973206275726e65640a2f2f2f20696e207468697320636f6e747261637420616e6420746865204552433230206973207472616e7366657272656420746f2074686520646566696e656420726563697069656e742e20496e2074686973207761792c2074686520436164656e6365205661756c74206163747320617320610a2f2f2f20726570726573656e746174696f6e206f6620626f7468207468652045564d20746f6b656e7320616e642074687573206f776e6572736869702072696768747320746f2069742075706f6e206272696467696e67206261636b20746f20466c6f772045564d2e0a2f2f2f0a2f2f2f20546f20627269646765206265747765656e20564d732c20612063616c6c65722063616e20656974686572207573652074686520696e74657266616365206578706f736564206f6e20436164656e63654f776e65644163636f756e74206f722075736520466c6f7745564d4272696467650a2f2f2f207075626c696320636f6e7472616374206d6574686f64732e0a2f2f2f0a61636365737328616c6c2920636f6e747261637420" + }, { + "type": "String", + "value": "203a204943726f7373564d2c204945564d427269646765546f6b656e4d696e7465722c2046756e6769626c65546f6b656e207b0a0a202020202f2f2f20506f696e74657220746f2074686520466163746f7279206465706c6f79656420536f6c696469747920636f6e7472616374206164647265737320646566696e696e672074686520627269646765642061737365740a2020202061636365737328616c6c29206c65742065766d546f6b656e436f6e7472616374416464726573733a2045564d2e45564d416464726573730a202020202f2f2f204e616d65206f66207468652066756e6769626c6520746f6b656e20646566696e656420696e2074686520636f72726573706f6e64696e6720455243323020636f6e74726163740a2020202061636365737328616c6c29206c6574206e616d653a20537472696e670a202020202f2f2f2053796d626f6c206f66207468652066756e6769626c6520746f6b656e20646566696e656420696e2074686520636f72726573706f6e64696e6720455243323020636f6e74726163740a2020202061636365737328616c6c29206c65742073796d626f6c3a20537472696e670a202020202f2f2f20446563696d616c20706c6163652076616c756520646566696e656420696e2074686520736f7572636520455243323020636f6e74726163740a2020202061636365737328616c6c29206c657420646563696d616c733a2055496e74380a202020202f2f2f20555249206f662074686520636f6e74726163742c20696620617661696c61626c6520617320612076617220696e2063617365207468652062726964676520656e61626c65732063726f73732d564d204d657461646174612073796e63696e6720696e20746865206675747572650a2020202061636365737328616c6c292076617220636f6e74726163745552493a20537472696e673f0a202020202f2f2f20546f74616c20737570706c79206f66207468697320436164656e636520746f6b656e20696e2063697263756c6174696f6e0a202020202f2f2f204e4f54453a205468697320646f6573206e6f74207265666c6563742074686520746f74616c20737570706c79206f662074686520736f7572636520455243323020696e2063697263756c6174696f6e2077697468696e2045564d0a2020202061636365737328616c6c292076617220746f74616c537570706c793a205546697836340a202020202f2f2f2052657461696e2061205661756c7420746f207265666572656e6365207768656e207265736f6c76696e67205661756c74204d657461646174610a202020206163636573732873656c6629206c6574207661756c743a20405661756c740a0a202020202f2f2f20546865205661756c74207265736f7572636520726570726573656e74696e6720746865206272696467656420455243323020746f6b656e0a202020202f2f2f0a2020202061636365737328616c6c29207265736f75726365205661756c74203a2043726f7373564d546f6b656e2e45564d546f6b656e496e666f2c2046756e6769626c65546f6b656e2e5661756c74207b0a20202020202020202f2f2f2042616c616e6365206f662074686520746f6b656e7320696e206120676976656e205661756c740a202020202020202061636365737328616c6c29207661722062616c616e63653a205546697836340a0a2020202020202020696e69742862616c616e63653a2055466978363429207b0a20202020202020202020202073656c662e62616c616e6365203d2062616c616e63650a20202020202020207d0a0a20202020202020202f2a202d2d2d2043726f7373564d546f6b656e2e45564d46545661756c7420636f6e666f726d616e6365202d2d2d202a2f0a20202020202020202f2f0a20202020202020202f2f2f204765747320746865204552433230206e616d652076616c75650a202020202020202061636365737328616c6c2920766965772066756e206765744e616d6528293a20537472696e67207b0a20202020202020202020202072657475726e20" + }, { + "type": "String", + "value": "2e6e616d650a20202020202020207d0a20202020202020202f2f2f2047657473207468652045524332302073796d626f6c2076616c75650a202020202020202061636365737328616c6c2920766965772066756e2067657453796d626f6c28293a20537472696e67207b0a20202020202020202020202072657475726e20" + }, { + "type": "String", + "value": "2e73796d626f6c0a20202020202020207d0a20202020202020202f2f2f20476574732074686520455243323020646563696d616c732076616c75650a202020202020202061636365737328616c6c2920766965772066756e20676574446563696d616c7328293a2055496e7438207b0a20202020202020202020202072657475726e20" + }, { + "type": "String", + "value": "2e646563696d616c730a20202020202020207d0a20202020202020202f2f2f2052657475726e73207468652045564d20636f6e74726163742061646472657373206f66207468652066756e6769626c6520746f6b656e0a202020202020202061636365737328616c6c2920766965772066756e2067657445564d436f6e74726163744164647265737328293a2045564d2e45564d41646472657373207b0a20202020202020202020202072657475726e20" + }, { + "type": "String", + "value": "2e67657445564d436f6e74726163744164647265737328290a20202020202020207d0a0a202020202020202061636365737328616c6c2920766965772066756e20676574566965777328293a205b547970655d207b0a20202020202020202020202072657475726e20" + }, { + "type": "String", + "value": "2e676574436f6e74726163745669657773287265736f75726365547970653a206e696c290a20202020202020207d0a0a202020202020202061636365737328616c6c292066756e207265736f6c766556696577285f20766965773a2054797065293a20416e795374727563743f207b0a20202020202020202020202072657475726e20" + }, { + "type": "String", + "value": "2e7265736f6c7665436f6e747261637456696577287265736f75726365547970653a206e696c2c2076696577547970653a2076696577290a20202020202020207d0a0a20202020202020202f2f2f20676574537570706f727465645661756c745479706573206f7074696f6e616c6c792072657475726e732061206c697374206f66207661756c742074797065732074686174207468697320726563656976657220616363657074730a202020202020202061636365737328616c6c2920766965772066756e20676574537570706f727465645661756c74547970657328293a207b547970653a20426f6f6c7d207b0a20202020202020202020202072657475726e207b2073656c662e6765745479706528293a2074727565207d0a20202020202020207d0a0a202020202020202061636365737328616c6c2920766965772066756e206973537570706f727465645661756c745479706528747970653a2054797065293a20426f6f6c207b0a20202020202020202020202072657475726e2073656c662e676574537570706f727465645661756c74547970657328295b747970655d203f3f2066616c73650a20202020202020207d0a0a20202020202020202f2f2f2041736b732069662074686520616d6f756e742063616e2062652077697468647261776e2066726f6d2074686973207661756c740a202020202020202061636365737328616c6c2920766965772066756e206973417661696c61626c65546f576974686472617728616d6f756e743a20554669783634293a20426f6f6c207b0a20202020202020202020202072657475726e20616d6f756e74203c3d2073656c662e62616c616e63650a20202020202020207d0a0a20202020202020202f2f2f206465706f7369740a20202020202020202f2f2f0a20202020202020202f2f2f2046756e6374696f6e20746861742074616b65732061205661756c74206f626a65637420617320616e20617267756d656e7420616e6420616464730a20202020202020202f2f2f206974732062616c616e636520746f207468652062616c616e6365206f6620746865206f776e657273205661756c742e0a20202020202020202f2f2f0a20202020202020202f2f2f20497420697320616c6c6f77656420746f2064657374726f79207468652073656e74205661756c74206265636175736520746865205661756c740a20202020202020202f2f2f2077617320612074656d706f7261727920686f6c646572206f662074686520746f6b656e732e20546865205661756c7427732062616c616e6365206861730a20202020202020202f2f2f206265656e20636f6e73756d656420616e64207468657265666f72652063616e2062652064657374726f7965642e0a20202020202020202f2f2f0a202020202020202061636365737328616c6c292066756e206465706f7369742866726f6d3a20407b46756e6769626c65546f6b656e2e5661756c747d29207b0a2020202020202020202020206c6574207661756c74203c2d2066726f6d2061732120405661756c740a20202020202020202020202073656c662e62616c616e6365203d2073656c662e62616c616e6365202b207661756c742e62616c616e63650a2020202020202020202020207661756c742e62616c616e6365203d20302e300a20202020202020202020202064657374726f79207661756c740a20202020202020207d0a0a20202020202020202f2f2f20637265617465456d7074795661756c740a20202020202020202f2f2f0a20202020202020202f2f2f2046756e6374696f6e207468617420637265617465732061206e6577205661756c74207769746820612062616c616e6365206f66207a65726f0a20202020202020202f2f2f20616e642072657475726e7320697420746f207468652063616c6c696e6720636f6e746578742e20412075736572206d7573742063616c6c20746869732066756e6374696f6e0a20202020202020202f2f2f20616e642073746f7265207468652072657475726e6564205661756c7420696e2074686569722073746f7261676520696e206f7264657220746f20616c6c6f772074686569720a20202020202020202f2f2f206163636f756e7420746f2062652061626c6520746f2072656365697665206465706f73697473206f66207468697320746f6b656e20747970652e0a20202020202020202f2f2f0a202020202020202061636365737328616c6c292066756e20637265617465456d7074795661756c7428293a20405661756c74207b0a20202020202020202020202072657475726e203c2d637265617465205661756c742862616c616e63653a20302e30290a20202020202020207d0a0a20202020202020202f2f2f2077697468647261770a20202020202020202f2f2f0a20202020202020202f2f2f2046756e6374696f6e20746861742074616b657320616e20616d6f756e7420617320616e20617267756d656e740a20202020202020202f2f2f20616e6420776974686472617773207468617420616d6f756e742066726f6d20746865205661756c742e0a20202020202020202f2f2f0a20202020202020202f2f2f20497420637265617465732061206e65772074656d706f72617279205661756c742074686174206973207573656420746f20686f6c640a20202020202020202f2f2f2074686520746f6b656e73207468617420617265206265696e67207472616e736665727265642e2049742072657475726e7320746865206e65776c790a20202020202020202f2f2f2063726561746564205661756c7420746f2074686520636f6e7465787420746861742063616c6c656420736f2069742063616e206265206465706f73697465640a20202020202020202f2f2f20656c736577686572652e0a20202020202020202f2f2f0a20202020202020206163636573732846756e6769626c65546f6b656e2e5769746864726177292066756e20776974686472617728616d6f756e743a20554669783634293a20405661756c74207b0a20202020202020202020202073656c662e62616c616e6365203d2073656c662e62616c616e6365202d20616d6f756e740a20202020202020202020202072657475726e203c2d637265617465205661756c742862616c616e63653a20616d6f756e74290a20202020202020207d0a0a20202020202020202f2f2f2043616c6c6564207768656e20612066756e6769626c6520746f6b656e206973206275726e6564207669612074686520604275726e65722e6275726e282960206d6574686f640a202020202020202061636365737328636f6e7472616374292066756e206275726e43616c6c6261636b2829207b0a20202020202020202020202069662073656c662e62616c616e6365203e20302e30207b0a20202020202020202020202020202020" + }, { + "type": "String", + "value": "2e746f74616c537570706c79203d20" + }, { + "type": "String", + "value": "2e746f74616c537570706c79202d2073656c662e62616c616e63650a2020202020202020202020207d0a20202020202020202020202073656c662e62616c616e6365203d20302e300a20202020202020207d0a202020207d0a0a202020202f2f2f20637265617465456d7074795661756c740a202020202f2f2f0a202020202f2f2f2046756e6374696f6e207468617420637265617465732061206e6577205661756c74207769746820612062616c616e6365206f66207a65726f20616e642072657475726e7320697420746f207468652063616c6c696e6720636f6e746578742e20412075736572206d7573742063616c6c0a202020202f2f2f20746869732066756e6374696f6e20616e642073746f7265207468652072657475726e6564205661756c7420696e2074686569722073746f7261676520696e206f7264657220746f20616c6c6f77207468656972206163636f756e7420746f2062652061626c6520746f0a202020202f2f2f2072656365697665206465706f73697473206f66207468697320746f6b656e20747970652e0a202020202f2f2f0a2020202061636365737328616c6c292066756e20637265617465456d7074795661756c74287661756c74547970653a2054797065293a2040" + }, { + "type": "String", + "value": "2e5661756c74207b0a202020202020202072657475726e203c2d20637265617465205661756c742862616c616e63653a20302e30290a202020207d0a0a202020202f2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a0a202020202020202020202020476574746572730a202020202a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2f0a0a202020202f2f2f2052657475726e73207468652045564d20636f6e74726163742061646472657373206f66207468652066756e6769626c6520746f6b656e207468697320636f6e747261637420726570726573656e74730a202020202f2f2f0a2020202061636365737328616c6c2920766965772066756e2067657445564d436f6e74726163744164647265737328293a2045564d2e45564d41646472657373207b0a202020202020202072657475726e2073656c662e65766d546f6b656e436f6e7472616374416464726573730a202020207d0a0a202020202f2f2f2046756e6374696f6e20746861742072657475726e7320616c6c20746865204d6574616461746120566965777320696d706c656d656e74656420627920746869732066756e6769626c6520746f6b656e20636f6e74726163742e0a202020202f2f2f0a202020202f2f2f204072657475726e20416e206172726179206f6620547970657320646566696e696e672074686520696d706c656d656e7465642076696577732e20546869732076616c75652077696c6c20626520757365642062790a202020202f2f2f202020202020202020646576656c6f7065727320746f206b6e6f7720776869636820706172616d6574657220746f207061737320746f20746865207265736f6c7665566965772829206d6574686f642e0a202020202f2f2f0a2020202061636365737328616c6c2920766965772066756e20676574436f6e74726163745669657773287265736f75726365547970653a20547970653f293a205b547970655d207b0a202020202020202072657475726e205b0a202020202020202020202020547970653c46756e6769626c65546f6b656e4d6574616461746156696577732e4654566965773e28292c0a202020202020202020202020547970653c46756e6769626c65546f6b656e4d6574616461746156696577732e4654446973706c61793e28292c0a202020202020202020202020547970653c46756e6769626c65546f6b656e4d6574616461746156696577732e46545661756c74446174613e28292c0a202020202020202020202020547970653c46756e6769626c65546f6b656e4d6574616461746156696577732e546f74616c537570706c793e28292c0a202020202020202020202020547970653c43726f7373564d4e46542e45564d427269646765644d657461646174613e28290a20202020202020205d0a202020207d0a0a202020202f2f2f2046756e6374696f6e2074686174207265736f6c7665732061206d65746164617461207669657720666f72207468697320636f6e74726163742e0a202020202f2f2f0a202020202f2f2f2040706172616d20766965773a205468652054797065206f6620746865206465736972656420766965772e0a202020202f2f2f0a202020202f2f2f204072657475726e20412073747275637475726520726570726573656e74696e67207468652072657175657374656420766965772e0a202020202f2f2f0a2020202061636365737328616c6c292066756e207265736f6c7665436f6e747261637456696577287265736f75726365547970653a20547970653f2c2076696577547970653a2054797065293a20416e795374727563743f207b0a2020202020202020737769746368207669657754797065207b0a2020202020202020202020206361736520547970653c46756e6769626c65546f6b656e4d6574616461746156696577732e4654566965773e28293a0a2020202020202020202020202020202072657475726e2046756e6769626c65546f6b656e4d6574616461746156696577732e465456696577280a20202020202020202020202020202020202020206674446973706c61793a2073656c662e7265736f6c7665436f6e747261637456696577287265736f75726365547970653a206e696c2c2076696577547970653a20547970653c46756e6769626c65546f6b656e4d6574616461746156696577732e4654446973706c61793e282929206173212046756e6769626c65546f6b656e4d6574616461746156696577732e4654446973706c61793f2c0a202020202020202020202020202020202020202066745661756c74446174613a2073656c662e7265736f6c7665436f6e747261637456696577287265736f75726365547970653a206e696c2c2076696577547970653a20547970653c46756e6769626c65546f6b656e4d6574616461746156696577732e46545661756c74446174613e282929206173212046756e6769626c65546f6b656e4d6574616461746156696577732e46545661756c74446174613f0a20202020202020202020202020202020290a2020202020202020202020206361736520547970653c46756e6769626c65546f6b656e4d6574616461746156696577732e4654446973706c61793e28293a0a202020202020202020202020202020206c6574206d65646961203d204d6574616461746156696577732e4d65646961280a20202020202020202020202020202020202020202020202066696c653a204d6574616461746156696577732e4854545046696c65280a20202020202020202020202020202020202020202020202075726c3a202268747470733a2f2f6173736574732e776562736974652d66696c65732e636f6d2f3566363239346330633761386364643634336231633832302f3566363239346330633761386364613535636231633933365f466c6f775f576f72646d61726b2e737667220a2020202020202020202020202020202020202020292c0a20202020202020202020202020202020202020206d65646961547970653a2022696d6167652f7376672b786d6c220a20202020202020202020202020202020290a202020202020202020202020202020206c6574206d6564696173203d204d6574616461746156696577732e4d6564696173285b6d656469615d290a2020202020202020202020202020202072657475726e2046756e6769626c65546f6b656e4d6574616461746156696577732e4654446973706c6179280a20202020202020202020202020202020202020202f2f20544f444f3a20446563696465206f6e20686f772077652077616e7420746f20726570726573656e74206272696467656420746f6b656e206d656469610a20202020202020202020202020202020202020206e616d653a2073656c662e6e616d652c0a202020202020202020202020202020202020202073796d626f6c3a2073656c662e73796d626f6c2c0a20202020202020202020202020202020202020206465736372697074696f6e3a2022546869732066756e6769626c6520746f6b656e2077617320627269646765642066726f6d20466c6f772045564d2e222c0a202020202020202020202020202020202020202065787465726e616c55524c3a204d6574616461746156696577732e45787465726e616c55524c282268747470733a2f2f6272696467652e666c6f772e636f6d2f66756e6769626c652d746f6b656e22292c0a20202020202020202020202020202020202020206c6f676f733a206d65646961732c0a2020202020202020202020202020202020202020736f6369616c733a207b7d0a20202020202020202020202020202020290a2020202020202020202020206361736520547970653c46756e6769626c65546f6b656e4d6574616461746156696577732e46545661756c74446174613e28293a0a2020202020202020202020202020202072657475726e2046756e6769626c65546f6b656e4d6574616461746156696577732e46545661756c7444617461280a202020202020202020202020202020202020202073746f72616765506174683a202f73746f726167652f" + }, { + "type": "String", + "value": "5661756c742c0a20202020202020202020202020202020202020207265636569766572506174683a202f7075626c69632f" + }, { + "type": "String", + "value": "52656365697665722c0a20202020202020202020202020202020202020206d65746164617461506174683a202f7075626c69632f" + }, { + "type": "String", + "value": "5661756c742c0a202020202020202020202020202020202020202072656365697665724c696e6b6564547970653a20547970653c26" + }, { + "type": "String", + "value": "2e5661756c743e28292c0a20202020202020202020202020202020202020206d657461646174614c696e6b6564547970653a20547970653c26" + }, { + "type": "String", + "value": "2e5661756c743e28292c0a2020202020202020202020202020202020202020637265617465456d7074795661756c7446756e6374696f6e3a202866756e28293a20407b46756e6769626c65546f6b656e2e5661756c747d207b0a20202020202020202020202020202020202020202020202072657475726e203c2d73656c662e637265617465456d7074795661756c74287661756c74547970653a20547970653c40" + }, { + "type": "String", + "value": "2e5661756c743e2829290a20202020202020202020202020202020202020207d290a20202020202020202020202020202020290a2020202020202020202020206361736520547970653c46756e6769626c65546f6b656e4d6574616461746156696577732e546f74616c537570706c793e28293a0a2020202020202020202020202020202072657475726e2046756e6769626c65546f6b656e4d6574616461746156696577732e546f74616c537570706c79280a2020202020202020202020202020202020202020746f74616c537570706c793a2073656c662e746f74616c537570706c790a20202020202020202020202020202020290a2020202020202020202020206361736520547970653c43726f7373564d4e46542e45564d427269646765644d657461646174613e28293a0a2020202020202020202020202020202072657475726e2043726f7373564d4e46542e45564d427269646765644d65746164617461280a20202020202020202020202020202020202020206e616d653a2073656c662e6e616d652c0a202020202020202020202020202020202020202073796d626f6c3a2073656c662e73796d626f6c2c0a20202020202020202020202020202020202020207572693a2073656c662e636f6e747261637455524920213d206e696c203f2043726f7373564d4e46542e55524928626173655552493a206e696c2c2076616c75653a2073656c662e636f6e74726163745552492129203a2043726f7373564d4e46542e55524928626173655552493a206e696c2c2076616c75653a202222290a20202020202020202020202020202020290a20202020202020207d0a202020202020202072657475726e206e696c0a202020207d0a0a202020202f2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a0a2020202020202020496e7465726e616c204d6574686f64730a202020202a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2f0a0a202020202f2f2f20416c6c6f7773207468652062726964676520746f206d696e7420746f6b656e732066726f6d206272696467652d646566696e65642066756e6769626c6520746f6b656e20636f6e7472616374730a202020202f2f2f0a20202020616363657373286163636f756e74292066756e206d696e74546f6b656e7328616d6f756e743a20554669783634293a20407b46756e6769626c65546f6b656e2e5661756c747d207b0a202020202020202073656c662e746f74616c537570706c79203d2073656c662e746f74616c537570706c79202b20616d6f756e740a202020202020202072657475726e203c2d20637265617465205661756c742862616c616e63653a20616d6f756e74290a202020207d0a0a20202020696e6974286e616d653a20537472696e672c2073796d626f6c3a20537472696e672c20646563696d616c733a2055496e74382c2065766d436f6e7472616374416464726573733a2045564d2e45564d416464726573732c20636f6e74726163745552493a20537472696e673f29207b0a202020202020202073656c662e65766d546f6b656e436f6e747261637441646472657373203d2065766d436f6e7472616374416464726573730a202020202020202073656c662e6e616d65203d206e616d650a202020202020202073656c662e73796d626f6c203d2073796d626f6c0a202020202020202073656c662e646563696d616c73203d20646563696d616c730a202020202020202073656c662e636f6e7472616374555249203d20636f6e74726163745552490a202020202020202073656c662e746f74616c537570706c79203d20302e300a202020202020202073656c662e7661756c74203c2d20637265617465205661756c742862616c616e63653a20302e30290a0a2020202020202020466c6f7745564d427269646765436f6e6669672e6173736f63696174655479706528547970653c40" + }, { + "type": "String", + "value": "2e5661756c743e28292c20776974683a2073656c662e65766d546f6b656e436f6e747261637441646472657373290a2020202020202020466c6f7745564d427269646765546f6b656e457363726f772e696e697469616c697a65457363726f77280a202020202020202020202020776974683a203c2d637265617465205661756c742862616c616e63653a20302e30292c0a2020202020202020202020206e616d653a206e616d652c0a20202020202020202020202073796d626f6c3a2073796d626f6c2c0a202020202020202020202020646563696d616c733a20646563696d616c732c0a20202020202020202020202065766d546f6b656e416464726573733a2073656c662e65766d546f6b656e436f6e7472616374416464726573730a2020202020202020290a202020207d0a7d0a" + } + ] + } +] \ No newline at end of file diff --git a/cadence/args/deploy-erc20-args.json b/cadence/args/deploy-erc20-args.json new file mode 100644 index 00000000..e7bb0595 --- /dev/null +++ b/cadence/args/deploy-erc20-args.json @@ -0,0 +1,14 @@ +[ + { + "type": "String", + "value": "6101606040523480156200001257600080fd5b50604051806040016040528060048152602001634e414d4560e01b81525080604051806040016040528060018152602001603160f81b81525033604051806040016040528060048152602001634e414d4560e01b8152506040518060400160405280600681526020016514d6535093d360d21b815250816003908162000099919062000318565b506004620000a8828262000318565b5050506001600160a01b038116620000db57604051631e4fbdf760e01b8152600060048201526024015b60405180910390fd5b620000e681620001a3565b50620000f4826006620001f5565b6101205262000105816007620001f5565b61014052815160208084019190912060e052815190820120610100524660a0526200019360e05161010051604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201529081019290925260608201524660808201523060a082015260009060c00160405160208183030381529060405280519060200120905090565b60805250503060c052506200045a565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600060208351101562000215576200020d836200022e565b905062000228565b8162000222848262000318565b5060ff90505b92915050565b600080829050601f815111156200025c578260405163305a27a960e01b8152600401620000d29190620003e4565b8051620002698262000435565b179392505050565b634e487b7160e01b600052604160045260246000fd5b600181811c908216806200029c57607f821691505b602082108103620002bd57634e487b7160e01b600052602260045260246000fd5b50919050565b601f82111562000313576000816000526020600020601f850160051c81016020861015620002ee5750805b601f850160051c820191505b818110156200030f57828155600101620002fa565b5050505b505050565b81516001600160401b0381111562000334576200033462000271565b6200034c8162000345845462000287565b84620002c3565b602080601f8311600181146200038457600084156200036b5750858301515b600019600386901b1c1916600185901b1785556200030f565b600085815260208120601f198616915b82811015620003b55788860151825594840194600190910190840162000394565b5085821015620003d45787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60006020808352835180602085015260005b818110156200041457858101830151858201604001528201620003f6565b506000604082860101526040601f19601f8301168501019250505092915050565b80516020808301519190811015620002bd5760001960209190910360031b1b16919050565b60805160a05160c05160e051610100516101205161014051611147620004b5600039600061093101526000610904015260006107c101526000610799015260006106f40152600061071e0152600061074801526111476000f3fe608060405234801561001057600080fd5b50600436106101215760003560e01c8063715018a6116100ad57806395d89b411161007157806395d89b4114610258578063a9059cbb14610260578063d505accf14610273578063dd62ed3e14610286578063f2fde38b146102bf57600080fd5b8063715018a6146101f457806379cc6790146101fc5780637ecebe001461020f57806384b0196e146102225780638da5cb5b1461023d57600080fd5b8063313ce567116100f4578063313ce5671461018c5780633644e5151461019b57806340c10f19146101a357806342966c68146101b857806370a08231146101cb57600080fd5b806306fdde0314610126578063095ea7b31461014457806318160ddd1461016757806323b872dd14610179575b600080fd5b61012e6102d2565b60405161013b9190610e91565b60405180910390f35b610157610152366004610ec7565b610364565b604051901515815260200161013b565b6002545b60405190815260200161013b565b610157610187366004610ef1565b61037e565b6040516012815260200161013b565b61016b6103a2565b6101b66101b1366004610ec7565b6103b1565b005b6101b66101c6366004610f2d565b6103c7565b61016b6101d9366004610f46565b6001600160a01b031660009081526020819052604090205490565b6101b66103d4565b6101b661020a366004610ec7565b6103e8565b61016b61021d366004610f46565b6103fd565b61022a61041b565b60405161013b9796959493929190610f61565b6005546040516001600160a01b03909116815260200161013b565b61012e610461565b61015761026e366004610ec7565b610470565b6101b6610281366004610ffa565b61047e565b61016b61029436600461106d565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b6101b66102cd366004610f46565b6105bd565b6060600380546102e1906110a0565b80601f016020809104026020016040519081016040528092919081815260200182805461030d906110a0565b801561035a5780601f1061032f5761010080835404028352916020019161035a565b820191906000526020600020905b81548152906001019060200180831161033d57829003601f168201915b5050505050905090565b6000336103728185856105f8565b60019150505b92915050565b60003361038c85828561060a565b610397858585610688565b506001949350505050565b60006103ac6106e7565b905090565b6103b9610812565b6103c3828261083f565b5050565b6103d13382610875565b50565b6103dc610812565b6103e660006108ab565b565b6103f382338361060a565b6103c38282610875565b6001600160a01b038116600090815260086020526040812054610378565b60006060806000806000606061042f6108fd565b61043761092a565b60408051600080825260208201909252600f60f81b9b939a50919850469750309650945092509050565b6060600480546102e1906110a0565b600033610372818585610688565b834211156104a75760405163313c898160e11b8152600481018590526024015b60405180910390fd5b60007f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98888886104f48c6001600160a01b0316600090815260086020526040902080546001810190915590565b6040805160208101969096526001600160a01b0394851690860152929091166060840152608083015260a082015260c0810186905260e001604051602081830303815290604052805190602001209050600061054f82610957565b9050600061055f82878787610984565b9050896001600160a01b0316816001600160a01b0316146105a6576040516325c0072360e11b81526001600160a01b0380831660048301528b16602482015260440161049e565b6105b18a8a8a6105f8565b50505050505050505050565b6105c5610812565b6001600160a01b0381166105ef57604051631e4fbdf760e01b81526000600482015260240161049e565b6103d1816108ab565b61060583838360016109b2565b505050565b6001600160a01b038381166000908152600160209081526040808320938616835292905220546000198114610682578181101561067357604051637dc7a0d960e11b81526001600160a01b0384166004820152602481018290526044810183905260640161049e565b610682848484840360006109b2565b50505050565b6001600160a01b0383166106b257604051634b637e8f60e11b81526000600482015260240161049e565b6001600160a01b0382166106dc5760405163ec442f0560e01b81526000600482015260240161049e565b610605838383610a87565b6000306001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614801561074057507f000000000000000000000000000000000000000000000000000000000000000046145b1561076a57507f000000000000000000000000000000000000000000000000000000000000000090565b6103ac604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201527f0000000000000000000000000000000000000000000000000000000000000000918101919091527f000000000000000000000000000000000000000000000000000000000000000060608201524660808201523060a082015260009060c00160405160208183030381529060405280519060200120905090565b6005546001600160a01b031633146103e65760405163118cdaa760e01b815233600482015260240161049e565b6001600160a01b0382166108695760405163ec442f0560e01b81526000600482015260240161049e565b6103c360008383610a87565b6001600160a01b03821661089f57604051634b637e8f60e11b81526000600482015260240161049e565b6103c382600083610a87565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b60606103ac7f00000000000000000000000000000000000000000000000000000000000000006006610bb1565b60606103ac7f00000000000000000000000000000000000000000000000000000000000000006007610bb1565b60006103786109646106e7565b8360405161190160f01b8152600281019290925260228201526042902090565b60008060008061099688888888610c5c565b9250925092506109a68282610d2b565b50909695505050505050565b6001600160a01b0384166109dc5760405163e602df0560e01b81526000600482015260240161049e565b6001600160a01b038316610a0657604051634a1406b160e11b81526000600482015260240161049e565b6001600160a01b038085166000908152600160209081526040808320938716835292905220829055801561068257826001600160a01b0316846001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92584604051610a7991815260200190565b60405180910390a350505050565b6001600160a01b038316610ab2578060026000828254610aa791906110da565b90915550610b249050565b6001600160a01b03831660009081526020819052604090205481811015610b055760405163391434e360e21b81526001600160a01b0385166004820152602481018290526044810183905260640161049e565b6001600160a01b03841660009081526020819052604090209082900390555b6001600160a01b038216610b4057600280548290039055610b5f565b6001600160a01b03821660009081526020819052604090208054820190555b816001600160a01b0316836001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef83604051610ba491815260200190565b60405180910390a3505050565b606060ff8314610bcb57610bc483610de4565b9050610378565b818054610bd7906110a0565b80601f0160208091040260200160405190810160405280929190818152602001828054610c03906110a0565b8015610c505780601f10610c2557610100808354040283529160200191610c50565b820191906000526020600020905b815481529060010190602001808311610c3357829003601f168201915b50505050509050610378565b600080807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0841115610c975750600091506003905082610d21565b604080516000808252602082018084528a905260ff891692820192909252606081018790526080810186905260019060a0016020604051602081039080840390855afa158015610ceb573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116610d1757506000925060019150829050610d21565b9250600091508190505b9450945094915050565b6000826003811115610d3f57610d3f6110fb565b03610d48575050565b6001826003811115610d5c57610d5c6110fb565b03610d7a5760405163f645eedf60e01b815260040160405180910390fd5b6002826003811115610d8e57610d8e6110fb565b03610daf5760405163fce698f760e01b81526004810182905260240161049e565b6003826003811115610dc357610dc36110fb565b036103c3576040516335e2f38360e21b81526004810182905260240161049e565b60606000610df183610e23565b604080516020808252818301909252919250600091906020820181803683375050509182525060208101929092525090565b600060ff8216601f81111561037857604051632cd44ac360e21b815260040160405180910390fd5b6000815180845260005b81811015610e7157602081850181015186830182015201610e55565b506000602082860101526020601f19601f83011685010191505092915050565b602081526000610ea46020830184610e4b565b9392505050565b80356001600160a01b0381168114610ec257600080fd5b919050565b60008060408385031215610eda57600080fd5b610ee383610eab565b946020939093013593505050565b600080600060608486031215610f0657600080fd5b610f0f84610eab565b9250610f1d60208501610eab565b9150604084013590509250925092565b600060208284031215610f3f57600080fd5b5035919050565b600060208284031215610f5857600080fd5b610ea482610eab565b60ff60f81b881681526000602060e06020840152610f8260e084018a610e4b565b8381036040850152610f94818a610e4b565b606085018990526001600160a01b038816608086015260a0850187905284810360c08601528551808252602080880193509091019060005b81811015610fe857835183529284019291840191600101610fcc565b50909c9b505050505050505050505050565b600080600080600080600060e0888a03121561101557600080fd5b61101e88610eab565b965061102c60208901610eab565b95506040880135945060608801359350608088013560ff8116811461105057600080fd5b9699959850939692959460a0840135945060c09093013592915050565b6000806040838503121561108057600080fd5b61108983610eab565b915061109760208401610eab565b90509250929050565b600181811c908216806110b457607f821691505b6020821081036110d457634e487b7160e01b600052602260045260246000fd5b50919050565b8082018082111561037857634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052602160045260246000fdfea2646970667358221220f1e9d08ff3a77a5dedf27b973e8f3f8da74683e415389a21794cdc5ebb196f9164736f6c63430008170033" + }, + { + "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 52ac023c..9df43cb2 100644 --- a/cadence/args/deploy-factory-args.json +++ b/cadence/args/deploy-factory-args.json @@ -1,6 +1,6 @@ [ { "type": "String", - "value": "608060405234801561001057600080fd5b50338061003757604051631e4fbdf760e01b81526000600482015260240160405180910390fd5b61004081610046565b50610096565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6129f4806100a56000396000f3fe60806040523480156200001157600080fd5b5060043610620000ab5760003560e01c80638da5cb5b116200006e5780638da5cb5b1462000155578063d56e0ccf1462000167578063daa09e54146200019e578063f2fde38b14620001b5578063f93241dd14620001cc57600080fd5b806304433bbc14620000b05780630a2c0ce914620000e4578063335f4c76146200010a57806361a169051462000132578063715018a61462000149575b600080fd5b620000c7620000c1366004620006ae565b620001e3565b6040516001600160a01b0390911681526020015b60405180910390f35b620000fb620000f5366004620006ef565b62000216565b604051620000db919062000775565b620001216200011b366004620006ef565b620002ca565b6040519015158152602001620000db565b620000c7620001433660046200078a565b620002f8565b62000153620003f9565b005b6000546001600160a01b0316620000c7565b620000c762000178366004620006ae565b80516020818301810180516001825292820191909301209152546001600160a01b031681565b62000121620001af366004620006ef565b62000411565b62000153620001c6366004620006ef565b6200048c565b620000fb620001dd366004620006ef565b620004d4565b6000600182604051620001f791906200086c565b908152604051908190036020019020546001600160a01b031692915050565b6001600160a01b03811660009081526002602052604090208054606091906200023f906200088a565b80601f01602080910402602001604051908101604052809291908181526020018280546200026d906200088a565b8015620002be5780601f106200029257610100808354040283529160200191620002be565b820191906000526020600020905b815481529060010190602001808311620002a057829003601f168201915b50505050509050919050565b6001600160a01b03811660009081526002602052604081208054620002ef906200088a565b15159392505050565b60006200030462000576565b600080546001600160a01b031687878787876040516200032490620005f5565b6200033596959493929190620008c6565b604051809103906000f08015801562000352573d6000803e3d6000fd5b509050806001856040516200036891906200086c565b908152604080516020928190038301902080546001600160a01b0319166001600160a01b039485161790559183166000908152600290915220620003ad8582620009a4565b507fbebce54951ebf20c0dcd195a45bb2388d9ac8e38b5974e00bb63c5822dbe65f08188888888604051620003e795949392919062000a71565b60405180910390a19695505050505050565b6200040362000576565b6200040f6000620005a5565b565b6040516301ffc9a760e01b81526380ac58cd60e01b60048201526000906001600160a01b038316906301ffc9a790602401602060405180830381865afa15801562000460573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000486919062000ae3565b92915050565b6200049662000576565b6001600160a01b038116620004c657604051631e4fbdf760e01b8152600060048201526024015b60405180910390fd5b620004d181620005a5565b50565b60026020526000908152604090208054620004ef906200088a565b80601f01602080910402602001604051908101604052809291908181526020018280546200051d906200088a565b80156200056e5780601f1062000542576101008083540402835291602001916200056e565b820191906000526020600020905b8154815290600101906020018083116200055057829003601f168201915b505050505081565b6000546001600160a01b031633146200040f5760405163118cdaa760e01b8152336004820152602401620004bd565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b611eb78062000b0883390190565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126200062b57600080fd5b813567ffffffffffffffff8082111562000649576200064962000603565b604051601f8301601f19908116603f0116810190828211818310171562000674576200067462000603565b816040528381528660208588010111156200068e57600080fd5b836020870160208301376000602085830101528094505050505092915050565b600060208284031215620006c157600080fd5b813567ffffffffffffffff811115620006d957600080fd5b620006e78482850162000619565b949350505050565b6000602082840312156200070257600080fd5b81356001600160a01b03811681146200071a57600080fd5b9392505050565b60005b838110156200073e57818101518382015260200162000724565b50506000910152565b600081518084526200076181602086016020860162000721565b601f01601f19169290920160200192915050565b6020815260006200071a602083018462000747565b600080600080600060a08688031215620007a357600080fd5b853567ffffffffffffffff80821115620007bc57600080fd5b620007ca89838a0162000619565b96506020880135915080821115620007e157600080fd5b620007ef89838a0162000619565b955060408801359150808211156200080657600080fd5b6200081489838a0162000619565b945060608801359150808211156200082b57600080fd5b6200083989838a0162000619565b935060808801359150808211156200085057600080fd5b506200085f8882890162000619565b9150509295509295909350565b600082516200088081846020870162000721565b9190910192915050565b600181811c908216806200089f57607f821691505b602082108103620008c057634e487b7160e01b600052602260045260246000fd5b50919050565b6001600160a01b038716815260c060208201819052600090620008ec9083018862000747565b828103604084015262000900818862000747565b9050828103606084015262000916818762000747565b905082810360808401526200092c818662000747565b905082810360a084015262000942818562000747565b9998505050505050505050565b601f8211156200099f576000816000526020600020601f850160051c810160208610156200097a5750805b601f850160051c820191505b818110156200099b5782815560010162000986565b5050505b505050565b815167ffffffffffffffff811115620009c157620009c162000603565b620009d981620009d284546200088a565b846200094f565b602080601f83116001811462000a115760008415620009f85750858301515b600019600386901b1c1916600185901b1785556200099b565b600085815260208120601f198616915b8281101562000a425788860151825594840194600190910190840162000a21565b508582101562000a615787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6001600160a01b038616815260a06020820181905260009062000a979083018762000747565b828103604084015262000aab818762000747565b9050828103606084015262000ac1818662000747565b9050828103608084015262000ad7818562000747565b98975050505050505050565b60006020828403121562000af657600080fd5b815180151581146200071a57600080fdfe60806040523480156200001157600080fd5b5060405162001eb738038062001eb7833981016040819052620000349162000202565b858585600062000045838262000386565b50600162000054828262000386565b5050506001600160a01b0381166200008657604051631e4fbdf760e01b81526000600482015260240160405180910390fd5b6200009181620000cb565b50600c620000a0848262000386565b50600d620000af838262000386565b50600e620000be828262000386565b5050505050505062000452565b600b80546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b80516001600160a01b03811681146200013557600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126200016257600080fd5b81516001600160401b03808211156200017f576200017f6200013a565b604051601f8301601f19908116603f01168101908282118183101715620001aa57620001aa6200013a565b8160405283815260209250866020858801011115620001c857600080fd5b600091505b83821015620001ec5785820183015181830184015290820190620001cd565b6000602085830101528094505050505092915050565b60008060008060008060c087890312156200021c57600080fd5b62000227876200011d565b60208801519096506001600160401b03808211156200024557600080fd5b620002538a838b0162000150565b965060408901519150808211156200026a57600080fd5b620002788a838b0162000150565b955060608901519150808211156200028f57600080fd5b6200029d8a838b0162000150565b94506080890151915080821115620002b457600080fd5b620002c28a838b0162000150565b935060a0890151915080821115620002d957600080fd5b50620002e889828a0162000150565b9150509295509295509295565b600181811c908216806200030a57607f821691505b6020821081036200032b57634e487b7160e01b600052602260045260246000fd5b50919050565b601f82111562000381576000816000526020600020601f850160051c810160208610156200035c5750805b601f850160051c820191505b818110156200037d5782815560010162000368565b5050505b505050565b81516001600160401b03811115620003a257620003a26200013a565b620003ba81620003b38454620002f5565b8462000331565b602080601f831160018114620003f25760008415620003d95750858301515b600019600386901b1c1916600185901b1785556200037d565b600085815260208120601f198616915b82811015620004235788860151825594840194600190910190840162000402565b5085821015620004425787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b611a5580620004626000396000f3fe608060405234801561001057600080fd5b50600436106101cf5760003560e01c806370a0823111610104578063a76b4d56116100a2578063cd279c7c11610071578063cd279c7c146103a8578063e8a3d485146103bb578063e985e9c5146103c3578063f2fde38b146103d657600080fd5b8063a76b4d5614610372578063b49bbd941461037a578063b88d4fde14610382578063c87b56dd1461039557600080fd5b806394e29329116100de57806394e293291461034757806395d89b411461034f578063a159047b14610357578063a22cb4651461035f57600080fd5b806370a082311461031b578063715018a61461032e5780638da5cb5b1461033657600080fd5b80632f745c59116101715780634f558e791161014b5780634f558e79146102c25780634f6ccce7146102ed5780635e0a9661146103005780636352211e1461030857600080fd5b80632f745c591461028957806342842e0e1461029c57806342966c68146102af57600080fd5b8063095ea7b3116101ad578063095ea7b31461023c57806318160ddd1461025157806318e97fd11461026357806323b872dd1461027657600080fd5b806301ffc9a7146101d457806306fdde03146101fc578063081812fc14610211575b600080fd5b6101e76101e2366004611494565b6103e9565b60405190151581526020015b60405180910390f35b6102046103fa565b6040516101f39190611501565b61022461021f366004611514565b61048c565b6040516001600160a01b0390911681526020016101f3565b61024f61024a366004611549565b6104b5565b005b6009545b6040519081526020016101f3565b61024f61027136600461161f565b6104c4565b61024f610284366004611666565b6104d6565b610255610297366004611549565b610566565b61024f6102aa366004611666565b6105cb565b61024f6102bd366004611514565b6105eb565b6101e76102d0366004611514565b6000908152600260205260409020546001600160a01b0316151590565b6102556102fb366004611514565b6105f7565b610204610650565b610224610316366004611514565b61065f565b6102556103293660046116a2565b61066a565b61024f6106b2565b600b546001600160a01b0316610224565b6102046106c6565b6102046106d5565b6102046106e4565b61024f61036d3660046116bd565b610772565b61020461077d565b61020461078a565b61024f6103903660046116f9565b610797565b6102046103a3366004611514565b6107ae565b61024f6103b6366004611775565b6107b9565b6102046107d5565b6101e76103d13660046117cc565b6107e4565b61024f6103e43660046116a2565b610812565b60006103f482610850565b92915050565b606060008054610409906117ff565b80601f0160208091040260200160405190810160405280929190818152602001828054610435906117ff565b80156104825780601f1061045757610100808354040283529160200191610482565b820191906000526020600020905b81548152906001019060200180831161046557829003601f168201915b5050505050905090565b600061049782610875565b506000828152600460205260409020546001600160a01b03166103f4565b6104c08282336108ae565b5050565b6104cc6108bb565b6104c082826108e8565b6001600160a01b03821661050557604051633250574960e11b8152600060048201526024015b60405180910390fd5b6000610512838333610938565b9050836001600160a01b0316816001600160a01b031614610560576040516364283d7b60e01b81526001600160a01b03808616600483015260248201849052821660448201526064016104fc565b50505050565b60006105718361066a565b82106105a25760405163295f44f760e21b81526001600160a01b0384166004820152602481018390526044016104fc565b506001600160a01b03919091166000908152600760209081526040808320938352929052205490565b6105e683838360405180602001604052806000815250610797565b505050565b6104c060008233610938565b600061060260095490565b821061062b5760405163295f44f760e21b815260006004820152602481018390526044016104fc565b6009828154811061063e5761063e611839565b90600052602060002001549050919050565b6060600d8054610409906117ff565b60006103f482610875565b60006001600160a01b038216610696576040516322718ad960e21b8152600060048201526024016104fc565b506001600160a01b031660009081526003602052604090205490565b6106ba6108bb565b6106c4600061094d565b565b6060600c8054610409906117ff565b606060018054610409906117ff565b600d80546106f1906117ff565b80601f016020809104026020016040519081016040528092919081815260200182805461071d906117ff565b801561076a5780601f1061073f5761010080835404028352916020019161076a565b820191906000526020600020905b81548152906001019060200180831161074d57829003601f168201915b505050505081565b6104c033838361099f565b600e80546106f1906117ff565b600c80546106f1906117ff565b6107a28484846104d6565b61056084848484610a3e565b60606103f482610b67565b6107c16108bb565b6107cb8383610c70565b6105e682826108e8565b6060600e8054610409906117ff565b6001600160a01b03918216600090815260056020908152604080832093909416825291909152205460ff1690565b61081a6108bb565b6001600160a01b03811661084457604051631e4fbdf760e01b8152600060048201526024016104fc565b61084d8161094d565b50565b60006001600160e01b0319821663780e9d6360e01b14806103f457506103f482610c8a565b6000818152600260205260408120546001600160a01b0316806103f457604051637e27328960e01b8152600481018490526024016104fc565b6105e68383836001610caf565b600b546001600160a01b031633146106c45760405163118cdaa760e01b81523360048201526024016104fc565b6000828152600660205260409020610900828261189f565b506040518281527ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79060200160405180910390a15050565b6000610945848484610db5565b949350505050565b600b80546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6001600160a01b0382166109d157604051630b61174360e31b81526001600160a01b03831660048201526024016104fc565b6001600160a01b03838116600081815260056020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b6001600160a01b0383163b1561056057604051630a85bd0160e11b81526001600160a01b0384169063150b7a0290610a8090339088908790879060040161195f565b6020604051808303816000875af1925050508015610abb575060408051601f3d908101601f19168201909252610ab89181019061199c565b60015b610b24573d808015610ae9576040519150601f19603f3d011682016040523d82523d6000602084013e610aee565b606091505b508051600003610b1c57604051633250574960e11b81526001600160a01b03851660048201526024016104fc565b805181602001fd5b6001600160e01b03198116630a85bd0160e11b14610b6057604051633250574960e11b81526001600160a01b03851660048201526024016104fc565b5050505050565b6060610b7282610875565b5060008281526006602052604081208054610b8c906117ff565b80601f0160208091040260200160405190810160405280929190818152602001828054610bb8906117ff565b8015610c055780601f10610bda57610100808354040283529160200191610c05565b820191906000526020600020905b815481529060010190602001808311610be857829003601f168201915b505050505090506000610c2360408051602081019091526000815290565b90508051600003610c35575092915050565b815115610c67578082604051602001610c4f9291906119b9565b60405160208183030381529060405292505050919050565b61094584610e82565b6104c0828260405180602001604052806000815250610ef7565b60006001600160e01b03198216632483248360e11b14806103f457506103f482610f0e565b8080610cc357506001600160a01b03821615155b15610d85576000610cd384610875565b90506001600160a01b03831615801590610cff5750826001600160a01b0316816001600160a01b031614155b8015610d125750610d1081846107e4565b155b15610d3b5760405163a9fbf51f60e01b81526001600160a01b03841660048201526024016104fc565b8115610d835783856001600160a01b0316826001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45b505b5050600090815260046020526040902080546001600160a01b0319166001600160a01b0392909216919091179055565b600080610dc3858585610f5e565b90506001600160a01b038116610e2057610e1b84600980546000838152600a60205260408120829055600182018355919091527f6e1540171b6c0c960b71a7020d9f60077f6af931a8bbf590da0223dacf75c7af0155565b610e43565b846001600160a01b0316816001600160a01b031614610e4357610e438185611057565b6001600160a01b038516610e5f57610e5a846110e8565b610945565b846001600160a01b0316816001600160a01b031614610945576109458585611197565b6060610e8d82610875565b506000610ea560408051602081019091526000815290565b90506000815111610ec55760405180602001604052806000815250610ef0565b80610ecf846111e7565b604051602001610ee09291906119b9565b6040516020818303038152906040525b9392505050565b610f01838361127a565b6105e66000848484610a3e565b60006001600160e01b031982166380ac58cd60e01b1480610f3f57506001600160e01b03198216635b5e139f60e01b145b806103f457506301ffc9a760e01b6001600160e01b03198316146103f4565b6000828152600260205260408120546001600160a01b0390811690831615610f8b57610f8b8184866112df565b6001600160a01b03811615610fc957610fa8600085600080610caf565b6001600160a01b038116600090815260036020526040902080546000190190555b6001600160a01b03851615610ff8576001600160a01b0385166000908152600360205260409020805460010190555b60008481526002602052604080822080546001600160a01b0319166001600160a01b0389811691821790925591518793918516917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4949350505050565b60006110628361066a565b6000838152600860205260409020549091508082146110b5576001600160a01b03841660009081526007602090815260408083208584528252808320548484528184208190558352600890915290208190555b5060009182526008602090815260408084208490556001600160a01b039094168352600781528383209183525290812055565b6009546000906110fa906001906119e8565b6000838152600a60205260408120546009805493945090928490811061112257611122611839565b90600052602060002001549050806009838154811061114357611143611839565b6000918252602080832090910192909255828152600a9091526040808220849055858252812055600980548061117b5761117b611a09565b6001900381819060005260206000200160009055905550505050565b600060016111a48461066a565b6111ae91906119e8565b6001600160a01b039093166000908152600760209081526040808320868452825280832085905593825260089052919091209190915550565b606060006111f483611343565b600101905060008167ffffffffffffffff81111561121457611214611573565b6040519080825280601f01601f19166020018201604052801561123e576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a850494508461124857509392505050565b6001600160a01b0382166112a457604051633250574960e11b8152600060048201526024016104fc565b60006112b283836000610938565b90506001600160a01b038116156105e6576040516339e3563760e11b8152600060048201526024016104fc565b6112ea83838361141b565b6105e6576001600160a01b03831661131857604051637e27328960e01b8152600481018290526024016104fc565b60405163177e802f60e01b81526001600160a01b0383166004820152602481018290526044016104fc565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b83106113825772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef810000000083106113ae576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc1000083106113cc57662386f26fc10000830492506010015b6305f5e10083106113e4576305f5e100830492506008015b61271083106113f857612710830492506004015b6064831061140a576064830492506002015b600a83106103f45760010192915050565b60006001600160a01b038316158015906109455750826001600160a01b0316846001600160a01b03161480611455575061145584846107e4565b806109455750506000908152600460205260409020546001600160a01b03908116911614919050565b6001600160e01b03198116811461084d57600080fd5b6000602082840312156114a657600080fd5b8135610ef08161147e565b60005b838110156114cc5781810151838201526020016114b4565b50506000910152565b600081518084526114ed8160208601602086016114b1565b601f01601f19169290920160200192915050565b602081526000610ef060208301846114d5565b60006020828403121561152657600080fd5b5035919050565b80356001600160a01b038116811461154457600080fd5b919050565b6000806040838503121561155c57600080fd5b6115658361152d565b946020939093013593505050565b634e487b7160e01b600052604160045260246000fd5b600067ffffffffffffffff808411156115a4576115a4611573565b604051601f8501601f19908116603f011681019082821181831017156115cc576115cc611573565b816040528093508581528686860111156115e557600080fd5b858560208301376000602087830101525050509392505050565b600082601f83011261161057600080fd5b610ef083833560208501611589565b6000806040838503121561163257600080fd5b82359150602083013567ffffffffffffffff81111561165057600080fd5b61165c858286016115ff565b9150509250929050565b60008060006060848603121561167b57600080fd5b6116848461152d565b92506116926020850161152d565b9150604084013590509250925092565b6000602082840312156116b457600080fd5b610ef08261152d565b600080604083850312156116d057600080fd5b6116d98361152d565b9150602083013580151581146116ee57600080fd5b809150509250929050565b6000806000806080858703121561170f57600080fd5b6117188561152d565b93506117266020860161152d565b925060408501359150606085013567ffffffffffffffff81111561174957600080fd5b8501601f8101871361175a57600080fd5b61176987823560208401611589565b91505092959194509250565b60008060006060848603121561178a57600080fd5b6117938461152d565b925060208401359150604084013567ffffffffffffffff8111156117b657600080fd5b6117c2868287016115ff565b9150509250925092565b600080604083850312156117df57600080fd5b6117e88361152d565b91506117f66020840161152d565b90509250929050565b600181811c9082168061181357607f821691505b60208210810361183357634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052603260045260246000fd5b601f8211156105e6576000816000526020600020601f850160051c810160208610156118785750805b601f850160051c820191505b8181101561189757828155600101611884565b505050505050565b815167ffffffffffffffff8111156118b9576118b9611573565b6118cd816118c784546117ff565b8461184f565b602080601f83116001811461190257600084156118ea5750858301515b600019600386901b1c1916600185901b178555611897565b600085815260208120601f198616915b8281101561193157888601518255948401946001909101908401611912565b508582101561194f5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6001600160a01b0385811682528416602082015260408101839052608060608201819052600090611992908301846114d5565b9695505050505050565b6000602082840312156119ae57600080fd5b8151610ef08161147e565b600083516119cb8184602088016114b1565b8351908301906119df8183602088016114b1565b01949350505050565b818103818111156103f457634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052603160045260246000fdfea26469706673582212206ff38700c73b602455dbb7964f2d3281f62efc77263f0f3bdb67f5e4ee5d4f3f64736f6c63430008170033a26469706673582212207f55223fc039b168a1e0c0bb9dc8d219b8219d1b2151fe8e9843aecefd41f82664736f6c63430008170033" + "value": "608060405234801561001057600080fd5b50338061003757604051631e4fbdf760e01b81526000600482015260240160405180910390fd5b61004081610046565b50610096565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b61484a806100a56000396000f3fe60806040523480156200001157600080fd5b5060043610620000c35760003560e01c8063715018a6116200007a578063715018a6146200018f5780638da5cb5b146200019b578063d56e0ccf14620001ad578063daa09e5414620001e4578063f2fde38b14620001fb578063f93241dd146200021257600080fd5b806304433bbc14620000c85780630a2c0ce914620000fc578063263e0c1b1462000122578063335f4c76146200014a57806340f8d42b146200016157806361a169051462000178575b600080fd5b620000df620000d936600462000c0a565b62000229565b6040516001600160a01b0390911681526020015b60405180910390f35b620001136200010d36600462000c4b565b6200025c565b604051620000f3919062000cd1565b620001396200013336600462000c4b565b62000310565b6040519015158152602001620000f3565b620001396200015b36600462000c4b565b62000724565b620000df6200017236600462000ce6565b62000752565b620000df6200018936600462000ce6565b62000853565b6200019962000942565b005b6000546001600160a01b0316620000df565b620000df620001be36600462000c0a565b80516020818301810180516001825292820191909301209152546001600160a01b031681565b62000139620001f536600462000c4b565b6200095a565b620001996200020c36600462000c4b565b620009da565b620001136200022336600462000c4b565b62000a22565b60006001826040516200023d919062000dc8565b908152604051908190036020019020546001600160a01b031692915050565b6001600160a01b0381166000908152600260205260409020805460609190620002859062000de6565b80601f0160208091040260200160405190810160405280929190818152602001828054620002b39062000de6565b8015620003045780601f10620002d85761010080835404028352916020019162000304565b820191906000526020600020905b815481529060010190602001808311620002e657829003601f168201915b50505050509050919050565b60408051600481526024810182526020810180516001600160e01b03166318160ddd60e01b1790529051600091829182916001600160a01b0386169162000358919062000dc8565b600060405180830381855afa9150503d806000811462000395576040519150601f19603f3d011682016040523d82523d6000602084013e6200039a565b606091505b5091509150811580620003ac57508051155b15620003bc575060009392505050565b604051600060248201526001600160a01b0385169060440160408051601f198184030181529181526020820180516001600160e01b03166370a0823160e01b179052516200040b919062000dc8565b600060405180830381855afa9150503d806000811462000448576040519150601f19603f3d011682016040523d82523d6000602084013e6200044d565b606091505b5090925090508115806200046057508051155b1562000470575060009392505050565b60405160006024820181905260448201526001600160a01b0385169060640160408051601f198184030181529181526020820180516001600160e01b0316636eb1769f60e11b17905251620004c6919062000dc8565b600060405180830381855afa9150503d806000811462000503576040519150601f19603f3d011682016040523d82523d6000602084013e62000508565b606091505b5090925090508115806200051b57508051155b156200052b575060009392505050565b60408051600481526024810182526020810180516001600160e01b03166306fdde0360e01b17905290516001600160a01b038616916200056b9162000dc8565b600060405180830381855afa9150503d8060008114620005a8576040519150601f19603f3d011682016040523d82523d6000602084013e620005ad565b606091505b509092509050811580620005c057508051155b15620005d0575060009392505050565b60408051600481526024810182526020810180516001600160e01b03166395d89b4160e01b17905290516001600160a01b03861691620006109162000dc8565b600060405180830381855afa9150503d80600081146200064d576040519150601f19603f3d011682016040523d82523d6000602084013e62000652565b606091505b5090925090508115806200066557508051155b1562000675575060009392505050565b60408051600481526024810182526020810180516001600160e01b031663313ce56760e01b17905290516001600160a01b03861691620006b59162000dc8565b600060405180830381855afa9150503d8060008114620006f2576040519150601f19603f3d011682016040523d82523d6000602084013e620006f7565b606091505b5090925090508115806200070a57508051155b156200071a575060009392505050565b5060019392505050565b6001600160a01b03811660009081526002602052604081208054620007499062000de6565b15159392505050565b60006200075e62000ac4565b600080546001600160a01b031687878787876040516200077e9062000b43565b6200078f9695949392919062000e22565b604051809103906000f080158015620007ac573d6000803e3d6000fd5b50905080600185604051620007c2919062000dc8565b908152604080516020928190038301902080546001600160a01b0319166001600160a01b03948516179055918316600090815260029091522062000807858262000f00565b507f99a64021330f1af36b3fd5f64a1d12b99b8ddf91fa553618c4df01ffba4c1cee81888888886040516200084195949392919062000fcd565b60405180910390a19695505050505050565b60006200085f62000ac4565b600080546001600160a01b031687878787876040516200087f9062000b51565b620008909695949392919062000e22565b604051809103906000f080158015620008ad573d6000803e3d6000fd5b50905080600185604051620008c3919062000dc8565b908152604080516020928190038301902080546001600160a01b0319166001600160a01b03948516179055918316600090815260029091522062000908858262000f00565b507fbebce54951ebf20c0dcd195a45bb2388d9ac8e38b5974e00bb63c5822dbe65f081888888886040516200084195949392919062000fcd565b6200094c62000ac4565b62000958600062000af3565b565b6040516301ffc9a760e01b81526380ac58cd60e01b60048201526000906001600160a01b038316906301ffc9a790602401602060405180830381865afa925050508015620009c7575060408051601f3d908101601f19168201909252620009c4918101906200103f565b60015b620009d457506000919050565b92915050565b620009e462000ac4565b6001600160a01b03811662000a1457604051631e4fbdf760e01b8152600060048201526024015b60405180910390fd5b62000a1f8162000af3565b50565b6002602052600090815260409020805462000a3d9062000de6565b80601f016020809104026020016040519081016040528092919081815260200182805462000a6b9062000de6565b801562000abc5780601f1062000a905761010080835404028352916020019162000abc565b820191906000526020600020905b81548152906001019060200180831162000a9e57829003601f168201915b505050505081565b6000546001600160a01b03163314620009585760405163118cdaa760e01b815233600482015260240162000a0b565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6118fa806200106483390190565b611eb7806200295e83390190565b634e487b7160e01b600052604160045260246000fd5b600082601f83011262000b8757600080fd5b813567ffffffffffffffff8082111562000ba55762000ba562000b5f565b604051601f8301601f19908116603f0116810190828211818310171562000bd05762000bd062000b5f565b8160405283815286602085880101111562000bea57600080fd5b836020870160208301376000602085830101528094505050505092915050565b60006020828403121562000c1d57600080fd5b813567ffffffffffffffff81111562000c3557600080fd5b62000c438482850162000b75565b949350505050565b60006020828403121562000c5e57600080fd5b81356001600160a01b038116811462000c7657600080fd5b9392505050565b60005b8381101562000c9a57818101518382015260200162000c80565b50506000910152565b6000815180845262000cbd81602086016020860162000c7d565b601f01601f19169290920160200192915050565b60208152600062000c76602083018462000ca3565b600080600080600060a0868803121562000cff57600080fd5b853567ffffffffffffffff8082111562000d1857600080fd5b62000d2689838a0162000b75565b9650602088013591508082111562000d3d57600080fd5b62000d4b89838a0162000b75565b9550604088013591508082111562000d6257600080fd5b62000d7089838a0162000b75565b9450606088013591508082111562000d8757600080fd5b62000d9589838a0162000b75565b9350608088013591508082111562000dac57600080fd5b5062000dbb8882890162000b75565b9150509295509295909350565b6000825162000ddc81846020870162000c7d565b9190910192915050565b600181811c9082168062000dfb57607f821691505b60208210810362000e1c57634e487b7160e01b600052602260045260246000fd5b50919050565b6001600160a01b038716815260c06020820181905260009062000e489083018862000ca3565b828103604084015262000e5c818862000ca3565b9050828103606084015262000e72818762000ca3565b9050828103608084015262000e88818662000ca3565b905082810360a084015262000e9e818562000ca3565b9998505050505050505050565b601f82111562000efb576000816000526020600020601f850160051c8101602086101562000ed65750805b601f850160051c820191505b8181101562000ef75782815560010162000ee2565b5050505b505050565b815167ffffffffffffffff81111562000f1d5762000f1d62000b5f565b62000f358162000f2e845462000de6565b8462000eab565b602080601f83116001811462000f6d576000841562000f545750858301515b600019600386901b1c1916600185901b17855562000ef7565b600085815260208120601f198616915b8281101562000f9e5788860151825594840194600190910190840162000f7d565b508582101562000fbd5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6001600160a01b038616815260a06020820181905260009062000ff39083018762000ca3565b828103604084015262001007818762000ca3565b905082810360608401526200101d818662000ca3565b9050828103608084015262001033818562000ca3565b98975050505050505050565b6000602082840312156200105257600080fd5b8151801515811462000c7657600080fdfe6101606040523480156200001257600080fd5b50604051620018fa380380620018fa833981016040819052620000359162000357565b6040805180820190915260018152603160f81b6020820152859081908882886003620000628382620004db565b506004620000718282620004db565b5050506001600160a01b038116620000a457604051631e4fbdf760e01b8152600060048201526024015b60405180910390fd5b620000af816200019f565b50620000bd826006620001f1565b61012052620000ce816007620001f1565b61014052815160208084019190912060e052815190820120610100524660a0526200015c60e05161010051604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201529081019290925260608201524660808201523060a082015260009060c00160405160208183030381529060405280519060200120905090565b60805250503060c052506009620001748482620004db565b50600a620001838382620004db565b50600b620001928282620004db565b5050505050505062000601565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6000602083511015620002115762000209836200022a565b905062000224565b816200021e8482620004db565b5060ff90505b92915050565b600080829050601f8151111562000258578260405163305a27a960e01b81526004016200009b9190620005a7565b80516200026582620005dc565b179392505050565b80516001600160a01b03811681146200028557600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60005b83811015620002bd578181015183820152602001620002a3565b50506000910152565b600082601f830112620002d857600080fd5b81516001600160401b0380821115620002f557620002f56200028a565b604051601f8301601f19908116603f011681019082821181831017156200032057620003206200028a565b816040528381528660208588010111156200033a57600080fd5b6200034d846020830160208901620002a0565b9695505050505050565b60008060008060008060c087890312156200037157600080fd5b6200037c876200026d565b60208801519096506001600160401b03808211156200039a57600080fd5b620003a88a838b01620002c6565b96506040890151915080821115620003bf57600080fd5b620003cd8a838b01620002c6565b95506060890151915080821115620003e457600080fd5b620003f28a838b01620002c6565b945060808901519150808211156200040957600080fd5b620004178a838b01620002c6565b935060a08901519150808211156200042e57600080fd5b506200043d89828a01620002c6565b9150509295509295509295565b600181811c908216806200045f57607f821691505b6020821081036200048057634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115620004d6576000816000526020600020601f850160051c81016020861015620004b15750805b601f850160051c820191505b81811015620004d257828155600101620004bd565b5050505b505050565b81516001600160401b03811115620004f757620004f76200028a565b6200050f816200050884546200044a565b8462000486565b602080601f8311600181146200054757600084156200052e5750858301515b600019600386901b1c1916600185901b178555620004d2565b600085815260208120601f198616915b82811015620005785788860151825594840194600190910190840162000557565b5085821015620005975787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6020815260008251806020840152620005c8816040850160208701620002a0565b601f01601f19169190910160400192915050565b80516020808301519190811015620004805760001960209190910360031b1b16919050565b60805160a05160c05160e05161010051610120516101405161129e6200065c6000396000610a8801526000610a5b01526000610918015260006108f00152600061084b015260006108750152600061089f015261129e6000f3fe608060405234801561001057600080fd5b50600436106101735760003560e01c8063715018a6116100de578063a76b4d5611610097578063dc9716eb11610071578063dc9716eb146102f8578063dd62ed3e14610300578063e8a3d48514610339578063f2fde38b1461034157600080fd5b8063a76b4d56146102ca578063a9059cbb146102d2578063d505accf146102e557600080fd5b8063715018a61461025e57806379cc6790146102665780637ecebe001461027957806384b0196e1461028c5780638da5cb5b146102a757806395d89b41146102c257600080fd5b8063313ce56711610130578063313ce567146101ee5780633644e515146101fd5780633fd4d4a81461020557806340c10f191461020d57806342966c681461022257806370a082311461023557600080fd5b806306fdde0314610178578063095ea7b3146101965780630cd9acb7146101b9578063120a88ad146101c157806318160ddd146101c957806323b872dd146101db575b600080fd5b610180610354565b60405161018d9190610fe8565b60405180910390f35b6101a96101a436600461101e565b6103e6565b604051901515815260200161018d565b610180610400565b61018061048e565b6002545b60405190815260200161018d565b6101a96101e9366004611048565b61049d565b6040516012815260200161018d565b6101cd6104c1565b6101806104d0565b61022061021b36600461101e565b6104df565b005b610220610230366004611084565b6104f5565b6101cd61024336600461109d565b6001600160a01b031660009081526020819052604090205490565b610220610502565b61022061027436600461101e565b610516565b6101cd61028736600461109d565b61052b565b610294610549565b60405161018d97969594939291906110b8565b6005546040516001600160a01b03909116815260200161018d565b61018061058f565b61018061059e565b6101a96102e036600461101e565b6105ab565b6102206102f3366004611151565b6105b9565b6101806106f8565b6101cd61030e3660046111c4565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b610180610705565b61022061034f36600461109d565b610714565b606060038054610363906111f7565b80601f016020809104026020016040519081016040528092919081815260200182805461038f906111f7565b80156103dc5780601f106103b1576101008083540402835291602001916103dc565b820191906000526020600020905b8154815290600101906020018083116103bf57829003601f168201915b5050505050905090565b6000336103f481858561074f565b60019150505b92915050565b6009805461040d906111f7565b80601f0160208091040260200160405190810160405280929190818152602001828054610439906111f7565b80156104865780601f1061045b57610100808354040283529160200191610486565b820191906000526020600020905b81548152906001019060200180831161046957829003601f168201915b505050505081565b606060098054610363906111f7565b6000336104ab858285610761565b6104b68585856107df565b506001949350505050565b60006104cb61083e565b905090565b6060600a8054610363906111f7565b6104e7610969565b6104f18282610996565b5050565b6104ff33826109cc565b50565b61050a610969565b6105146000610a02565b565b610521823383610761565b6104f182826109cc565b6001600160a01b0381166000908152600860205260408120546103fa565b60006060806000806000606061055d610a54565b610565610a81565b60408051600080825260208201909252600f60f81b9b939a50919850469750309650945092509050565b606060048054610363906111f7565b600b805461040d906111f7565b6000336103f48185856107df565b834211156105e25760405163313c898160e11b8152600481018590526024015b60405180910390fd5b60007f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c988888861062f8c6001600160a01b0316600090815260086020526040902080546001810190915590565b6040805160208101969096526001600160a01b0394851690860152929091166060840152608083015260a082015260c0810186905260e001604051602081830303815290604052805190602001209050600061068a82610aae565b9050600061069a82878787610adb565b9050896001600160a01b0316816001600160a01b0316146106e1576040516325c0072360e11b81526001600160a01b0380831660048301528b1660248201526044016105d9565b6106ec8a8a8a61074f565b50505050505050505050565b600a805461040d906111f7565b6060600b8054610363906111f7565b61071c610969565b6001600160a01b03811661074657604051631e4fbdf760e01b8152600060048201526024016105d9565b6104ff81610a02565b61075c8383836001610b09565b505050565b6001600160a01b0383811660009081526001602090815260408083209386168352929052205460001981146107d957818110156107ca57604051637dc7a0d960e11b81526001600160a01b038416600482015260248101829052604481018390526064016105d9565b6107d984848484036000610b09565b50505050565b6001600160a01b03831661080957604051634b637e8f60e11b8152600060048201526024016105d9565b6001600160a01b0382166108335760405163ec442f0560e01b8152600060048201526024016105d9565b61075c838383610bde565b6000306001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614801561089757507f000000000000000000000000000000000000000000000000000000000000000046145b156108c157507f000000000000000000000000000000000000000000000000000000000000000090565b6104cb604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201527f0000000000000000000000000000000000000000000000000000000000000000918101919091527f000000000000000000000000000000000000000000000000000000000000000060608201524660808201523060a082015260009060c00160405160208183030381529060405280519060200120905090565b6005546001600160a01b031633146105145760405163118cdaa760e01b81523360048201526024016105d9565b6001600160a01b0382166109c05760405163ec442f0560e01b8152600060048201526024016105d9565b6104f160008383610bde565b6001600160a01b0382166109f657604051634b637e8f60e11b8152600060048201526024016105d9565b6104f182600083610bde565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b60606104cb7f00000000000000000000000000000000000000000000000000000000000000006006610d08565b60606104cb7f00000000000000000000000000000000000000000000000000000000000000006007610d08565b60006103fa610abb61083e565b8360405161190160f01b8152600281019290925260228201526042902090565b600080600080610aed88888888610db3565b925092509250610afd8282610e82565b50909695505050505050565b6001600160a01b038416610b335760405163e602df0560e01b8152600060048201526024016105d9565b6001600160a01b038316610b5d57604051634a1406b160e11b8152600060048201526024016105d9565b6001600160a01b03808516600090815260016020908152604080832093871683529290522082905580156107d957826001600160a01b0316846001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92584604051610bd091815260200190565b60405180910390a350505050565b6001600160a01b038316610c09578060026000828254610bfe9190611231565b90915550610c7b9050565b6001600160a01b03831660009081526020819052604090205481811015610c5c5760405163391434e360e21b81526001600160a01b038516600482015260248101829052604481018390526064016105d9565b6001600160a01b03841660009081526020819052604090209082900390555b6001600160a01b038216610c9757600280548290039055610cb6565b6001600160a01b03821660009081526020819052604090208054820190555b816001600160a01b0316836001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef83604051610cfb91815260200190565b60405180910390a3505050565b606060ff8314610d2257610d1b83610f3b565b90506103fa565b818054610d2e906111f7565b80601f0160208091040260200160405190810160405280929190818152602001828054610d5a906111f7565b8015610da75780601f10610d7c57610100808354040283529160200191610da7565b820191906000526020600020905b815481529060010190602001808311610d8a57829003601f168201915b505050505090506103fa565b600080807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0841115610dee5750600091506003905082610e78565b604080516000808252602082018084528a905260ff891692820192909252606081018790526080810186905260019060a0016020604051602081039080840390855afa158015610e42573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116610e6e57506000925060019150829050610e78565b9250600091508190505b9450945094915050565b6000826003811115610e9657610e96611252565b03610e9f575050565b6001826003811115610eb357610eb3611252565b03610ed15760405163f645eedf60e01b815260040160405180910390fd5b6002826003811115610ee557610ee5611252565b03610f065760405163fce698f760e01b8152600481018290526024016105d9565b6003826003811115610f1a57610f1a611252565b036104f1576040516335e2f38360e21b8152600481018290526024016105d9565b60606000610f4883610f7a565b604080516020808252818301909252919250600091906020820181803683375050509182525060208101929092525090565b600060ff8216601f8111156103fa57604051632cd44ac360e21b815260040160405180910390fd5b6000815180845260005b81811015610fc857602081850181015186830182015201610fac565b506000602082860101526020601f19601f83011685010191505092915050565b602081526000610ffb6020830184610fa2565b9392505050565b80356001600160a01b038116811461101957600080fd5b919050565b6000806040838503121561103157600080fd5b61103a83611002565b946020939093013593505050565b60008060006060848603121561105d57600080fd5b61106684611002565b925061107460208501611002565b9150604084013590509250925092565b60006020828403121561109657600080fd5b5035919050565b6000602082840312156110af57600080fd5b610ffb82611002565b60ff60f81b881681526000602060e060208401526110d960e084018a610fa2565b83810360408501526110eb818a610fa2565b606085018990526001600160a01b038816608086015260a0850187905284810360c08601528551808252602080880193509091019060005b8181101561113f57835183529284019291840191600101611123565b50909c9b505050505050505050505050565b600080600080600080600060e0888a03121561116c57600080fd5b61117588611002565b965061118360208901611002565b95506040880135945060608801359350608088013560ff811681146111a757600080fd5b9699959850939692959460a0840135945060c09093013592915050565b600080604083850312156111d757600080fd5b6111e083611002565b91506111ee60208401611002565b90509250929050565b600181811c9082168061120b57607f821691505b60208210810361122b57634e487b7160e01b600052602260045260246000fd5b50919050565b808201808211156103fa57634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052602160045260246000fdfea26469706673582212200fea5736ecebd6f4f71e77a0743e7169bb21209a84517a64d4e0a6b0313817b864736f6c6343000817003360806040523480156200001157600080fd5b5060405162001eb738038062001eb7833981016040819052620000349162000202565b858585600062000045838262000386565b50600162000054828262000386565b5050506001600160a01b0381166200008657604051631e4fbdf760e01b81526000600482015260240160405180910390fd5b6200009181620000cb565b50600c620000a0848262000386565b50600d620000af838262000386565b50600e620000be828262000386565b5050505050505062000452565b600b80546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b80516001600160a01b03811681146200013557600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126200016257600080fd5b81516001600160401b03808211156200017f576200017f6200013a565b604051601f8301601f19908116603f01168101908282118183101715620001aa57620001aa6200013a565b8160405283815260209250866020858801011115620001c857600080fd5b600091505b83821015620001ec5785820183015181830184015290820190620001cd565b6000602085830101528094505050505092915050565b60008060008060008060c087890312156200021c57600080fd5b62000227876200011d565b60208801519096506001600160401b03808211156200024557600080fd5b620002538a838b0162000150565b965060408901519150808211156200026a57600080fd5b620002788a838b0162000150565b955060608901519150808211156200028f57600080fd5b6200029d8a838b0162000150565b94506080890151915080821115620002b457600080fd5b620002c28a838b0162000150565b935060a0890151915080821115620002d957600080fd5b50620002e889828a0162000150565b9150509295509295509295565b600181811c908216806200030a57607f821691505b6020821081036200032b57634e487b7160e01b600052602260045260246000fd5b50919050565b601f82111562000381576000816000526020600020601f850160051c810160208610156200035c5750805b601f850160051c820191505b818110156200037d5782815560010162000368565b5050505b505050565b81516001600160401b03811115620003a257620003a26200013a565b620003ba81620003b38454620002f5565b8462000331565b602080601f831160018114620003f25760008415620003d95750858301515b600019600386901b1c1916600185901b1785556200037d565b600085815260208120601f198616915b82811015620004235788860151825594840194600190910190840162000402565b5085821015620004425787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b611a5580620004626000396000f3fe608060405234801561001057600080fd5b50600436106101cf5760003560e01c806370a0823111610104578063a76b4d56116100a2578063cd279c7c11610071578063cd279c7c146103a8578063e8a3d485146103bb578063e985e9c5146103c3578063f2fde38b146103d657600080fd5b8063a76b4d5614610372578063b49bbd941461037a578063b88d4fde14610382578063c87b56dd1461039557600080fd5b806394e29329116100de57806394e293291461034757806395d89b411461034f578063a159047b14610357578063a22cb4651461035f57600080fd5b806370a082311461031b578063715018a61461032e5780638da5cb5b1461033657600080fd5b80632f745c59116101715780634f558e791161014b5780634f558e79146102c25780634f6ccce7146102ed5780635e0a9661146103005780636352211e1461030857600080fd5b80632f745c591461028957806342842e0e1461029c57806342966c68146102af57600080fd5b8063095ea7b3116101ad578063095ea7b31461023c57806318160ddd1461025157806318e97fd11461026357806323b872dd1461027657600080fd5b806301ffc9a7146101d457806306fdde03146101fc578063081812fc14610211575b600080fd5b6101e76101e2366004611494565b6103e9565b60405190151581526020015b60405180910390f35b6102046103fa565b6040516101f39190611501565b61022461021f366004611514565b61048c565b6040516001600160a01b0390911681526020016101f3565b61024f61024a366004611549565b6104b5565b005b6009545b6040519081526020016101f3565b61024f61027136600461161f565b6104c4565b61024f610284366004611666565b6104d6565b610255610297366004611549565b610566565b61024f6102aa366004611666565b6105cb565b61024f6102bd366004611514565b6105eb565b6101e76102d0366004611514565b6000908152600260205260409020546001600160a01b0316151590565b6102556102fb366004611514565b6105f7565b610204610650565b610224610316366004611514565b61065f565b6102556103293660046116a2565b61066a565b61024f6106b2565b600b546001600160a01b0316610224565b6102046106c6565b6102046106d5565b6102046106e4565b61024f61036d3660046116bd565b610772565b61020461077d565b61020461078a565b61024f6103903660046116f9565b610797565b6102046103a3366004611514565b6107ae565b61024f6103b6366004611775565b6107b9565b6102046107d5565b6101e76103d13660046117cc565b6107e4565b61024f6103e43660046116a2565b610812565b60006103f482610850565b92915050565b606060008054610409906117ff565b80601f0160208091040260200160405190810160405280929190818152602001828054610435906117ff565b80156104825780601f1061045757610100808354040283529160200191610482565b820191906000526020600020905b81548152906001019060200180831161046557829003601f168201915b5050505050905090565b600061049782610875565b506000828152600460205260409020546001600160a01b03166103f4565b6104c08282336108ae565b5050565b6104cc6108bb565b6104c082826108e8565b6001600160a01b03821661050557604051633250574960e11b8152600060048201526024015b60405180910390fd5b6000610512838333610938565b9050836001600160a01b0316816001600160a01b031614610560576040516364283d7b60e01b81526001600160a01b03808616600483015260248201849052821660448201526064016104fc565b50505050565b60006105718361066a565b82106105a25760405163295f44f760e21b81526001600160a01b0384166004820152602481018390526044016104fc565b506001600160a01b03919091166000908152600760209081526040808320938352929052205490565b6105e683838360405180602001604052806000815250610797565b505050565b6104c060008233610938565b600061060260095490565b821061062b5760405163295f44f760e21b815260006004820152602481018390526044016104fc565b6009828154811061063e5761063e611839565b90600052602060002001549050919050565b6060600d8054610409906117ff565b60006103f482610875565b60006001600160a01b038216610696576040516322718ad960e21b8152600060048201526024016104fc565b506001600160a01b031660009081526003602052604090205490565b6106ba6108bb565b6106c4600061094d565b565b6060600c8054610409906117ff565b606060018054610409906117ff565b600d80546106f1906117ff565b80601f016020809104026020016040519081016040528092919081815260200182805461071d906117ff565b801561076a5780601f1061073f5761010080835404028352916020019161076a565b820191906000526020600020905b81548152906001019060200180831161074d57829003601f168201915b505050505081565b6104c033838361099f565b600e80546106f1906117ff565b600c80546106f1906117ff565b6107a28484846104d6565b61056084848484610a3e565b60606103f482610b67565b6107c16108bb565b6107cb8383610c70565b6105e682826108e8565b6060600e8054610409906117ff565b6001600160a01b03918216600090815260056020908152604080832093909416825291909152205460ff1690565b61081a6108bb565b6001600160a01b03811661084457604051631e4fbdf760e01b8152600060048201526024016104fc565b61084d8161094d565b50565b60006001600160e01b0319821663780e9d6360e01b14806103f457506103f482610c8a565b6000818152600260205260408120546001600160a01b0316806103f457604051637e27328960e01b8152600481018490526024016104fc565b6105e68383836001610caf565b600b546001600160a01b031633146106c45760405163118cdaa760e01b81523360048201526024016104fc565b6000828152600660205260409020610900828261189f565b506040518281527ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79060200160405180910390a15050565b6000610945848484610db5565b949350505050565b600b80546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6001600160a01b0382166109d157604051630b61174360e31b81526001600160a01b03831660048201526024016104fc565b6001600160a01b03838116600081815260056020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b6001600160a01b0383163b1561056057604051630a85bd0160e11b81526001600160a01b0384169063150b7a0290610a8090339088908790879060040161195f565b6020604051808303816000875af1925050508015610abb575060408051601f3d908101601f19168201909252610ab89181019061199c565b60015b610b24573d808015610ae9576040519150601f19603f3d011682016040523d82523d6000602084013e610aee565b606091505b508051600003610b1c57604051633250574960e11b81526001600160a01b03851660048201526024016104fc565b805181602001fd5b6001600160e01b03198116630a85bd0160e11b14610b6057604051633250574960e11b81526001600160a01b03851660048201526024016104fc565b5050505050565b6060610b7282610875565b5060008281526006602052604081208054610b8c906117ff565b80601f0160208091040260200160405190810160405280929190818152602001828054610bb8906117ff565b8015610c055780601f10610bda57610100808354040283529160200191610c05565b820191906000526020600020905b815481529060010190602001808311610be857829003601f168201915b505050505090506000610c2360408051602081019091526000815290565b90508051600003610c35575092915050565b815115610c67578082604051602001610c4f9291906119b9565b60405160208183030381529060405292505050919050565b61094584610e82565b6104c0828260405180602001604052806000815250610ef7565b60006001600160e01b03198216632483248360e11b14806103f457506103f482610f0e565b8080610cc357506001600160a01b03821615155b15610d85576000610cd384610875565b90506001600160a01b03831615801590610cff5750826001600160a01b0316816001600160a01b031614155b8015610d125750610d1081846107e4565b155b15610d3b5760405163a9fbf51f60e01b81526001600160a01b03841660048201526024016104fc565b8115610d835783856001600160a01b0316826001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45b505b5050600090815260046020526040902080546001600160a01b0319166001600160a01b0392909216919091179055565b600080610dc3858585610f5e565b90506001600160a01b038116610e2057610e1b84600980546000838152600a60205260408120829055600182018355919091527f6e1540171b6c0c960b71a7020d9f60077f6af931a8bbf590da0223dacf75c7af0155565b610e43565b846001600160a01b0316816001600160a01b031614610e4357610e438185611057565b6001600160a01b038516610e5f57610e5a846110e8565b610945565b846001600160a01b0316816001600160a01b031614610945576109458585611197565b6060610e8d82610875565b506000610ea560408051602081019091526000815290565b90506000815111610ec55760405180602001604052806000815250610ef0565b80610ecf846111e7565b604051602001610ee09291906119b9565b6040516020818303038152906040525b9392505050565b610f01838361127a565b6105e66000848484610a3e565b60006001600160e01b031982166380ac58cd60e01b1480610f3f57506001600160e01b03198216635b5e139f60e01b145b806103f457506301ffc9a760e01b6001600160e01b03198316146103f4565b6000828152600260205260408120546001600160a01b0390811690831615610f8b57610f8b8184866112df565b6001600160a01b03811615610fc957610fa8600085600080610caf565b6001600160a01b038116600090815260036020526040902080546000190190555b6001600160a01b03851615610ff8576001600160a01b0385166000908152600360205260409020805460010190555b60008481526002602052604080822080546001600160a01b0319166001600160a01b0389811691821790925591518793918516917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4949350505050565b60006110628361066a565b6000838152600860205260409020549091508082146110b5576001600160a01b03841660009081526007602090815260408083208584528252808320548484528184208190558352600890915290208190555b5060009182526008602090815260408084208490556001600160a01b039094168352600781528383209183525290812055565b6009546000906110fa906001906119e8565b6000838152600a60205260408120546009805493945090928490811061112257611122611839565b90600052602060002001549050806009838154811061114357611143611839565b6000918252602080832090910192909255828152600a9091526040808220849055858252812055600980548061117b5761117b611a09565b6001900381819060005260206000200160009055905550505050565b600060016111a48461066a565b6111ae91906119e8565b6001600160a01b039093166000908152600760209081526040808320868452825280832085905593825260089052919091209190915550565b606060006111f483611343565b600101905060008167ffffffffffffffff81111561121457611214611573565b6040519080825280601f01601f19166020018201604052801561123e576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a850494508461124857509392505050565b6001600160a01b0382166112a457604051633250574960e11b8152600060048201526024016104fc565b60006112b283836000610938565b90506001600160a01b038116156105e6576040516339e3563760e11b8152600060048201526024016104fc565b6112ea83838361141b565b6105e6576001600160a01b03831661131857604051637e27328960e01b8152600481018290526024016104fc565b60405163177e802f60e01b81526001600160a01b0383166004820152602481018290526044016104fc565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b83106113825772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef810000000083106113ae576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc1000083106113cc57662386f26fc10000830492506010015b6305f5e10083106113e4576305f5e100830492506008015b61271083106113f857612710830492506004015b6064831061140a576064830492506002015b600a83106103f45760010192915050565b60006001600160a01b038316158015906109455750826001600160a01b0316846001600160a01b03161480611455575061145584846107e4565b806109455750506000908152600460205260409020546001600160a01b03908116911614919050565b6001600160e01b03198116811461084d57600080fd5b6000602082840312156114a657600080fd5b8135610ef08161147e565b60005b838110156114cc5781810151838201526020016114b4565b50506000910152565b600081518084526114ed8160208601602086016114b1565b601f01601f19169290920160200192915050565b602081526000610ef060208301846114d5565b60006020828403121561152657600080fd5b5035919050565b80356001600160a01b038116811461154457600080fd5b919050565b6000806040838503121561155c57600080fd5b6115658361152d565b946020939093013593505050565b634e487b7160e01b600052604160045260246000fd5b600067ffffffffffffffff808411156115a4576115a4611573565b604051601f8501601f19908116603f011681019082821181831017156115cc576115cc611573565b816040528093508581528686860111156115e557600080fd5b858560208301376000602087830101525050509392505050565b600082601f83011261161057600080fd5b610ef083833560208501611589565b6000806040838503121561163257600080fd5b82359150602083013567ffffffffffffffff81111561165057600080fd5b61165c858286016115ff565b9150509250929050565b60008060006060848603121561167b57600080fd5b6116848461152d565b92506116926020850161152d565b9150604084013590509250925092565b6000602082840312156116b457600080fd5b610ef08261152d565b600080604083850312156116d057600080fd5b6116d98361152d565b9150602083013580151581146116ee57600080fd5b809150509250929050565b6000806000806080858703121561170f57600080fd5b6117188561152d565b93506117266020860161152d565b925060408501359150606085013567ffffffffffffffff81111561174957600080fd5b8501601f8101871361175a57600080fd5b61176987823560208401611589565b91505092959194509250565b60008060006060848603121561178a57600080fd5b6117938461152d565b925060208401359150604084013567ffffffffffffffff8111156117b657600080fd5b6117c2868287016115ff565b9150509250925092565b600080604083850312156117df57600080fd5b6117e88361152d565b91506117f66020840161152d565b90509250929050565b600181811c9082168061181357607f821691505b60208210810361183357634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052603260045260246000fd5b601f8211156105e6576000816000526020600020601f850160051c810160208610156118785750805b601f850160051c820191505b8181101561189757828155600101611884565b505050505050565b815167ffffffffffffffff8111156118b9576118b9611573565b6118cd816118c784546117ff565b8461184f565b602080601f83116001811461190257600084156118ea5750858301515b600019600386901b1c1916600185901b178555611897565b600085815260208120601f198616915b8281101561193157888601518255948401946001909101908401611912565b508582101561194f5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6001600160a01b0385811682528416602082015260408101839052608060608201819052600090611992908301846114d5565b9695505050505050565b6000602082840312156119ae57600080fd5b8151610ef08161147e565b600083516119cb8184602088016114b1565b8351908301906119df8183602088016114b1565b01949350505050565b818103818111156103f457634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052603160045260246000fdfea26469706673582212206ff38700c73b602455dbb7964f2d3281f62efc77263f0f3bdb67f5e4ee5d4f3f64736f6c63430008170033a2646970667358221220d058cf8dfb17169ff3320b4ba2cb9665d5f875cda19c5c22351f341d783cad4064736f6c63430008170033" } ] \ No newline at end of file diff --git a/cadence/contracts/bridge/CrossVMNFT.cdc b/cadence/contracts/bridge/CrossVMNFT.cdc index 3ff37797..c153ed19 100644 --- a/cadence/contracts/bridge/CrossVMNFT.cdc +++ b/cadence/contracts/bridge/CrossVMNFT.cdc @@ -4,27 +4,22 @@ import "MetadataViews" import "EVM" -/// Contract defining cross-VM NFT & Collection interfaces +/// Contract defining cross-VM NFT-related interfaces & Metadata views /// -access(all) -contract CrossVMNFT { +access(all) contract CrossVMNFT { /// A struct to represent a general case URI, used to represent the URI of the NFT where the type of URI is not /// able to be determined (i.e. HTTP, IPFS, etc.) /// - access(all) - struct URI : MetadataViews.File { + access(all) struct URI : MetadataViews.File { /// The base URI prefix, if any. Not needed for all URIs, but helpful for some use cases /// For example, updating a whole NFT collection's image host easily - access(all) - let baseURI: String? + access(all) let baseURI: String? /// The URI value /// NOTE: this is set on init as a concatenation of the baseURI and the value if baseURI != nil - access(self) - let value: String + access(self) let value: String - access(all) - view fun uri(): String { + access(all) view fun uri(): String { return self.value } @@ -36,19 +31,15 @@ contract CrossVMNFT { /// Proof of concept metadata to represent the ERC721 values of the NFT /// - access(all) - struct EVMBridgedMetadata { + access(all) struct EVMBridgedMetadata { /// The name of the NFT - access(all) - let name: String + access(all) let name: String /// The symbol of the NFT - access(all) - let symbol: String - /// The URI of the NFT - this can either be contract-level or token-level URI depending on where the metadata + access(all) let symbol: String + /// The URI of the asset - this can either be contract-level or token-level URI depending on where the metadata /// is requested. See the ViewResolver contract interface to discover how contract & resource-level metadata /// requests are handled. - access(all) - let uri: {MetadataViews.File} + access(all) let uri: {MetadataViews.File} init(name: String, symbol: String, uri: {MetadataViews.File}) { self.name = name @@ -65,38 +56,29 @@ contract CrossVMNFT { /// See discussion https://github.com/onflow/flow-nft/pull/126#discussion_r1462612559 where @austinkline raised /// differentiating IDs in a minimal interface incorporated into the one below /// - access(all) - resource interface EVMNFT : NonFungibleToken.NFT { - access(all) - let evmID: UInt256 - access(all) - let name: String - access(all) - let symbol: String - access(all) - view fun tokenURI(): String - access(all) - view fun getEVMContractAddress(): EVM.EVMAddress + access(all) resource interface EVMNFT : NonFungibleToken.NFT { + access(all) let evmID: UInt256 + + access(all) view fun getName(): String + access(all) view fun getSymbol(): String + access(all) view fun tokenURI(): String + access(all) view fun getEVMContractAddress(): EVM.EVMAddress } /// A simple interface for a collection of EVMNFTs /// - access(all) - resource interface EVMNFTCollection { - access(all) - view fun getEVMIDs(): [UInt256] - access(all) - view fun getCadenceID(from evmID: UInt256): UInt64? - access(all) - view fun getEVMID(from cadenceID: UInt64): UInt256? - access(all) - view fun contractURI(): String? + access(all) resource interface EVMNFTCollection : NonFungibleToken.Collection { + access(all) view fun getName(): String + access(all) view fun getSymbol(): String + access(all) view fun getEVMIDs(): [UInt256] + access(all) view fun getCadenceID(from evmID: UInt256): UInt64? + access(all) view fun getEVMID(from cadenceID: UInt64): UInt256? + access(all) fun contractURI(): String? } /// Retrieves the EVM ID of an NFT if it implements the EVMNFT interface, returning nil if not /// - access(all) - view fun getEVMID(from token: &{NonFungibleToken.NFT}): UInt256? { + access(all) view fun getEVMID(from token: &{NonFungibleToken.NFT}): UInt256? { if let evmNFT = token as? &{EVMNFT} { return evmNFT.evmID } diff --git a/cadence/contracts/bridge/CrossVMToken.cdc b/cadence/contracts/bridge/CrossVMToken.cdc new file mode 100644 index 00000000..62b3c9ad --- /dev/null +++ b/cadence/contracts/bridge/CrossVMToken.cdc @@ -0,0 +1,20 @@ +import "FungibleToken" + +import "EVM" + +/// Contract defining cross-VM Fungible Token Vault interface +/// +access(all) contract CrossVMToken { + + /// Interface for a Fungible Token Vault with a corresponding ERC20 contract on EVM + access(all) resource interface EVMTokenInfo { + /// Gets the ERC20 name value + access(all) view fun getName(): String + /// Gets the ERC20 symbol value + access(all) view fun getSymbol(): String + /// Gets the ERC20 decimals value + access(all) view fun getDecimals(): UInt8 + /// Get the EVM contract address of the corresponding ERC20 contract address + access(all) view fun getEVMContractAddress(): EVM.EVMAddress + } +} diff --git a/cadence/contracts/bridge/EVMBridgeRouter.cdc b/cadence/contracts/bridge/EVMBridgeRouter.cdc deleted file mode 100644 index 0260f5e0..00000000 --- a/cadence/contracts/bridge/EVMBridgeRouter.cdc +++ /dev/null @@ -1,120 +0,0 @@ -import "NonFungibleToken" -import "FungibleToken" -import "FlowToken" - -import "EVM" - -import "IFlowEVMNFTBridge" - -/// This contract defines a mechanism for routing bridge requests from the EVM contract to the Flow-EVM bridge as well -/// as updating the designated bridge address -/// -access(all) -contract EVMBridgeRouter { - - /// Entitlement allowing for updates to the Router - access(all) entitlement RouterAdmin - - /// Emitted if/when the bridge contract the router directs to is updated - access(all) event BridgeContractUpdated(address: Address, name: String) - - /// BridgeAccessor implementation used by the EVM contract to route bridge calls between VMs - /// - access(all) - resource Router : EVM.BridgeAccessor { - /// Address of the bridge contract - access(all) var bridgeAddress: Address - /// Name of the bridge contract - access(all) var bridgeContractName: String - - init(address: Address, name: String) { - self.bridgeAddress = address - self.bridgeContractName = name - } - - /// Passes along the bridge request to dedicated bridge contract - /// - /// @param nft: The NFT to be bridged to EVM - /// @param to: The address of the EVM account to receive the bridged NFT - /// @param feeProvider: A reference to a FungibleToken Provider from which the bridging fee is withdrawn in $FLOW - /// - access(EVM.Bridge) - fun depositNFT( - nft: @{NonFungibleToken.NFT}, - to: EVM.EVMAddress, - feeProvider: auth(FungibleToken.Withdraw) &{FungibleToken.Provider} - ) { - self.borrowBridge().bridgeNFTToEVM(token: <-nft, to: to, feeProvider: feeProvider) - } - - /// Passes along the bridge request to the dedicated bridge contract, returning the bridged NFT - /// - /// @param caller: A reference to the COA which currently owns the NFT in EVM - /// @param type: The Cadence type of the NFT to be bridged from EVM - /// @param id: The ID of the NFT to be bridged from EVM - /// @param feeProvider: A reference to a FungibleToken Provider from which the bridging fee is withdrawn in $FLOW - /// - /// @return The bridged NFT - /// - access(EVM.Bridge) - fun withdrawNFT( - caller: auth(EVM.Call) &EVM.CadenceOwnedAccount, - type: Type, - id: UInt256, - feeProvider: auth(FungibleToken.Withdraw) &{FungibleToken.Provider} - ): @{NonFungibleToken.NFT} { - let bridge = self.borrowBridge() - // Define a callback function, enabling the bridge to act on the ephemeral COA reference in scope - var executed = false - fun callback(): EVM.Result { - pre { - !executed: "Callback can only be executed once" - } - post { - executed: "Callback must be executed" - } - executed = true - return caller.call( - to: bridge.getAssociatedEVMAddress(with: type) - ?? panic("No EVM address associated with type"), - data: EVM.encodeABIWithSignature( - "safeTransferFrom(address,address,uint256)", - [caller.address(), bridge.getBridgeCOAEVMAddress(), id] - ), - gasLimit: 15000000, - value: EVM.Balance(attoflow: 0) - ) - } - // Execute the bridge request - return <- bridge.bridgeNFTFromEVM( - owner: caller.address(), - type: type, - id: id, - feeProvider: feeProvider, - protectedTransferCall: callback - ) - } - - /// Sets the bridge contract the router directs bridge requests through - /// - access(RouterAdmin) fun setBridgeContract(address: Address, name: String) { - self.bridgeAddress = address - self.bridgeContractName = name - emit BridgeContractUpdated(address: address, name: name) - } - - /// Returns a reference to the bridge contract - /// - access(self) fun borrowBridge(): &{IFlowEVMNFTBridge} { - return getAccount(self.bridgeAddress).contracts.borrow<&{IFlowEVMNFTBridge}>(name: self.bridgeContractName) - ?? panic("Bridge contract not found") - } - } - - init(bridgeAddress: Address, bridgeContractName: String) { - self.account.storage.save( - <-create Router(address: bridgeAddress, name: bridgeContractName), - to: /storage/evmBridgeRouter - ) - } -} diff --git a/cadence/contracts/bridge/FlowEVMBridge.cdc b/cadence/contracts/bridge/FlowEVMBridge.cdc index 51c5d7ca..a8c1071d 100644 --- a/cadence/contracts/bridge/FlowEVMBridge.cdc +++ b/cadence/contracts/bridge/FlowEVMBridge.cdc @@ -1,4 +1,6 @@ +import "Burner" import "FungibleToken" +import "FungibleTokenMetadataViews" import "NonFungibleToken" import "MetadataViews" import "ViewResolver" @@ -9,11 +11,15 @@ import "EVM" import "BridgePermissions" import "ICrossVM" import "IEVMBridgeNFTMinter" +import "IEVMBridgeTokenMinter" import "IFlowEVMNFTBridge" +import "IFlowEVMTokenBridge" import "CrossVMNFT" +import "CrossVMToken" import "FlowEVMBridgeConfig" import "FlowEVMBridgeUtils" import "FlowEVMBridgeNFTEscrow" +import "FlowEVMBridgeTokenEscrow" import "FlowEVMBridgeTemplates" import "SerializeNFT" @@ -27,7 +33,7 @@ import "SerializeNFT" /// - FLIP #237: https://github.com/onflow/flips/pull/233 /// access(all) -contract FlowEVMBridge : IFlowEVMNFTBridge { +contract FlowEVMBridge : IFlowEVMNFTBridge, IFlowEVMTokenBridge { /************* Events @@ -46,10 +52,37 @@ contract FlowEVMBridge : IFlowEVMNFTBridge { evmContractAddress: String ) + /**************** + Constructs + *****************/ + + /// Struct used to preserve and pass around multiple values preventing the need to make multiple EVM calls + /// during EVM asset onboarding + /// + access(all) struct EVMOnboardingValues { + access(all) let evmContractAddress: EVM.EVMAddress + access(all) let name: String + access(all) let symbol: String + access(all) let decimals: UInt8? + + init( + evmContractAddress: EVM.EVMAddress, + name: String, + symbol: String, + decimals: UInt8? + ) { + self.evmContractAddress = evmContractAddress + self.name = name + self.symbol = symbol + self.decimals = decimals + } + } + /************************** - Public NFT Handling + Public Onboarding **************************/ + /// Onboards a given asset by type to the bridge. Since we're onboarding by Cadence Type, the asset must be defined /// in a third-party contract. Attempting to onboard a bridge-defined asset will result in an error as the asset has /// already been onboarded to the bridge. @@ -60,6 +93,8 @@ contract FlowEVMBridge : IFlowEVMNFTBridge { access(all) fun onboardByType(_ type: Type, feeProvider: auth(FungibleToken.Withdraw) &{FungibleToken.Provider}) { pre { + type != Type<@FlowToken.Vault>(): + "$FLOW cannot be bridged via the VM bridge - use the CadenceOwnedAccount interface" feeProvider.isAvailableToWithdraw(amount: FlowEVMBridgeConfig.onboardFee): "Insufficient fee available via feeProvider" self.typeRequiresOnboarding(type) == true: "Onboarding is not needed for this type" @@ -74,14 +109,38 @@ contract FlowEVMBridge : IFlowEVMNFTBridge { let feeVault <-feeProvider.withdraw(amount: FlowEVMBridgeConfig.onboardFee) as! @FlowToken.Vault FlowEVMBridgeUtils.deposit(<-feeVault) // Deploy an EVM defining contract via the FlowBridgeFactory.sol contract - let erc721Address = self.deployEVMContract(forAssetType: type) + let onboardingValues = self.deployEVMContract(forAssetType: type) // Initialize bridge escrow for the asset - FlowEVMBridgeNFTEscrow.initializeEscrow(forType: type, erc721Address: erc721Address) + if type.isSubtype(of: Type<@{NonFungibleToken.NFT}>()) { + FlowEVMBridgeNFTEscrow.initializeEscrow( + forType: type, + name: onboardingValues.name, + symbol: onboardingValues.symbol, + erc721Address: onboardingValues.evmContractAddress + ) + } else if type.isSubtype(of: Type<@{FungibleToken.Vault}>()) { + let createVaultFunction = FlowEVMBridgeUtils.getCreateEmptyVaultFunction(forType: type) + ?? panic("Could not retrieve createEmptyVault function for the given type") + FlowEVMBridgeTokenEscrow.initializeEscrow( + with: <-createVaultFunction(type), + name: onboardingValues.name, + symbol: onboardingValues.symbol, + decimals: onboardingValues.decimals!, + evmTokenAddress: onboardingValues.evmContractAddress + ) + } else { + panic("Attempted to onboard unsupported type: ".concat(type.identifier)) + } + + assert( + FlowEVMBridgeNFTEscrow.isInitialized(forType: type) || FlowEVMBridgeTokenEscrow.isInitialized(forType: type), + message: "Failed to initialize escrow for given type" + ) emit Onboarded( type: type, cadenceContractAddress: FlowEVMBridgeUtils.getContractAddress(fromType: type)!, - evmContractAddress: FlowEVMBridgeUtils.getEVMAddressAsHexString(address: erc721Address) + evmContractAddress: FlowEVMBridgeUtils.getEVMAddressAsHexString(address: onboardingValues.evmContractAddress) ) } @@ -117,6 +176,10 @@ contract FlowEVMBridge : IFlowEVMNFTBridge { self.deployDefiningContract(evmContractAddress: address) } + /************************* + Public NFT Handling + **************************/ + /// Public entrypoint to bridge NFTs from Cadence to EVM. /// /// @param token: The NFT to be bridged @@ -236,7 +299,7 @@ contract FlowEVMBridge : IFlowEVMNFTBridge { /// /// @returns The bridged NFT /// - access(all) + access(account) fun bridgeNFTFromEVM( owner: EVM.EVMAddress, type: Type, @@ -306,7 +369,175 @@ contract FlowEVMBridge : IFlowEVMNFTBridge { /************************** Public FT Handling ***************************/ - // TODO + + /// Public entrypoint to bridge FTs from Cadence to EVM. + /// + /// @param vault: The fungible token Vault to be bridged + /// @param to: The fungible token recipient in EVM + /// @param feeProvider: A reference to a FungibleToken Provider from which the bridging fee is withdrawn in $FLOW + /// + access(all) + fun bridgeTokensToEVM( + vault: @{FungibleToken.Vault}, + to: EVM.EVMAddress, + feeProvider: auth(FungibleToken.Withdraw) &{FungibleToken.Provider} + ) { + pre { + !vault.isInstance(Type<@{NonFungibleToken.NFT}>()): "Mixed asset types are not yet supported" + self.typeRequiresOnboarding(vault.getType()) == false: "FT must first be onboarded" + } + let vaultType = vault.getType() + if vaultType == Type<@FlowToken.Vault>() { + let flowVault <-vault as! @FlowToken.Vault + to.deposit(from: <-flowVault) + return + } + + let vaultBalance = vault.balance + var feeAmount = 0.0 + + // Lock the tokens if the bridge does not define them + if FlowEVMBridgeUtils.isCadenceNative(type: vault.getType()) { + // Lock the FT balance & calculate the extra used by the FT if any + let storageUsed = FlowEVMBridgeTokenEscrow.lockTokens(<-vault) + // Calculate the bridge fee on current rates + feeAmount = FlowEVMBridgeUtils.calculateBridgeFee(used: storageUsed, includeBase: true) + } else { + Burner.burn(<-vault) + feeAmount = FlowEVMBridgeUtils.calculateBridgeFee(used: 0, includeBase: true) + } + + // Withdraw from feeProvider and deposit to self + assert( + feeProvider.isAvailableToWithdraw(amount: feeAmount), + message: "Fee provider does not have balance to cover the bridge fee of ".concat(feeAmount.toString()) + ) + let feeVault <-feeProvider.withdraw(amount: feeAmount) as! @FlowToken.Vault + FlowEVMBridgeUtils.deposit(<-feeVault) + + // Does the bridge control the EVM contract associated with this type? + let associatedAddress = FlowEVMBridgeConfig.getEVMAddressAssociated(with: vaultType) + ?? panic("No EVMAddress found for vault type") + // Convert the vault balance to a UInt256 + let decimals = FlowEVMBridgeUtils.getTokenDecimals(evmContractAddress: associatedAddress) + let bridgeAmount = FlowEVMBridgeUtils.ufix64ToUInt256(value: vaultBalance, decimals: decimals) + + let isFactoryDeployed = FlowEVMBridgeUtils.isEVMContractBridgeOwned(evmContractAddress: associatedAddress) + // Controlled by the bridge - mint or transfer based on the bridge's EVM contract authority + if isFactoryDeployed { + // Mint tokens to the recipient + let callResult: EVM.Result = FlowEVMBridgeUtils.call( + signature: "mint(address,uint256)", + targetEVMAddress: associatedAddress, + args: [to, bridgeAmount], + gasLimit: 15000000, + value: 0.0 + ) + assert(callResult.status == EVM.Status.successful, message: "Tranfer to bridge recipient failed") + } else { + // Not bridge-controlled, transfer existing ownership + let callResult: EVM.Result = FlowEVMBridgeUtils.call( + signature: "transfer(address,uint256)", + targetEVMAddress: associatedAddress, + args: [to, bridgeAmount], + gasLimit: 15000000, + value: 0.0 + ) + assert(callResult.status == EVM.Status.successful, message: "Tranfer to bridge recipient failed") + } + } + + /// Public entrypoint to bridge FTs from EVM to Cadence + /// + /// @param owner: The EVM address of the FT owner. Current ownership and successful transfer (via + /// `protectedTransferCall`) is validated before the bridge request is executed. + /// @param calldata: Caller-provided approve() call, enabling contract COA to operate on FT in EVM contract + /// @param amount: The amount of tokens to be bridged + /// @param evmContractAddress: Address of the EVM address defining the FT being bridged - also call target + /// @param feeProvider: A reference to a FungibleToken Provider from which the bridging fee is withdrawn in $FLOW + /// @param protectedTransferCall: A function that executes the transfer of the FT from the named owner to the + /// bridge's COA. This function is expected to return a Result indicating the status of the transfer call. + /// + /// @returns The bridged fungible token Vault + /// + access(account) + fun bridgeTokensFromEVM( + owner: EVM.EVMAddress, + type: Type, + amount: UInt256, + feeProvider: auth(FungibleToken.Withdraw) &{FungibleToken.Provider}, + protectedTransferCall: fun (): EVM.Result + ): @{FungibleToken.Vault} { + pre { + feeProvider.isAvailableToWithdraw(amount: FlowEVMBridgeUtils.calculateBridgeFee(used: 0, includeBase: true)): + "Insufficient fee paid" + !type.isSubtype(of: Type<@{NonFungibleToken.Collection}>()): "Mixed asset types are not yet supported" + !type.isInstance(Type<@FlowToken.Vault>()): "Must use the CadenceOwnedAccount interface to bridge $FLOW from EVM" + self.typeRequiresOnboarding(type) == false: "NFT must first be onboarded" + } + // Withdraw from feeProvider and deposit to self + let feeAmount = FlowEVMBridgeUtils.calculateBridgeFee(used: 0, includeBase: true) + let feeVault <-feeProvider.withdraw(amount: feeAmount) as! @FlowToken.Vault + FlowEVMBridgeUtils.deposit(<-feeVault) + + // Get the EVMAddress of the ERC20 contract associated with the type + let associatedAddress = FlowEVMBridgeConfig.getEVMAddressAssociated(with: type) + ?? panic("No EVMAddress found for token type") + + // Ensure the caller is has sufficient balance to bridge the requested amount + let hasSufficientBalance = FlowEVMBridgeUtils.hasSufficientBalance( + amount: amount, + owner: owner, + evmContractAddress: associatedAddress + ) + assert(hasSufficientBalance, message: "Caller does not have sufficient balance to bridge requested tokens") + + // Get the bridge COA's balance of the token before executing the protected transfer call + let bridgeBalanceBefore = FlowEVMBridgeUtils.balanceOf( + owner: self.getBridgeCOAEVMAddress(), + evmContractAddress: associatedAddress + ) + + // Execute the transfer from the calling owner to the bridge's COA, escrowing the tokens in EVM + let callResult = protectedTransferCall() + assert(callResult.status == EVM.Status.successful, message: "Transfer to bridge COA failed") + + // Get the bridge COA's balance of the token before executing the protected transfer call + let bridgeBalanceAfter = FlowEVMBridgeUtils.balanceOf( + owner: self.getBridgeCOAEVMAddress(), + evmContractAddress: associatedAddress + ) + assert( + bridgeBalanceAfter == bridgeBalanceBefore + amount, + message: "Transfer to bridge COA failed - cannot bridge FT without bridge escrow" + ) + + let definingAddress = FlowEVMBridgeUtils.getContractAddress(fromType: type)! + let definingContractName = FlowEVMBridgeUtils.getContractName(fromType: type)! + + let decimals = FlowEVMBridgeUtils.getTokenDecimals(evmContractAddress: associatedAddress) + let ufixAmount = FlowEVMBridgeUtils.uint256ToUFix64(value: amount, decimals: decimals) + // If the Cadence Vault is bridge-defined, mint the tokens + if definingAddress == self.account.address { + let minter = getAccount(definingAddress).contracts.borrow<&{IEVMBridgeTokenMinter}>(name: definingContractName)! + return <- minter.mintTokens(amount: ufixAmount) + } + // Otherwise, the bridge will need to unlock them from escrow + assert( + FlowEVMBridgeUtils.isEVMContractBridgeOwned(evmContractAddress: associatedAddress), + message: "Unexpected error bridging FT from EVM" + ) + // Burn the EVM tokens that have now been transferred to the bridge in EVM + let burnResult: EVM.Result = FlowEVMBridgeUtils.call( + signature: "burn(uint256)", + targetEVMAddress: associatedAddress, + args: [amount], + gasLimit: 15000000, + value: 0.0 + ) + assert(burnResult.status == EVM.Status.successful, message: "Burn of EVM tokens failed") + return <-FlowEVMBridgeTokenEscrow.unlockTokens(type: type, amount: ufixAmount) + } /************************** Public Getters @@ -347,9 +578,15 @@ contract FlowEVMBridge : IFlowEVMNFTBridge { /// access(all) view fun typeRequiresOnboarding(_ type: Type): Bool? { - if FlowEVMBridgeUtils.isValidFlowAsset(type: type) { - // TODO: FT validation + if !FlowEVMBridgeUtils.isValidFlowAsset(type: type) { + return nil + } + if type == Type<@FlowToken.Vault>() { + return false + } else if type.isSubtype(of: Type<@{NonFungibleToken.NFT}>()) { return !FlowEVMBridgeNFTEscrow.isInitialized(forType: type) + } else if type.isSubtype(of: Type<@{FungibleToken.Vault}>()) { + return !FlowEVMBridgeTokenEscrow.isInitialized(forType: type) } return nil } @@ -364,9 +601,11 @@ contract FlowEVMBridge : IFlowEVMNFTBridge { fun evmAddressRequiresOnboarding(_ address: EVM.EVMAddress): Bool? { // If the address was deployed by the bridge or a Cadence contract has been deployed to define the // corresponding NFT, it's already been onboarded - let cadenceContractName = FlowEVMBridgeUtils.deriveBridgedNFTContractName(from: address) + let nftContractName = FlowEVMBridgeUtils.deriveBridgedNFTContractName(from: address) + let tokenContractName = FlowEVMBridgeUtils.deriveBridgedTokenContractName(from: address) if FlowEVMBridgeUtils.isEVMContractBridgeOwned(evmContractAddress: address) || - self.account.contracts.get(name: cadenceContractName) != nil { + self.account.contracts.get(name: nftContractName) != nil || + self.account.contracts.get(name: tokenContractName) != nil { return false } // Dealing with EVM-native asset, check if it's NFT or FT exclusively @@ -387,12 +626,11 @@ contract FlowEVMBridge : IFlowEVMNFTBridge { /// @returns The EVMAddress of the deployed contract /// access(self) - fun deployEVMContract(forAssetType: Type): EVM.EVMAddress { + fun deployEVMContract(forAssetType: Type): EVMOnboardingValues { if forAssetType.isSubtype(of: Type<@{NonFungibleToken.NFT}>()) { return self.deployERC721(forAssetType) } else if forAssetType.isSubtype(of: Type<@{FungibleToken.Vault}>()) { - // TODO - // return self.deployERC20(name: forAssetType.identifier) + return self.deployERC20(forAssetType) } panic("Unsupported asset type: ".concat(forAssetType.identifier)) } @@ -404,7 +642,7 @@ contract FlowEVMBridge : IFlowEVMNFTBridge { /// @returns The EVMAddress of the deployed contract /// access(self) - fun deployERC721(_ forNFTType: Type): EVM.EVMAddress { + fun deployERC721(_ forNFTType: Type): EVMOnboardingValues { // Retrieve the Cadence type's defining contract name, address, & its identifier var name = FlowEVMBridgeUtils.getContractName(fromType: forNFTType) ?? panic("Could not contract name from type: ".concat(forNFTType.identifier)) @@ -442,7 +680,7 @@ contract FlowEVMBridge : IFlowEVMNFTBridge { let callResult: EVM.Result = FlowEVMBridgeUtils.call( signature: "deployERC721(string,string,string,string,string)", targetEVMAddress: FlowEVMBridgeUtils.bridgeFactoryEVMAddress, - args: [name, symbol, cadenceAddress.toString(), identifier, contractURI], // TODO: Decide on and update symbol + args: [name, symbol, cadenceAddress.toString(), identifier, contractURI], gasLimit: 15000000, value: 0.0 ) @@ -453,7 +691,81 @@ contract FlowEVMBridge : IFlowEVMNFTBridge { // Associate the deployed contract with the given type & return the deployed address let erc721Address = decodedResult[0] as! EVM.EVMAddress FlowEVMBridgeConfig.associateType(forNFTType, with: erc721Address) - return erc721Address + return EVMOnboardingValues( + evmContractAddress: erc721Address, + name: name, + symbol: symbol, + decimals: nil + ) + } + + /// Deploys templated ERC20 contract supporting EVM-native asset bridging to Cadence + /// + /// @param forTokenType: The Cadence Type of the FungibleToken.Vault + /// + /// @returns The EVMAddress of the deployed contract + /// + access(self) + fun deployERC20(_ forTokenType: Type): EVMOnboardingValues { + // Retrieve the Cadence type's defining contract name, address, & its identifier + var name = FlowEVMBridgeUtils.getContractName(fromType: forTokenType) + ?? panic("Could not contract name from type: ".concat(forTokenType.identifier)) + let identifier = forTokenType.identifier + let cadenceAddress = FlowEVMBridgeUtils.getContractAddress(fromType: forTokenType) + ?? panic("Could not derive contract address for token type: ".concat(identifier)) + // Assign a default symbol + var symbol: String? = nil + // Borrow the ViewResolver to attempt to resolve the EVMBridgedMetadata view + let viewResolver = getAccount(cadenceAddress).contracts.borrow<&{ViewResolver}>(name: name)! + var contractURI = "" + // Try to resolve the EVMBridgedMetadata + let bridgedMetadata = viewResolver.resolveContractView( + resourceType: forTokenType, + viewType: Type() + ) as! CrossVMNFT.EVMBridgedMetadata? + let ftDisplay = viewResolver.resolveContractView( + resourceType: forTokenType, + viewType: Type() + ) as! FungibleTokenMetadataViews.FTDisplay? + // Default to project-defined bridged metadata if available + if bridgedMetadata != nil { + name = bridgedMetadata!.name + symbol = bridgedMetadata!.symbol + contractURI = bridgedMetadata!.uri.uri() + } else if ftDisplay != nil { + // Otherwise pull from FTDisplay + name = ftDisplay!.name + symbol = ftDisplay!.symbol + } + if contractURI.length == 0 && ftDisplay != nil { + let serializedDisplay = SerializeNFT.serializeFTDisplay(ftDisplay!) + contractURI = "data:application/json;utf8,{".concat(serializedDisplay).concat("}") + } + + // Ensure symbol is assigned before proceeding + assert(symbol != nil, message: "Symbol must be assigned before deploying ERC20 contract") + + // Call to the factory contract to deploy an ERC20 & validate result + let callResult: EVM.Result = FlowEVMBridgeUtils.call( + signature: "deployERC20(string,string,string,string,string)", + targetEVMAddress: FlowEVMBridgeUtils.bridgeFactoryEVMAddress, + args: [name, symbol!, cadenceAddress.toString(), identifier, contractURI], // TODO: Decide on and update symbol + gasLimit: 15000000, + value: 0.0 + ) + assert(callResult.status == EVM.Status.successful, message: "Contract deployment failed") + let decodedResult: [AnyStruct] = EVM.decodeABI(types: [Type()], data: callResult.data) + assert(decodedResult.length == 1, message: "Invalid response length") + + // Associate the deployed contract with the given type & return the deployed address + let erc20Address = decodedResult[0] as! EVM.EVMAddress + FlowEVMBridgeConfig.associateType(forTokenType, with: erc20Address) + return EVMOnboardingValues( + evmContractAddress: erc20Address, + name: name, + symbol: symbol!, + decimals: FlowEVMBridgeConfig.defaultDecimals + ) } /// Helper for deploying templated defining contract supporting EVM-native asset bridging to Cadence @@ -464,21 +776,36 @@ contract FlowEVMBridge : IFlowEVMNFTBridge { access(self) fun deployDefiningContract(evmContractAddress: EVM.EVMAddress) { // Deploy the Cadence contract defining the asset - // Treat as NFT if ERC721, otherwise FT + // Treat as NFT if contract is ERC721, otherwise treat as FT let name: String = FlowEVMBridgeUtils.getName(evmContractAddress: evmContractAddress) let symbol: String = FlowEVMBridgeUtils.getSymbol(evmContractAddress: evmContractAddress) + let contractURI = FlowEVMBridgeUtils.getContractURI(evmContractAddress: evmContractAddress) + var decimals: UInt8 = FlowEVMBridgeConfig.defaultDecimals // Derive contract name - let isERC721: Bool = FlowEVMBridgeUtils.isEVMNFT(evmContractAddress: evmContractAddress) - let cadenceContractName: String = FlowEVMBridgeUtils.deriveBridgedNFTContractName(from: evmContractAddress) - let contractURI = FlowEVMBridgeUtils.getContractURI(evmContractAddress: evmContractAddress) + let isERC721: Bool = FlowEVMBridgeUtils.isERC721(evmContractAddress: evmContractAddress) + var cadenceContractName: String = "" + if isERC721 { + // Assert the contract is not mixed asset + let isERC20 = FlowEVMBridgeUtils.isERC20(evmContractAddress: evmContractAddress) + assert(!isERC20, message: "Contract is mixed asset and is not currently supported by the bridge") + // Derive the contract name from the ERC721 contract + cadenceContractName = FlowEVMBridgeUtils.deriveBridgedNFTContractName(from: evmContractAddress) + } else { + cadenceContractName = FlowEVMBridgeUtils.deriveBridgedTokenContractName(from: evmContractAddress) + decimals = FlowEVMBridgeUtils.getTokenDecimals(evmContractAddress: evmContractAddress) + } - // Get Cadence code from template + // Get Cadence code from template & deploy to the bridge account let cadenceCode: [UInt8] = FlowEVMBridgeTemplates.getBridgedAssetContractCode( - evmContractAddress: evmContractAddress, + cadenceContractName, isERC721: isERC721 ) ?? panic("Problem retrieving code for Cadence-defining contract") - self.account.contracts.add(name: cadenceContractName, code: cadenceCode, name, symbol, evmContractAddress, contractURI) + if isERC721 { + self.account.contracts.add(name: cadenceContractName, code: cadenceCode, name, symbol, evmContractAddress, contractURI) + } else { + self.account.contracts.add(name: cadenceContractName, code: cadenceCode, name, symbol, decimals, evmContractAddress, contractURI) + } emit BridgeDefiningContractDeployed( contractName: cadenceContractName, diff --git a/cadence/contracts/bridge/FlowEVMBridgeAccessor.cdc b/cadence/contracts/bridge/FlowEVMBridgeAccessor.cdc new file mode 100644 index 00000000..f8f4d734 --- /dev/null +++ b/cadence/contracts/bridge/FlowEVMBridgeAccessor.cdc @@ -0,0 +1,189 @@ +import "NonFungibleToken" +import "FungibleToken" +import "FlowToken" + +import "EVM" + +import "FlowEVMBridge" + +/// This contract defines a mechanism for routing bridge requests from the EVM contract to the Flow-EVM bridge contract +/// +access(all) +contract FlowEVMBridgeAccessor { + + access(all) let StoragePath: StoragePath + + /// BridgeAccessor implementation used by the EVM contract to route bridge calls from COA resources + /// + access(all) + resource BridgeAccessor : EVM.BridgeAccessor { + + /// Passes along the bridge request to dedicated bridge contract + /// + /// @param nft: The NFT to be bridged to EVM + /// @param to: The address of the EVM account to receive the bridged NFT + /// @param feeProvider: A reference to a FungibleToken Provider from which the bridging fee is withdrawn in $FLOW + /// + access(EVM.Bridge) + fun depositNFT( + nft: @{NonFungibleToken.NFT}, + to: EVM.EVMAddress, + feeProvider: auth(FungibleToken.Withdraw) &{FungibleToken.Provider} + ) { + FlowEVMBridge.bridgeNFTToEVM(token: <-nft, to: to, feeProvider: feeProvider) + } + + /// Passes along the bridge request to the dedicated bridge contract, returning the bridged NFT + /// + /// @param caller: A reference to the COA which currently owns the NFT in EVM + /// @param type: The Cadence type of the NFT to be bridged from EVM + /// @param id: The ID of the NFT to be bridged from EVM + /// @param feeProvider: A reference to a FungibleToken Provider from which the bridging fee is withdrawn in $FLOW + /// + /// @return The bridged NFT + /// + access(EVM.Bridge) + fun withdrawNFT( + caller: auth(EVM.Call) &EVM.CadenceOwnedAccount, + type: Type, + id: UInt256, + feeProvider: auth(FungibleToken.Withdraw) &{FungibleToken.Provider} + ): @{NonFungibleToken.NFT} { + // Define a callback function, enabling the bridge to act on the ephemeral COA reference in scope + var executed = false + fun callback(): EVM.Result { + pre { + !executed: "Callback can only be executed once" + } + post { + executed: "Callback must be executed" + } + executed = true + return caller.call( + to: FlowEVMBridge.getAssociatedEVMAddress(with: type) + ?? panic("No EVM address associated with type"), + data: EVM.encodeABIWithSignature( + "safeTransferFrom(address,address,uint256)", + [caller.address(), FlowEVMBridge.getBridgeCOAEVMAddress(), id] + ), + gasLimit: 15000000, + value: EVM.Balance(attoflow: 0) + ) + } + // Execute the bridge request + return <- FlowEVMBridge.bridgeNFTFromEVM( + owner: caller.address(), + type: type, + id: id, + feeProvider: feeProvider, + protectedTransferCall: callback + ) + } + + /// Passes along the bridge request to dedicated bridge contract + /// + /// @param vault: The fungible token vault to be bridged to EVM + /// @param to: The address of the EVM account to receive the bridged tokens + /// @param feeProvider: A reference to a FungibleToken Provider from which the bridging fee is withdrawn in $FLOW + /// + access(EVM.Bridge) + fun depositTokens( + vault: @{FungibleToken.Vault}, + to: EVM.EVMAddress, + feeProvider: auth(FungibleToken.Withdraw) &{FungibleToken.Provider} + ) { + FlowEVMBridge.bridgeTokensToEVM(vault: <-vault, to: to, feeProvider: feeProvider) + } + + /// Passes along the bridge request to the dedicated bridge contract, returning the bridged NFT + /// + /// @param caller: A reference to the COA which currently owns the tokens in EVM + /// @param type: The Cadence type of the fungible token vault to be bridged from EVM + /// @param amount: The amount of tokens to be bridged + /// @param feeProvider: A reference to a FungibleToken Provider from which the bridging fee is withdrawn in $FLOW + /// + /// @return The bridged NFT + /// + access(EVM.Bridge) + fun withdrawTokens( + caller: auth(EVM.Call) &EVM.CadenceOwnedAccount, + type: Type, + amount: UInt256, + feeProvider: auth(FungibleToken.Withdraw) &{FungibleToken.Provider} + ): @{FungibleToken.Vault} { + // Define a callback function, enabling the bridge to act on the ephemeral COA reference in scope + var executed = false + fun callback(): EVM.Result { + pre { + !executed: "Callback can only be executed once" + } + post { + executed: "Callback must be executed" + } + executed = true + return caller.call( + to: FlowEVMBridge.getAssociatedEVMAddress(with: type) + ?? panic("No EVM address associated with type"), + data: EVM.encodeABIWithSignature( + "transfer(address,uint256)", + [FlowEVMBridge.getBridgeCOAEVMAddress(), amount] + ), + gasLimit: 15000000, + value: EVM.Balance(attoflow: 0) + ) + } + // Execute the bridge request + return <- FlowEVMBridge.bridgeTokensFromEVM( + owner: caller.address(), + type: type, + amount: amount, + feeProvider: feeProvider, + protectedTransferCall: callback + ) + } + + /// Returns a BridgeRouter resource so a Capability on this BridgeAccessor can be stored in the BridgeRouter + /// + access(EVM.Bridge) fun createBridgeRouter(): @BridgeRouter { + return <-create BridgeRouter() + } + } + + /// BridgeRouter implementation used by the EVM contract to capture a BridgeAccessor Capability and route bridge + /// calls from COA resources to the FlowEVMBridge contract + /// + access(all) resource BridgeRouter : EVM.BridgeRouter { + /// Capability to the BridgeAccessor resource, initialized to nil + access(self) var bridgeAccessorCap: Capability? + + init() { + self.bridgeAccessorCap = nil + } + + /// Sets the BridgeAccessor capability on the BridgeRouter + /// + access(EVM.Bridge) fun setBridgeAccessorCap(_ cap: Capability) { + pre { + cap.check(): "BridgeAccessor capability already set" + } + self.bridgeAccessorCap = cap + } + + /// Returns an EVM.Bridge entitled reference to the underlying BridgeAccessor resource + /// + access(EVM.Bridge) view fun borrowBridgeAccessor(): auth(EVM.Bridge) &{EVM.BridgeAccessor} { + let cap = self.bridgeAccessorCap ?? panic("BridgeAccessor Capabaility is not yet set") + return cap.borrow() ?? panic("Problem retrieving BridgeAccessor reference") + } + } + + init(publishToEVMAccount: Address) { + self.StoragePath = /storage/flowEVMBridgeAccessor + self.account.storage.save( + <-create BridgeAccessor(), + to: self.StoragePath + ) + let cap = self.account.capabilities.storage.issue(self.StoragePath) + self.account.inbox.publish(cap, name: "FlowEVMBridgeAccessor", recipient: publishToEVMAccount) + } +} diff --git a/cadence/contracts/bridge/FlowEVMBridgeConfig.cdc b/cadence/contracts/bridge/FlowEVMBridgeConfig.cdc index b78054b2..0387af17 100644 --- a/cadence/contracts/bridge/FlowEVMBridgeConfig.cdc +++ b/cadence/contracts/bridge/FlowEVMBridgeConfig.cdc @@ -1,5 +1,7 @@ import "EVM" +import "FlowToken" + /// This contract is used to store configuration information shared by FlowEVMBridge contracts /// access(all) @@ -16,6 +18,9 @@ contract FlowEVMBridgeConfig { /// Fee rate per storage unit consumed by bridged assets access(all) var storageRate: UFix64 + /// Default ERC20.decimals() value + access(all) + let defaultDecimals: UInt8 /// Mapping of Type to its associated EVMAddress as relevant to the bridge access(self) let typeToEVMAddress: {Type: EVM.EVMAddress} @@ -113,7 +118,12 @@ contract FlowEVMBridgeConfig { self.onboardFee = 0.0 self.baseFee = 0.0 self.storageRate = 0.0 - self.typeToEVMAddress = {} + self.defaultDecimals = 18 + self.typeToEVMAddress = { + Type<@FlowToken.Vault>(): EVM.EVMAddress( + bytes: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + ) + } self.adminStoragePath = /storage/flowEVMBridgeConfigAdmin self.coaStoragePath = /storage/evm self.providerCapabilityStoragePath = /storage/bridgeFlowVaultProvider diff --git a/cadence/contracts/bridge/FlowEVMBridgeNFTEscrow.cdc b/cadence/contracts/bridge/FlowEVMBridgeNFTEscrow.cdc index 93c6f5b6..78fde7e4 100644 --- a/cadence/contracts/bridge/FlowEVMBridgeNFTEscrow.cdc +++ b/cadence/contracts/bridge/FlowEVMBridgeNFTEscrow.cdc @@ -21,12 +21,8 @@ access(all) contract FlowEVMBridgeNFTEscrow { /// Returns whether the Locker has been initialized for the given NFT type /// - access(all) - view fun isInitialized(forType: Type): Bool { - if let lockerPath = FlowEVMBridgeUtils.deriveEscrowStoragePath(fromType: forType) { - return self.account.storage.type(at: lockerPath) != nil - } - return false + access(all) view fun isInitialized(forType: Type): Bool { + return self.borrowLocker(forType: forType) != nil } /// Returns whether an NFT with the given ID is locked @@ -35,8 +31,7 @@ access(all) contract FlowEVMBridgeNFTEscrow { /// /// @returns True if the NFT is locked, false otherwise /// - access(all) - view fun isLocked(type: Type, id: UInt64): Bool { + access(all) view fun isLocked(type: Type, id: UInt64): Bool { return self.borrowLockedNFT(type: type, id: id) != nil } @@ -47,14 +42,8 @@ access(all) contract FlowEVMBridgeNFTEscrow { /// /// @returns Cadence ID of the locked NFT if it exists /// - access(all) - view fun getLockedCadenceID(type: Type, evmID: UInt256): UInt64? { - if let lockerPath = FlowEVMBridgeUtils.deriveEscrowStoragePath(fromType: type) { - if let locker = self.account.storage.borrow<&Locker>(from: lockerPath) { - return locker.getCadenceID(from: evmID) - } - } - return nil + access(all) view fun getLockedCadenceID(type: Type, evmID: UInt256): UInt64? { + return self.borrowLocker(forType: type)?.getCadenceID(from: evmID) ?? nil } /// Returns the EVM NFT ID associated with the Cadence NFT ID. The goal is to retrieve the ERC721 ID value @@ -70,14 +59,8 @@ access(all) contract FlowEVMBridgeNFTEscrow { /// /// @returns EVM ID of the locked NFT if it exists /// - access(all) - view fun getLockedEVMID(type: Type, cadenceID: UInt64): UInt256? { - if let lockerPath = FlowEVMBridgeUtils.deriveEscrowStoragePath(fromType: type) { - if let locker = self.account.storage.borrow<&Locker>(from: lockerPath) { - return locker.getEVMID(from: cadenceID) - } - } - return nil + access(all) view fun getLockedEVMID(type: Type, cadenceID: UInt64): UInt256? { + return self.borrowLocker(forType: type)?.getEVMID(from: cadenceID) ?? nil } /// Resolves the requested view type for the given NFT type if it is locked and supports the requested view type @@ -88,13 +71,10 @@ access(all) contract FlowEVMBridgeNFTEscrow { /// /// @returns The resolved view as AnyStruct if the NFT is locked and the view is supported, otherwise returns nil /// - access(all) - fun resolveLockedNFTView(nftType: Type, id: UInt256, viewType: Type): AnyStruct? { - if let lockerPath = FlowEVMBridgeUtils.deriveEscrowStoragePath(fromType: nftType) { - if let locker = self.account.storage.borrow<&Locker>(from: lockerPath) { - if let cadenceID = locker.getCadenceID(from: id) { - return locker.borrowViewResolver(id: cadenceID)?.resolveView(viewType) ?? nil - } + access(all) fun resolveLockedNFTView(nftType: Type, id: UInt256, viewType: Type): AnyStruct? { + if let locker = self.borrowLocker(forType: nftType) { + if let cadenceID = locker.getCadenceID(from: id) { + return locker.borrowViewResolver(id: cadenceID)?.resolveView(viewType) ?? nil } } return nil @@ -106,77 +86,84 @@ access(all) contract FlowEVMBridgeNFTEscrow { /// Initializes the Locker for the given NFT type if it hasn't been initialized yet /// - access(account) - fun initializeEscrow(forType: Type, erc721Address: EVM.EVMAddress) { + access(account) fun initializeEscrow(forType: Type, name: String, symbol: String, erc721Address: EVM.EVMAddress) { let lockerPath = FlowEVMBridgeUtils.deriveEscrowStoragePath(fromType: forType) ?? panic("Problem deriving locker path") if self.account.storage.type(at: lockerPath) != nil { return } - let locker <- create Locker(lockedType: forType, erc721Address: erc721Address) + + let locker <- create Locker(name: name, symbol: symbol, lockedType: forType, erc721Address: erc721Address) self.account.storage.save(<-locker, to: lockerPath) } /// Locks the NFT in escrow, returning the amount of storage used by the locker after storing /// - access(account) - fun lockNFT(_ nft: @{NonFungibleToken.NFT}): UInt64 { - let lockerPath = FlowEVMBridgeUtils.deriveEscrowStoragePath(fromType: nft.getType()) + access(account) fun lockNFT(_ nft: @{NonFungibleToken.NFT}): UInt64 { + let locker = self.borrowLocker(forType: nft.getType()) ?? panic("Problem deriving locker path") - let locker = self.account.storage.borrow<&Locker>(from: lockerPath) - ?? panic("Locker doesn't exist") + let preStorageSnapshot = self.account.storage.used locker.deposit(token: <-nft) let postStorageSnapshot = self.account.storage.used + return postStorageSnapshot - preStorageSnapshot } /// Unlocks the NFT of the given type and ID, reverting if it isn't in escrow /// - access(account) - fun unlockNFT(type: Type, id: UInt64): @{NonFungibleToken.NFT} { - let lockerPath = FlowEVMBridgeUtils.deriveEscrowStoragePath(fromType: type) + access(account) fun unlockNFT(type: Type, id: UInt64): @{NonFungibleToken.NFT} { + let locker = self.borrowLocker(forType: type) ?? panic("Problem deriving locker path") - let locker = self.account.storage.borrow(from: lockerPath) - ?? panic("Locker doesn't exist") return <- locker.withdraw(withdrawID: id) } /// Retrieves a reference to the NFT of the given type and ID if it is locked, otherwise returns nil /// - access(account) - view fun borrowLockedNFT(type: Type, id: UInt64): &{NonFungibleToken.NFT}? { + access(account) view fun borrowLockedNFT(type: Type, id: UInt64): &{NonFungibleToken.NFT}? { if let lockerPath = FlowEVMBridgeUtils.deriveEscrowStoragePath(fromType: type) { return self.account.storage.borrow<&Locker>(from: lockerPath)?.borrowNFT(id) ?? nil } return nil } + /// Retrieves an entitled locker for the given type or nil if it doesn't exist + /// + access(self) view fun borrowLocker(forType: Type): auth(NonFungibleToken.Withdraw) &Locker? { + if let lockerPath = FlowEVMBridgeUtils.deriveEscrowStoragePath(fromType: forType) { + if self.account.storage.type(at: lockerPath) == Type<@Locker>() { + return self.account.storage.borrow(from: lockerPath) + } + } + return nil + } + /********************* Locker *********************/ /// The resource managing the locking & unlocking of NFTs via this contract's interface /// - access(all) resource Locker : CrossVMNFT.EVMNFTCollection, NonFungibleToken.Collection { - /// The type of NFTs this Locker escrows - access(all) - let lockedType: Type + access(all) resource Locker : CrossVMNFT.EVMNFTCollection { + /// Corresponding name assigned in the tokens' corresponding ERC20 contract + access(all) let name: String + /// Corresponding symbol assigned in the tokens' corresponding ERC20 contract + access(all) let symbol: String /// Corresponding ERC721 address for the locked NFTs - access(all) - let erc721Address: EVM.EVMAddress + access(all) let erc721Address: EVM.EVMAddress + /// The type of NFTs this Locker escrows + access(all) let lockedType: Type /// Count of locked NFTs as lockedNFTs.length may exceed computation limits - access(self) - var lockedNFTCount: Int + access(self) var lockedNFTCount: Int /// Indexed on NFT UUID to prevent collisions - access(self) - let lockedNFTs: @{UInt64: {NonFungibleToken.NFT}} + access(self) let lockedNFTs: @{UInt64: {NonFungibleToken.NFT}} /// Maps EVM NFT ID to Flow NFT ID, covering cross-VM project NFTs - access(self) - let evmIDToFlowID: {UInt256: UInt64} + access(self) let evmIDToFlowID: {UInt256: UInt64} - init(lockedType: Type, erc721Address: EVM.EVMAddress) { + init(name: String, symbol: String, lockedType: Type, erc721Address: EVM.EVMAddress) { + self.name = name + self.symbol = symbol self.lockedType = lockedType self.erc721Address = erc721Address self.lockedNFTCount = 0 @@ -184,6 +171,16 @@ access(all) contract FlowEVMBridgeNFTEscrow { self.evmIDToFlowID = {} } + access(all) + view fun getName(): String { + return self.name + } + + access(all) + view fun getSymbol(): String { + return self.symbol + } + /// Returns the number of locked NFTs /// access(all) @@ -233,7 +230,7 @@ access(all) contract FlowEVMBridgeNFTEscrow { return nil } - access(all) view fun contractURI(): String? { + access(all) fun contractURI(): String? { return nil } @@ -300,7 +297,12 @@ access(all) contract FlowEVMBridgeNFTEscrow { /// access(all) fun createEmptyCollection(): @{NonFungibleToken.Collection} { - return <- create Locker(lockedType: self.lockedType, erc721Address: self.erc721Address) + return <- create Locker( + name: self.name, + symbol: self.symbol, + lockedType: self.lockedType, + erc721Address: self.erc721Address + ) } } } diff --git a/cadence/contracts/bridge/FlowEVMBridgeTemplates.cdc b/cadence/contracts/bridge/FlowEVMBridgeTemplates.cdc index 20566681..0ec78fcc 100644 --- a/cadence/contracts/bridge/FlowEVMBridgeTemplates.cdc +++ b/cadence/contracts/bridge/FlowEVMBridgeTemplates.cdc @@ -28,16 +28,11 @@ contract FlowEVMBridgeTemplates { /// Serves bridged asset contract code for a given type, deriving the contract name from the EVM contract info access(all) - fun getBridgedAssetContractCode(evmContractAddress: EVM.EVMAddress, isERC721: Bool): [UInt8]? { - let cadenceContractName: String = isERC721 ? - FlowEVMBridgeUtils.deriveBridgedNFTContractName(from: evmContractAddress) : - FlowEVMBridgeUtils.deriveBridgedTokenContractName(from: evmContractAddress) - + fun getBridgedAssetContractCode(_ cadenceContractName: String, isERC721: Bool): [UInt8]? { if isERC721 { return self.getBridgedNFTContractCode(contractName: cadenceContractName) } else { - // TODO - return nil + return self.getBridgedTokenContractCode(contractName: cadenceContractName) } } @@ -47,7 +42,18 @@ contract FlowEVMBridgeTemplates { access(self) fun getBridgedNFTContractCode(contractName: String): [UInt8]? { - return self.joinChunks(self.templateCodeChunks["bridgedNFT"]!, with: String.encodeHex(contractName.utf8)) + if let chunks = self.templateCodeChunks["bridgedNFT"] { + return self.joinChunks(chunks, with: String.encodeHex(contractName.utf8)) + } + return nil + } + + access(self) + fun getBridgedTokenContractCode(contractName: String): [UInt8]? { + if let chunks = self.templateCodeChunks["bridgedToken"] { + return self.joinChunks(chunks, with: String.encodeHex(contractName.utf8)) + } + return nil } access(self) diff --git a/cadence/contracts/bridge/FlowEVMBridgeTokenEscrow.cdc b/cadence/contracts/bridge/FlowEVMBridgeTokenEscrow.cdc new file mode 100644 index 00000000..a8c9eebf --- /dev/null +++ b/cadence/contracts/bridge/FlowEVMBridgeTokenEscrow.cdc @@ -0,0 +1,237 @@ + +import "Burner" +import "FungibleToken" +import "NonFungibleToken" +import "MetadataViews" +import "ViewResolver" +import "FlowToken" + +import "EVM" + +import "FlowEVMBridgeConfig" +import "FlowEVMBridgeUtils" +import "CrossVMToken" + +/// This escrow contract handles the locking of fungible tokens that are bridged from Cadence to EVM and retrieval of +/// locked assets in escrow when they are bridged back to Cadence. +/// +access(all) contract FlowEVMBridgeTokenEscrow { + + /********************** + Getters + ***********************/ + + /// Returns whether the Locker has been initialized for the given fungible token type + /// + /// @param forType: Type of the locked fungible tokens + /// + /// @returns true if the Locker has been initialized for the given fungible token type, otherwise false + /// + access(all) view fun isInitialized(forType: Type): Bool { + return self.borrowLocker(forType: forType) != nil + } + + /// Returns the balance of locked tokens for the given fungible token type + /// + /// @param tokenType: Type of the locked fungible tokens + /// + /// @returns The balance of locked tokens for the given fungible token type or nil if the locker doesn't exist + /// + access(all) view fun getLockedTokenBalance(tokenType: Type): UFix64? { + return self.borrowLocker(forType: tokenType)?.getLockedBalance() ?? nil + } + + /// Returns the type of the locked vault for the given fungible token type + /// + /// @param tokenType: Type of the locked fungible tokens + /// + /// @returns The type of the locked vault for the given fungible token type or nil if the locker doesn't exist + /// + access(all) view fun getViews(tokenType: Type): [Type]? { + return self.borrowLocker(forType: tokenType)?.getViews() ?? [] + } + + /// Resolves the requested view type for the given FT type if it is locked and supports the requested view type + /// + /// @param tokenType: Type of the locked fungible tokens + /// @param viewType: Type of the view to resolve + /// + /// @returns The resolved view as AnyStruct if the vault is locked and the view is supported, otherwise returns nil + /// + access(all) fun resolveLockedTokenView(tokenType: Type, viewType: Type): AnyStruct? { + // The Locker implements Resolver, which has basic resolveView functionality + return self.borrowLocker(forType: tokenType)?.resolveView(viewType) ?? nil + } + + /********************** + Bridge Methods + ***********************/ + + /// Initializes the Locker for the given fungible token type if it hasn't been initialized yet + /// + access(account) fun initializeEscrow( + with vault: @{FungibleToken.Vault}, + name: String, + symbol: String, + decimals: UInt8, + evmTokenAddress: EVM.EVMAddress + ) { + pre { + vault.balance == 0.0: "Can only initialize Escrow with an empty vault" + } + let lockedType = vault.getType() + let lockerPath = FlowEVMBridgeUtils.deriveEscrowStoragePath(fromType: lockedType) + ?? panic("Problem deriving locker path") + if self.account.storage.type(at: lockerPath) != nil { + panic("Collision at derived Locker path for type: ".concat(lockedType.identifier)) + } + + // Create the Locker, lock a new vault of given type and save at the derived path + let locker <- create Locker( + name: name, + symbol: symbol, + decimals: decimals, + lockedVault: <-vault, + evmTokenAddress: evmTokenAddress + ) + self.account.storage.save(<-locker, to: lockerPath) + } + + /// Locks the fungible tokens in escrow returning the storage used by locking the Vault + /// + access(account) fun lockTokens(_ vault: @{FungibleToken.Vault}): UInt64 { + let locker = self.borrowLocker(forType: vault.getType()) ?? panic("Locker doesn't exist for given type") + + let preStorageSnapshot = self.account.storage.used + locker.deposit(from: <-vault) + let postStorageSnapshot = self.account.storage.used + + return postStorageSnapshot - preStorageSnapshot + } + + /// Unlocks the tokens of the given type and amount, reverting if it isn't in escrow + /// + access(account) fun unlockTokens(type: Type, amount: UFix64): @{FungibleToken.Vault} { + let locker = self.borrowLocker(forType: type) ?? panic("Locker doesn't exist for given type") + return <- locker.withdraw(amount: amount) + + } + + /// Retrieves an entitled locker for the given type or nil if it doesn't exist + /// + access(self) view fun borrowLocker(forType: Type): auth(FungibleToken.Withdraw) &Locker? { + if let lockerPath = FlowEVMBridgeUtils.deriveEscrowStoragePath(fromType: forType) { + if self.account.storage.type(at: lockerPath) == Type<@Locker>() { + return self.account.storage.borrow(from: lockerPath) + } + } + return nil + } + + /********************* + Locker + *********************/ + + /// The resource managing the locking & unlocking of FTs via this contract's interface. + /// + access(all) resource Locker : CrossVMToken.EVMTokenInfo, FungibleToken.Receiver, FungibleToken.Provider, ViewResolver.Resolver { + /// Corresponding name assigned in the tokens' corresponding ERC20 contract + access(all) let name: String + /// Corresponding symbol assigned in the tokens' corresponding ERC20 contract + access(all) let symbol: String + /// Corresponding decimals assigned in the tokens' corresponding ERC20 contract. While Cadence support floating + /// point numbers, EVM does not, so we need to keep track of the decimals to convert between the two. + access(all) let decimals: UInt8 + /// Corresponding ERC20 address for the locked tokens + access(all) let evmTokenAddress: EVM.EVMAddress + // Vault to hold all locked tokens + access(self) let lockedVault: @{FungibleToken.Vault} + + + init(name: String, symbol: String, decimals: UInt8, lockedVault: @{FungibleToken.Vault}, evmTokenAddress: EVM.EVMAddress) { + self.decimals = decimals + self.name = name + self.symbol = symbol + self.evmTokenAddress = evmTokenAddress + + self.lockedVault <- lockedVault + // Locked Vaults must accept their own type as Lockers escrow Vaults on a 1:1 type basis + assert( + self.lockedVault.isSupportedVaultType(type: self.lockedVault.getType()), + message: "Locked Vault does not accept its own type" + ) + } + + /// Gets the ERC20 name value + access(all) view fun getName(): String { + return self.name + } + /// Gets the ERC20 symbol value + access(all) view fun getSymbol(): String { + return self.symbol + } + /// Gets the ERC20 decimals value + access(all) view fun getDecimals(): UInt8 { + return self.decimals + } + /// Get the EVM contract address of the locked Vault's corresponding ERC20 contract address + /// + access(all) view fun getEVMContractAddress(): EVM.EVMAddress { + return self.evmTokenAddress + } + + /// Returns the balance of tokens in the locked Vault + /// + access(all) view fun getLockedBalance(): UFix64 { + return self.lockedVault.balance + } + + /// Returns the type of the locked vault + /// + access(all) view fun getLockedType(): Type { + return self.lockedVault.getType() + } + + /// Function to ask a provider if a specific amount of tokens is available to be withdrawn from the locked vault + /// + access(all) view fun isAvailableToWithdraw(amount: UFix64): Bool { + return self.lockedVault.isAvailableToWithdraw(amount: amount) + } + + /// Returns a mapping of vault types that this locker accepts. This Locker will only accept Vaults of the same + /// + access(all) view fun getSupportedVaultTypes(): {Type: Bool} { + return {self.lockedVault.getType(): true} + } + + /// Returns whether or not the given type is accepted by the Receiver + /// + access(all) view fun isSupportedVaultType(type: Type): Bool { + return self.getSupportedVaultTypes()[type] ?? false + } + + /// Returns the views supported by the locked Vault + /// + access(all) view fun getViews(): [Type] { + return self.lockedVault.getViews() + } + + /// Resolves the requested view type on the locked FT if it supports the requested view type + /// + access(all) fun resolveView(_ view: Type): AnyStruct? { + return self.lockedVault.resolveView(view) + } + + /// Deposits the given token vault into the contained locked Vault + /// + access(all) fun deposit(from: @{FungibleToken.Vault}) { + self.lockedVault.deposit(from: <-from) + } + + /// Withdraws an amount of tokens from this locker, removing it from the vault and returning it + /// + access(FungibleToken.Withdraw) fun withdraw(amount: UFix64): @{FungibleToken.Vault} { + return <-self.lockedVault.withdraw(amount: amount) + } + } +} diff --git a/cadence/contracts/bridge/FlowEVMBridgeUtils.cdc b/cadence/contracts/bridge/FlowEVMBridgeUtils.cdc index af3df80c..25ea3726 100644 --- a/cadence/contracts/bridge/FlowEVMBridgeUtils.cdc +++ b/cadence/contracts/bridge/FlowEVMBridgeUtils.cdc @@ -85,7 +85,11 @@ contract FlowEVMBridgeUtils { /// access(all) view fun calculateBridgeFee(used: UInt64, includeBase: Bool): UFix64 { - return FlowEVMBridgeConfig.baseFee + // TODO: Include storage-based fee calculation + // let x = FlowStorageFees.convertUInt64StorageBytesToUFix64Megabytes(used) * FlowEVMBridgeConfig.storageRate + let y = includeBase ? FlowEVMBridgeConfig.baseFee : 0.0 + // return x + y + return y } /// Returns whether the given type is allowed to be bridged as defined by the BridgePermissions contract interface. @@ -190,7 +194,7 @@ contract FlowEVMBridgeUtils { /// @return True if the asset is an ERC721, false otherwise /// access(all) - fun isEVMNFT(evmContractAddress: EVM.EVMAddress): Bool { + fun isERC721(evmContractAddress: EVM.EVMAddress): Bool { let callResult = self.call( signature: "isERC721(address)", targetEVMAddress: self.bridgeFactoryEVMAddress, @@ -208,10 +212,25 @@ contract FlowEVMBridgeUtils { /// Identifies if an asset is ERC20 /// + /// @param evmContractAddress: The EVM contract address to check + /// + /// @return true if the asset is an ERC20, false otherwise + /// access(all) - fun isEVMToken(evmContractAddress: EVM.EVMAddress): Bool { - // TODO: We will need to figure out how to identify ERC20s without ERC165 support - return false + fun isERC20(evmContractAddress: EVM.EVMAddress): Bool { + let callResult = self.call( + signature: "isERC20(address)", + targetEVMAddress: self.bridgeFactoryEVMAddress, + args: [evmContractAddress], + gasLimit: 100000, + value: 0.0 + ) + + assert(callResult.status == EVM.Status.successful, message: "Call to bridge factory failed") + 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 contract address is either an ERC721 or ERC20 exclusively. Reverts on EVM call failure. @@ -222,9 +241,9 @@ contract FlowEVMBridgeUtils { /// access(all) fun isValidEVMAsset(evmContractAddress: EVM.EVMAddress): Bool { - let isEVMNFT = FlowEVMBridgeUtils.isEVMNFT(evmContractAddress: evmContractAddress) - let isEVMToken = FlowEVMBridgeUtils.isEVMToken(evmContractAddress: evmContractAddress) - return (isEVMNFT && !isEVMToken) || (!isEVMNFT && isEVMToken) + let isERC721 = FlowEVMBridgeUtils.isERC721(evmContractAddress: evmContractAddress) + let isERC20 = FlowEVMBridgeUtils.isERC20(evmContractAddress: evmContractAddress) + return (isERC721 && !isERC20) || (!isERC721 && isERC20) } /// Returns whether the given type is either an NFT or FT exclusively @@ -418,7 +437,6 @@ contract FlowEVMBridgeUtils { gasLimit: 12000000, value: 0.0 ) - assert(callResult.status == EVM.Status.successful, message: "Call to ERC721.getApproved(uint256) failed") let decodedCallResult = EVM.decodeABI(types: [Type()], data: callResult.data) if decodedCallResult.length == 1 { @@ -428,8 +446,7 @@ contract FlowEVMBridgeUtils { return false } - /// Determines if the owner has sufficient funds to bridge the given amount at the ERC20 contract address - /// Reverts on EVM call failure. + /// Returns the ERC20 balance of the owner at the given ERC20 contract address. Reverts on EVM call failure. /// /// @param amount: The amount to check if the owner has enough balance to cover /// @param owner: The owner address to query @@ -438,7 +455,7 @@ contract FlowEVMBridgeUtils { /// @return true if the owner's balance >= amount, false otherwise /// access(all) - fun hasSufficientBalance(amount: UFix64, owner: EVM.EVMAddress, evmContractAddress: EVM.EVMAddress): Bool { + fun balanceOf(owner: EVM.EVMAddress, evmContractAddress: EVM.EVMAddress): UInt256 { let callResult = self.call( signature: "balanceOf(address)", targetEVMAddress: evmContractAddress, @@ -446,13 +463,24 @@ contract FlowEVMBridgeUtils { gasLimit: 60000, value: 0.0 ) - assert(callResult.status == EVM.Status.successful, message: "Call to ERC20.balanceOf(address) failed") - let decodedResult = EVM.decodeABI(types: [Type()], data: callResult.data) as! [UInt256] + let decodedResult = EVM.decodeABI(types: [Type()], data: callResult.data) as! [AnyStruct] assert(decodedResult.length == 1, message: "Invalid response length") + return decodedResult[0] as! UInt256 + } - let tokenDecimals = self.getTokenDecimals(evmContractAddress: evmContractAddress) - return self.uint256ToUFix64(value: decodedResult[0], decimals: tokenDecimals) >= amount + /// Determines if the owner has sufficient funds to bridge the given amount at the ERC20 contract address + /// Reverts on EVM call failure. + /// + /// @param amount: The amount to check if the owner has enough balance to cover + /// @param owner: The owner address to query + /// @param evmContractAddress: The ERC20 contract address to query + /// + /// @return true if the owner's balance >= amount, false otherwise + /// + access(all) + fun hasSufficientBalance(amount: UInt256, owner: EVM.EVMAddress, evmContractAddress: EVM.EVMAddress): Bool { + return self.balanceOf(owner: owner, evmContractAddress: evmContractAddress) >= amount } /************************ @@ -549,7 +577,10 @@ contract FlowEVMBridgeUtils { let scaleFactor: UInt256 = self.pow(base: 10, exponent: decimals) let scaledValue: UInt256 = value / scaleFactor - assert(scaledValue > UInt256(UInt64.max), message: "Value too large to fit into UFix64") + assert( + scaledValue < UInt256(UInt64.max), + message: "Value ".concat(value.toString()).concat(" exceeds max UFix64 value") + ) return UFix64(scaledValue) } @@ -647,6 +678,25 @@ contract FlowEVMBridgeUtils { return CompositeType(identifier) } + /************************** + FungibleToken Utils + **************************/ + + /// Returns the `createEmptyVault()` function from a Vault Type's defining contract or nil if either the Type is not + access(all) fun getCreateEmptyVaultFunction(forType: Type): (fun (Type): @{FungibleToken.Vault})? { + // We can only reasonably assume that the requested function is accessible from a FungibleToken contract + if !forType.isSubtype(of: Type<@{FungibleToken.Vault}>()) { + return nil + } + // Vault Types should guarantee that the following forced optionals are safe + let contractAddress = self.getContractAddress(fromType: forType)! + let contractName = self.getContractName(fromType: forType)! + let tokenContract: &{FungibleToken} = getAccount(contractAddress).contracts.borrow<&{FungibleToken}>( + name: contractName + )! + return tokenContract.createEmptyVault + } + /****************************** Bridge-Access Only Utils ******************************/ diff --git a/cadence/contracts/bridge/IEVMBridgeNFTMinter.cdc b/cadence/contracts/bridge/IEVMBridgeNFTMinter.cdc index ef74aa74..802c7e10 100644 --- a/cadence/contracts/bridge/IEVMBridgeNFTMinter.cdc +++ b/cadence/contracts/bridge/IEVMBridgeNFTMinter.cdc @@ -1,19 +1,36 @@ import "NonFungibleToken" -/// Contract interface enabling FlowEVMBridge to mint NFTs +/// Contract interface enabling FlowEVMBridge to mint NFTs from implementing bridge contracts. /// access(all) contract interface IEVMBridgeNFTMinter { + access(all) event Minted(type: Type, id: UInt64, evmID: UInt256, tokenURI: String, minter: Address) + access(all) event TokenURIUpdated(evmID: UInt256, newURI: String, updater: Address) + /// Account-only method to mint an NFT /// access(account) - fun mintNFT(id: UInt256, tokenURI: String): @{NonFungibleToken.NFT} + fun mintNFT(id: UInt256, tokenURI: String): @{NonFungibleToken.NFT} { + post { + emit Minted( + type: result.getType(), + id: result.id, + evmID: id, + tokenURI: tokenURI, + minter: self.account.address + ) + } + } /// Allows the bridge to update the URI of bridged NFTs. This assumes that the EVM-defining project may contain /// logic (onchain or offchain) which updates NFT metadata in the source ERC721 contract. On bridging, the URI can /// then be updated in this contract to reflect the source ERC721 contract's metadata. /// access(account) - fun updateTokenURI(evmID: UInt256, newURI: String) + fun updateTokenURI(evmID: UInt256, newURI: String) { + post { + emit TokenURIUpdated(evmID: evmID, newURI: newURI, updater: self.account.address) + } + } } diff --git a/cadence/contracts/bridge/IEVMBridgeTokenMinter.cdc b/cadence/contracts/bridge/IEVMBridgeTokenMinter.cdc new file mode 100644 index 00000000..90409063 --- /dev/null +++ b/cadence/contracts/bridge/IEVMBridgeTokenMinter.cdc @@ -0,0 +1,20 @@ +import "FungibleToken" + +/// Contract interface enabling FlowEVMBridge to mint fungible tokens from implementing bridge contracts. +/// +access(all) +contract interface IEVMBridgeTokenMinter { + + /// Emitted whenever tokens are minted, identifying the type, amount, and minter + access(all) event Minted(type: Type, amount: UFix64, minter: Address) + + /// Account-only method to mint a fungible token of the specified amount. + /// + access(account) + fun mintTokens(amount: UFix64): @{FungibleToken.Vault} { + post { + result.balance == amount: "Result does not contained specified amount" + emit Minted(type: result.getType(), amount: amount, minter: self.account.address) + } + } +} diff --git a/cadence/contracts/bridge/IFlowEVMNFTBridge.cdc b/cadence/contracts/bridge/IFlowEVMNFTBridge.cdc index 11516b37..d6fea52c 100644 --- a/cadence/contracts/bridge/IFlowEVMNFTBridge.cdc +++ b/cadence/contracts/bridge/IFlowEVMNFTBridge.cdc @@ -91,7 +91,7 @@ access(all) contract interface IFlowEVMNFTBridge { /// /// @returns The bridged NFT /// - access(all) + access(account) fun bridgeNFTFromEVM( owner: EVM.EVMAddress, type: Type, diff --git a/cadence/contracts/bridge/IFlowEVMTokenBridge.cdc b/cadence/contracts/bridge/IFlowEVMTokenBridge.cdc new file mode 100644 index 00000000..b6e87540 --- /dev/null +++ b/cadence/contracts/bridge/IFlowEVMTokenBridge.cdc @@ -0,0 +1,109 @@ +import "FungibleToken" +import "NonFungibleToken" + +import "EVM" + +import "FlowEVMBridgeUtils" + +access(all) contract interface IFlowEVMTokenBridge { + + /************* + Events + **************/ + + /// Broadcasts fungible tokens were bridged from Cadence to EVM + access(all) + event BridgedTokensToEVM( + type: Type, + amount: UFix64, + to: String, + evmContractAddress: String, + bridgeAddress: Address + ) + /// Broadcasts fungible tokens were bridged from EVM to Cadence + access(all) + event BridgedTokensFromEVM( + type: Type, + amount: UInt256, + caller: String, + evmContractAddress: String, + bridgeAddress: Address + ) + + /************** + Getters + ***************/ + + /// Returns the EVM address associated with the provided type + /// + access(all) + view fun getAssociatedEVMAddress(with type: Type): EVM.EVMAddress? + + /// Returns the EVM address of the bridge coordinating COA + /// + access(all) + view fun getBridgeCOAEVMAddress(): EVM.EVMAddress + + /******************************** + Public Bridge Entrypoints + *********************************/ + + /// Public entrypoint to bridge fungible tokens from Cadence to EVM. + /// + /// @param token: The token Vault to be bridged + /// @param to: The token recipient in EVM + /// @param feeProvider: A reference to a FungibleToken Provider from which the bridging fee is withdrawn in $FLOW + /// + access(all) + fun bridgeTokensToEVM( + vault: @{FungibleToken.Vault}, + to: EVM.EVMAddress, + feeProvider: auth(FungibleToken.Withdraw) &{FungibleToken.Provider} + ) { + pre { + emit BridgedTokensToEVM( + type: vault.getType(), + amount: vault.balance, + to: FlowEVMBridgeUtils.getEVMAddressAsHexString(address: to), + evmContractAddress: FlowEVMBridgeUtils.getEVMAddressAsHexString( + address: self.getAssociatedEVMAddress(with: vault.getType()) + ?? panic("Could not find EVM Contract address associated with provided NFT") + ), bridgeAddress: self.account.address + ) + } + } + + /// Public entrypoint to bridge fungible tokens from EVM to Cadence + /// + /// @param owner: The EVM address of the token owner. Current ownership and successful transfer (via + /// `protectedTransferCall`) is validated before the bridge request is executed. + /// @param calldata: Caller-provided approve() call, enabling contract COA to operate on NFT in EVM contract + /// @param amount: The amount of tokens to bridge from EVM to Cadence + /// @param evmContractAddress: Address of the EVM address defining the NFT being bridged - also call target + /// @param feeProvider: A reference to a FungibleToken Provider from which the bridging fee is withdrawn in $FLOW + /// @param protectedTransferCall: A function that executes the transfer of the NFT from the named owner to the + /// bridge's COA. This function is expected to return a Result indicating the status of the transfer call. + /// + /// @returns The bridged NFT + /// + access(account) + fun bridgeTokensFromEVM( + owner: EVM.EVMAddress, + type: Type, + amount: UInt256, + feeProvider: auth(FungibleToken.Withdraw) &{FungibleToken.Provider}, + protectedTransferCall: fun (): EVM.Result + ): @{FungibleToken.Vault} { + post { + emit BridgedTokensFromEVM( + type: result.getType(), + amount: amount, + caller: FlowEVMBridgeUtils.getEVMAddressAsHexString(address: owner), + evmContractAddress: FlowEVMBridgeUtils.getEVMAddressAsHexString( + address: self.getAssociatedEVMAddress(with: result.getType()) + ?? panic("Could not find EVM Contract address associated with provided Vault") + ), bridgeAddress: self.account.address + ) + } + } +} \ No newline at end of file diff --git a/cadence/contracts/example-assets/ExampleToken.cdc b/cadence/contracts/example-assets/ExampleToken.cdc new file mode 100644 index 00000000..91415bad --- /dev/null +++ b/cadence/contracts/example-assets/ExampleToken.cdc @@ -0,0 +1,223 @@ +import "FungibleToken" +import "MetadataViews" +import "FungibleTokenMetadataViews" + +access(all) contract ExampleToken: FungibleToken { + + /// The event that is emitted when new tokens are minted + access(all) event TokensMinted(amount: UFix64, type: String) + + /// Total supply of ExampleTokens in existence + access(all) var totalSupply: UFix64 + + /// Storage and Public Paths + access(all) let VaultStoragePath: StoragePath + access(all) let VaultPublicPath: PublicPath + access(all) let ReceiverPublicPath: PublicPath + access(all) let AdminStoragePath: StoragePath + + access(all) view fun getContractViews(resourceType: Type?): [Type] { + return [ + Type(), + Type(), + Type(), + Type() + ] + } + + access(all) fun resolveContractView(resourceType: Type?, viewType: Type): AnyStruct? { + switch viewType { + case Type(): + return FungibleTokenMetadataViews.FTView( + ftDisplay: self.resolveContractView(resourceType: nil, viewType: Type()) as! FungibleTokenMetadataViews.FTDisplay?, + ftVaultData: self.resolveContractView(resourceType: nil, viewType: Type()) as! FungibleTokenMetadataViews.FTVaultData? + ) + case Type(): + let media = MetadataViews.Media( + file: MetadataViews.HTTPFile( + url: "https://assets.website-files.com/5f6294c0c7a8cdd643b1c820/5f6294c0c7a8cda55cb1c936_Flow_Wordmark.svg" + ), + mediaType: "image/svg+xml" + ) + let medias = MetadataViews.Medias([media]) + return FungibleTokenMetadataViews.FTDisplay( + name: "Example Fungible Token", + symbol: "EFT", + description: "This fungible token is used as an example to help you develop your next FT #onFlow.", + externalURL: MetadataViews.ExternalURL("https://example-ft.onflow.org"), + logos: medias, + socials: { + "twitter": MetadataViews.ExternalURL("https://twitter.com/flow_blockchain") + } + ) + case Type(): + return FungibleTokenMetadataViews.FTVaultData( + storagePath: /storage/exampleTokenVault, + receiverPath: /public/exampleTokenReceiver, + metadataPath: /public/exampleTokenVault, + receiverLinkedType: Type<&ExampleToken.Vault>(), + metadataLinkedType: Type<&ExampleToken.Vault>(), + createEmptyVaultFunction: (fun(): @{FungibleToken.Vault} { + return <-ExampleToken.createEmptyVault(vaultType: Type<@ExampleToken.Vault>()) + }) + ) + case Type(): + return FungibleTokenMetadataViews.TotalSupply( + totalSupply: ExampleToken.totalSupply + ) + } + return nil + } + + /// Vault + /// + /// Each user stores an instance of only the Vault in their storage + /// The functions in the Vault and governed by the pre and post conditions + /// in FungibleToken when they are called. + /// The checks happen at runtime whenever a function is called. + /// + /// Resources can only be created in the context of the contract that they + /// are defined in, so there is no way for a malicious user to create Vaults + /// out of thin air. A special Minter resource needs to be defined to mint + /// new tokens. + /// + access(all) resource Vault: FungibleToken.Vault { + + /// The total balance of this vault + access(all) var balance: UFix64 + + // initialize the balance at resource creation time + init(balance: UFix64) { + self.balance = balance + } + + /// Called when a fungible token is burned via the `Burner.burn()` method + access(contract) fun burnCallback() { + if self.balance > 0.0 { + ExampleToken.totalSupply = ExampleToken.totalSupply - self.balance + } + self.balance = 0.0 + } + + access(all) view fun getViews(): [Type] { + return ExampleToken.getContractViews(resourceType: nil) + } + + access(all) fun resolveView(_ view: Type): AnyStruct? { + return ExampleToken.resolveContractView(resourceType: nil, viewType: view) + } + + /// getSupportedVaultTypes optionally returns a list of vault types that this receiver accepts + access(all) view fun getSupportedVaultTypes(): {Type: Bool} { + let supportedTypes: {Type: Bool} = {} + supportedTypes[self.getType()] = true + return supportedTypes + } + + access(all) view fun isSupportedVaultType(type: Type): Bool { + return self.getSupportedVaultTypes()[type] ?? false + } + + /// Asks if the amount can be withdrawn from this vault + access(all) view fun isAvailableToWithdraw(amount: UFix64): Bool { + return amount <= self.balance + } + + /// withdraw + /// + /// Function that takes an amount as an argument + /// and withdraws that amount from the Vault. + /// + /// It creates a new temporary Vault that is used to hold + /// the tokens that are being transferred. It returns the newly + /// created Vault to the context that called so it can be deposited + /// elsewhere. + /// + access(FungibleToken.Withdraw) fun withdraw(amount: UFix64): @ExampleToken.Vault { + self.balance = self.balance - amount + return <-create Vault(balance: amount) + } + + /// deposit + /// + /// Function that takes a Vault object as an argument and adds + /// its balance to the balance of the owners Vault. + /// + /// It is allowed to destroy the sent Vault because the Vault + /// was a temporary holder of the tokens. The Vault's balance has + /// been consumed and therefore can be destroyed. + /// + access(all) fun deposit(from: @{FungibleToken.Vault}) { + let vault <- from as! @ExampleToken.Vault + self.balance = self.balance + vault.balance + vault.balance = 0.0 + destroy vault + } + + /// createEmptyVault + /// + /// Function that creates a new Vault with a balance of zero + /// and returns it to the calling context. A user must call this function + /// and store the returned Vault in their storage in order to allow their + /// account to be able to receive deposits of this token type. + /// + access(all) fun createEmptyVault(): @ExampleToken.Vault { + return <-create Vault(balance: 0.0) + } + } + + /// Minter + /// + /// Resource object that token admin accounts can hold to mint new tokens. + /// + access(all) resource Minter { + /// mintTokens + /// + /// Function that mints new tokens, adds them to the total supply, + /// and returns them to the calling context. + /// + access(all) fun mintTokens(amount: UFix64): @ExampleToken.Vault { + ExampleToken.totalSupply = ExampleToken.totalSupply + amount + emit TokensMinted(amount: amount, type: self.getType().identifier) + return <-create Vault(balance: amount) + } + } + + /// createEmptyVault + /// + /// Function that creates a new Vault with a balance of zero + /// and returns it to the calling context. A user must call this function + /// and store the returned Vault in their storage in order to allow their + /// account to be able to receive deposits of this token type. + /// + access(all) fun createEmptyVault(vaultType: Type): @ExampleToken.Vault { + return <- create Vault(balance: 0.0) + } + + init() { + self.totalSupply = 1000.0 + + self.VaultStoragePath = /storage/exampleTokenVault + self.VaultPublicPath = /public/exampleTokenVault + self.ReceiverPublicPath = /public/exampleTokenReceiver + self.AdminStoragePath = /storage/exampleTokenAdmin + + // Create the Vault with the total supply of tokens and save it in storage + // + let vault <- create Vault(balance: self.totalSupply) + + // Create a public capability to the stored Vault that exposes + // the `deposit` method and getAcceptedTypes method through the `Receiver` interface + // and the `balance` method through the `Balance` interface + // + let exampleTokenCap = self.account.capabilities.storage.issue<&ExampleToken.Vault>(self.VaultStoragePath) + self.account.capabilities.publish(exampleTokenCap, at: self.VaultPublicPath) + let receiverCap = self.account.capabilities.storage.issue<&ExampleToken.Vault>(self.VaultStoragePath) + self.account.capabilities.publish(receiverCap, at: self.ReceiverPublicPath) + + self.account.storage.save(<-vault, to: /storage/exampleTokenVault) + + let admin <- create Minter() + self.account.storage.save(<-admin, to: self.AdminStoragePath) + } +} \ No newline at end of file diff --git a/cadence/contracts/standards/EVM.cdc b/cadence/contracts/standards/EVM.cdc index 4b2cf897..e6e89677 100644 --- a/cadence/contracts/standards/EVM.cdc +++ b/cadence/contracts/standards/EVM.cdc @@ -1,7 +1,7 @@ import Crypto -import "NonFungibleToken" -import "FungibleToken" -import "FlowToken" +import NonFungibleToken from 0x0000000000000001 +import FungibleToken from 0x0000000000000002 +import FlowToken from 0x0000000000000003 access(all) contract EVM { @@ -17,6 +17,18 @@ contract EVM { access(all) event CadenceOwnedAccountCreated(addressBytes: [UInt8; 20]) + /// FLOWTokensDeposited is emitted when FLOW tokens is bridged + /// into the EVM environment. Note that this event is not emitted + /// for transfer of flow tokens between two EVM addresses. + access(all) + event FLOWTokensDeposited(addressBytes: [UInt8; 20], amount: UFix64) + + /// FLOWTokensWithdrawn is emitted when FLOW tokens are bridged + /// out of the EVM environment. Note that this event is not emitted + /// for transfer of flow tokens between two EVM addresses. + access(all) + event FLOWTokensWithdrawn(addressBytes: [UInt8; 20], amount: UFix64) + /// EVMAddress is an EVM-compatible address access(all) struct EVMAddress { @@ -38,6 +50,44 @@ contract EVM { ) return Balance(attoflow: balance) } + + /// Nonce of the address + access(all) + fun nonce(): UInt64 { + return InternalEVM.nonce( + address: self.bytes + ) + } + + /// Code of the address + access(all) + fun code(): [UInt8] { + return InternalEVM.code( + address: self.bytes + ) + } + + /// CodeHash of the address + access(all) + fun codeHash(): [UInt8] { + return InternalEVM.codeHash( + address: self.bytes + ) + } + + /// Deposits the given vault into the EVM account with the given address + access(all) + fun deposit(from: @FlowToken.Vault) { + let amount = from.balance + if amount == 0.0 { + panic("calling deposit function with an empty vault is not allowed") + } + InternalEVM.deposit( + from: <-from, + to: self.bytes + ) + emit FLOWTokensDeposited(addressBytes: self.bytes, amount: amount) + } } access(all) @@ -77,6 +127,12 @@ contract EVM { view fun inAttoFLOW(): UInt { return self.attoflow } + + /// Returns true if the balance is zero + access(all) + fun isZero(): Bool { + return self.attoflow == 0 + } } /// reports the status of evm execution. @@ -187,10 +243,7 @@ contract EVM { /// Deposits the given vault into the cadence owned account's balance access(all) fun deposit(from: @FlowToken.Vault) { - InternalEVM.deposit( - from: <-from, - to: self.addressBytes - ) + self.address().deposit(from: <-from) } /// The EVM address of the cadence owned account behind an entitlement, acting as proof of access @@ -206,10 +259,14 @@ contract EVM { /// rounding error, this function would fail. access(Owner | Withdraw) fun withdraw(balance: Balance): @FlowToken.Vault { + if balance.isZero() { + panic("calling withdraw function with zero balance is not allowed") + } let vault <- InternalEVM.withdraw( from: self.addressBytes, amount: balance.attoflow ) as! @FlowToken.Vault + emit FLOWTokensWithdrawn(addressBytes: self.addressBytes, amount: balance.inFLOW()) return <-vault } @@ -258,8 +315,8 @@ contract EVM { EVM.borrowBridgeAccessor().depositNFT(nft: <-nft, to: self.address(), feeProvider: feeProvider) } - /// Bridges the given NFT to the EVM environment, requiring a Provider from which to withdraw a fee to fulfill - /// the bridge request + /// Bridges the given NFT from the EVM environment, requiring a Provider from which to withdraw a fee to fulfill + /// the bridge request. Note: the caller should own the requested NFT in EVM access(Owner | Bridge) fun withdrawNFT( type: Type, @@ -273,6 +330,33 @@ contract EVM { feeProvider: feeProvider ) } + + /// Bridges the given Vault to the EVM environment, requiring a Provider from which to withdraw a fee to fulfill + /// the bridge request + access(all) + fun depositTokens( + vault: @{FungibleToken.Vault}, + feeProvider: auth(FungibleToken.Withdraw) &{FungibleToken.Provider} + ) { + EVM.borrowBridgeAccessor().depositTokens(vault: <-vault, to: self.address(), feeProvider: feeProvider) + } + + /// Bridges the given fungible tokens from the EVM environment, requiring a Provider from which to withdraw a + /// fee to fulfill the bridge request. Note: the caller should own the requested tokens & sufficient balance of + /// requested tokens in EVM + access(Owner | Bridge) + fun withdrawTokens( + type: Type, + amount: UInt256, + feeProvider: auth(FungibleToken.Withdraw) &{FungibleToken.Provider} + ): @{FungibleToken.Vault} { + return <- EVM.borrowBridgeAccessor().withdrawTokens( + caller: &self as auth(Call) &CadenceOwnedAccount, + type: type, + amount: amount, + feeProvider: feeProvider + ) + } } /// Creates a new cadence owned account @@ -424,7 +508,6 @@ contract EVM { } let coaRef = acc.capabilities.borrow<&EVM.CadenceOwnedAccount>(path) - if coaRef == nil { return ValidationResult( isValid: false, @@ -449,26 +532,44 @@ contract EVM { ) } - /// Returns a reference to the BridgeAccessor designated for internal bridge requests - access(self) - view fun borrowBridgeAccessor(): auth(Bridge) &{BridgeAccessor} { - return self.account.storage.borrow(from: /storage/evmBridgeRouter) - ?? panic("Could not borrow reference to the EVM bridge") + /// Block returns information about the latest executed block. + access(all) + struct EVMBlock { + access(all) + let height: UInt64 + + access(all) + let hash: String + + access(all) + let totalSupply: Int + + init(height: UInt64, hash: String, totalSupply: Int) { + self.height = height + self.hash = hash + self.totalSupply = totalSupply + } + } + + /// Returns the latest executed block. + access(all) + fun getLatestBlock(): EVMBlock { + return InternalEVM.getLatestBlock() as! EVMBlock } /// Interface for a resource which acts as an entrypoint to the VM bridge access(all) resource interface BridgeAccessor { - /// Endpoint enabling the briding of an NFT to EVM + /// Endpoint enabling the bridging of an NFT to EVM access(Bridge) fun depositNFT( nft: @{NonFungibleToken.NFT}, - to: EVM.EVMAddress, + to: EVMAddress, feeProvider: auth(FungibleToken.Withdraw) &{FungibleToken.Provider} ) - /// Endpoint enabling the briding of an NFT from EVM + /// Endpoint enabling the bridging of an NFT from EVM access(Bridge) fun withdrawNFT( caller: auth(Call) &CadenceOwnedAccount, @@ -476,5 +577,38 @@ contract EVM { id: UInt256, feeProvider: auth(FungibleToken.Withdraw) &{FungibleToken.Provider} ): @{NonFungibleToken.NFT} + + /// Endpoint enabling the bridging of a fungible token vault to EVM + access(Bridge) + fun depositTokens( + vault: @{FungibleToken.Vault}, + to: EVMAddress, + feeProvider: auth(FungibleToken.Withdraw) &{FungibleToken.Provider} + ) + + /// Endpoint enabling the bridging of fungible tokens from EVM + access(Bridge) + fun withdrawTokens( + caller: auth(Call) &CadenceOwnedAccount, + type: Type, + amount: UInt256, + feeProvider: auth(FungibleToken.Withdraw) &{FungibleToken.Provider} + ): @{FungibleToken.Vault} + } + + /// Interface which captures a Capability to the bridge Accessor, saving it within the BridgeRouter resource + access(all) + resource interface BridgeRouter { + + /// Returns a reference to the BridgeAccessor designated for internal bridge requests + access(Bridge) view fun borrowBridgeAccessor(): auth(Bridge) &{BridgeAccessor} + } + + /// Returns a reference to the BridgeAccessor designated for internal bridge requests + access(self) + view fun borrowBridgeAccessor(): auth(Bridge) &{BridgeAccessor} { + return self.account.storage.borrow(from: /storage/evmBridgeRouter) + ?.borrowBridgeAccessor() + ?? panic("Could not borrow reference to the EVM bridge") } } diff --git a/cadence/contracts/templates/emulator/EVMBridgedNFTTemplate.cdc b/cadence/contracts/templates/emulator/EVMBridgedNFTTemplate.cdc index 3e734906..09f8a36d 100644 --- a/cadence/contracts/templates/emulator/EVMBridgedNFTTemplate.cdc +++ b/cadence/contracts/templates/emulator/EVMBridgedNFTTemplate.cdc @@ -20,14 +20,13 @@ import CrossVMNFT from 0xf8d6e0586b0a20c7 /// prepared as chunks in FlowEVMBridgeTemplates before being deployed to the Flow EVM Bridge account. /// /// On bridging, the ERC721 is transferred to the bridge's CadenceOwnedAccount EVM address and a new NFT is minted from -/// this contract to the bridging caller. On return to Flow EVM, the reverse process is followed - the token is burned -/// in this contract and the ERC721 is transferred to the defined recipient. In this way, the Cadence token acts as a +/// this contract to the bridging caller. On return to Flow EVM, the reverse process is followed - the token is locked +/// in NFT escrow and the ERC721 is transferred to the defined recipient. In this way, the Cadence token acts as a /// representation of both the EVM NFT and thus ownership rights to it upon bridging back to Flow EVM. /// -/// To bridge between VMs, a caller can either use the contract methods defined below, or use the FlowEVMBridge's -/// bridging methods which will programatically route bridging calls to this contract. +/// To bridge between VMs, a caller can either use the interface exposed on CadenceOwnedAccount or use FlowEVMBridge +/// public contract methods. /// -// TODO: Implement NFT contract interface once v2 available locally access(all) contract {{CONTRACT_NAME}} : ICrossVM, IEVMBridgeNFTMinter, NonFungibleToken { /// Pointer to the Factory deployed Solidity contract address defining the bridged asset @@ -47,26 +46,18 @@ access(all) contract {{CONTRACT_NAME}} : ICrossVM, IEVMBridgeNFTMinter, NonFungi /// The NFT resource representing the bridged ERC721 token /// - access(all) resource NFT: CrossVMNFT.EVMNFT { + access(all) resource NFT : CrossVMNFT.EVMNFT { /// The Cadence ID of the NFT access(all) let id: UInt64 /// The ERC721 ID of the NFT access(all) let evmID: UInt256 - /// The name of the NFT as defined in the ERC721 contract - access(all) let name: String - /// The symbol of the NFT as defined in the ERC721 contract - access(all) let symbol: String /// Additional onchain metadata access(all) let metadata: {String: AnyStruct} init( - name: String, - symbol: String, evmID: UInt256, metadata: {String: AnyStruct} ) { - self.name = name - self.symbol = symbol self.id = self.uuid self.evmID = evmID self.metadata = metadata @@ -82,6 +73,18 @@ access(all) contract {{CONTRACT_NAME}} : ICrossVM, IEVMBridgeNFTMinter, NonFungi ] } + access(all) view fun getName(): String { + return {{CONTRACT_NAME}}.name + } + + access(all) view fun getSymbol(): String { + return {{CONTRACT_NAME}}.symbol + } + + access(all) view fun tokenURI(): String { + return {{CONTRACT_NAME}}.tokenURIs[self.evmID] ?? "" + } + /// Resolves a metadata view for this NFT access(all) fun resolveView(_ view: Type): AnyStruct? { switch view { @@ -89,8 +92,8 @@ access(all) contract {{CONTRACT_NAME}} : ICrossVM, IEVMBridgeNFTMinter, NonFungi // with the URI as thumbnail - we may a new standard view for EVM NFTs - this is interim case Type(): return CrossVMNFT.EVMBridgedMetadata( - name: self.name, - symbol: self.symbol, + name: self.getName(), + symbol: self.getSymbol(), uri: CrossVMNFT.URI(baseURI: nil, value: self.tokenURI()) ) case Type(): @@ -122,15 +125,10 @@ access(all) contract {{CONTRACT_NAME}} : ICrossVM, IEVMBridgeNFTMinter, NonFungi access(all) view fun getEVMContractAddress(): EVM.EVMAddress { return {{CONTRACT_NAME}}.getEVMContractAddress() } - - /// Similar to ERC721.tokenURI method, returns the URI of the NFT with self.evmID at time of bridging - access(all) view fun tokenURI(): String { - return {{CONTRACT_NAME}}.tokenURIs[self.evmID] ?? "" - } } /// This resource holds associated NFTs, and serves queries about stored NFTs - access(all) resource Collection: NonFungibleToken.Collection, CrossVMNFT.EVMNFTCollection { + access(all) resource Collection : CrossVMNFT.EVMNFTCollection { /// dictionary of NFT conforming tokens indexed on their ID access(contract) var ownedNFTs: @{UInt64: {{CONTRACT_NAME}}.NFT} /// Mapping of EVM IDs to Flow NFT IDs @@ -151,6 +149,14 @@ access(all) contract {{CONTRACT_NAME}} : ICrossVM, IEVMBridgeNFTMinter, NonFungi self.publicPath = collectionData.publicPath } + access(all) view fun getName(): String { + return {{CONTRACT_NAME}}.name + } + + access(all) view fun getSymbol(): String { + return {{CONTRACT_NAME}}.symbol + } + /// Returns a list of NFT types that this receiver accepts access(all) view fun getSupportedNFTTypes(): {Type: Bool} { return { Type<@{{CONTRACT_NAME}}.NFT>(): true } @@ -171,11 +177,10 @@ access(all) contract {{CONTRACT_NAME}} : ICrossVM, IEVMBridgeNFTMinter, NonFungi } /// Withdraws an NFT from the collection by its EVM ID - access(NonFungibleToken.Withdraw | NonFungibleToken.Owner) fun withdrawByEVMID(_ id: UInt64): @{NonFungibleToken.NFT} { - let token <- self.ownedNFTs.remove(key: id) - ?? panic("Could not withdraw an NFT with the provided ID from the collection") - - return <-token + access(NonFungibleToken.Withdraw | NonFungibleToken.Owner) fun withdrawByEVMID(_ id: UInt256): @{NonFungibleToken.NFT} { + return <- self.withdraw(withdrawID: + self.getCadenceID(from: id) ?? panic("Could not withdraw an NFT with the provided EVM ID from the collection") + ) } /// Ttakes a NFT and adds it to the collections dictionary and adds the ID to the evmIDToFlowID mapping @@ -337,8 +342,6 @@ access(all) contract {{CONTRACT_NAME}} : ICrossVM, IEVMBridgeNFTMinter, NonFungi } self.tokenURIs[id] = tokenURI return <-create NFT( - name: self.name, - symbol: self.symbol, evmID: id, metadata: { "Bridged Block": getCurrentBlock().height, @@ -372,6 +375,8 @@ access(all) contract {{CONTRACT_NAME}} : ICrossVM, IEVMBridgeNFTMinter, NonFungi FlowEVMBridgeConfig.associateType(Type<@{{CONTRACT_NAME}}.NFT>(), with: self.evmNFTContractAddress) FlowEVMBridgeNFTEscrow.initializeEscrow( forType: Type<@{{CONTRACT_NAME}}.NFT>(), + name: name, + symbol: symbol, erc721Address: self.evmNFTContractAddress ) } diff --git a/cadence/contracts/templates/emulator/EVMBridgedTokenTemplate.cdc b/cadence/contracts/templates/emulator/EVMBridgedTokenTemplate.cdc new file mode 100644 index 00000000..b28503ee --- /dev/null +++ b/cadence/contracts/templates/emulator/EVMBridgedTokenTemplate.cdc @@ -0,0 +1,271 @@ +import NonFungibleToken from 0xf8d6e0586b0a20c7 +import MetadataViews from 0xf8d6e0586b0a20c7 +import FungibleTokenMetadataViews from 0xf8d6e0586b0a20c7 +import ViewResolver from 0xf8d6e0586b0a20c7 +import FungibleToken from 0xee82856bf20e2aa6 +import FlowToken from 0x0ae53cb6e3f42a79 + +import EVM from 0xf8d6e0586b0a20c7 + +import ICrossVM from 0xf8d6e0586b0a20c7 +import IEVMBridgeTokenMinter from 0xf8d6e0586b0a20c7 +import FlowEVMBridgeTokenEscrow from 0xf8d6e0586b0a20c7 +import FlowEVMBridgeConfig from 0xf8d6e0586b0a20c7 +import FlowEVMBridgeUtils from 0xf8d6e0586b0a20c7 +import FlowEVMBridge from 0xf8d6e0586b0a20c7 +import CrossVMNFT from 0xf8d6e0586b0a20c7 +import CrossVMToken from 0xf8d6e0586b0a20c7 + +/// This contract is a template used by FlowEVMBridge to define EVM-native fungible tokens bridged from Flow EVM to +/// Cadence. Upon deployment of this contract, the contract name is derived as a function of the asset type (here an +/// ERC20) and the contract's EVM address. The derived contract name is then joined with this contract's code, +/// prepared as chunks in FlowEVMBridgeTemplates before being deployed to the Flow EVM Bridge account. +/// +/// On bridging, the ERC20 is transferred to the bridge's CadenceOwnedAccount EVM address and tokens are minted from +/// this contract to the bridging caller. On return to Flow EVM, the reverse process is followed - the token is burned +/// in this contract and the ERC20 is transferred to the defined recipient. In this way, the Cadence Vault acts as a +/// representation of both the EVM tokens and thus ownership rights to it upon bridging back to Flow EVM. +/// +/// To bridge between VMs, a caller can either use the interface exposed on CadenceOwnedAccount or use FlowEVMBridge +/// public contract methods. +/// +access(all) contract {{CONTRACT_NAME}} : ICrossVM, IEVMBridgeTokenMinter, FungibleToken { + + /// Pointer to the Factory deployed Solidity contract address defining the bridged asset + access(all) let evmTokenContractAddress: EVM.EVMAddress + /// Name of the fungible token defined in the corresponding ERC20 contract + access(all) let name: String + /// Symbol of the fungible token defined in the corresponding ERC20 contract + access(all) let symbol: String + /// Decimal place value defined in the source ERC20 contract + access(all) let decimals: UInt8 + /// URI of the contract, if available as a var in case the bridge enables cross-VM Metadata syncing in the future + access(all) var contractURI: String? + /// Total supply of this Cadence token in circulation + /// NOTE: This does not reflect the total supply of the source ERC20 in circulation within EVM + access(all) var totalSupply: UFix64 + /// Retain a Vault to reference when resolving Vault Metadata + access(self) let vault: @Vault + + /// The Vault resource representing the bridged ERC20 token + /// + access(all) resource Vault : CrossVMToken.EVMTokenInfo, FungibleToken.Vault { + /// Balance of the tokens in a given Vault + access(all) var balance: UFix64 + + init(balance: UFix64) { + self.balance = balance + } + + /* --- CrossVMToken.EVMFTVault conformance --- */ + // + /// Gets the ERC20 name value + access(all) view fun getName(): String { + return {{CONTRACT_NAME}}.name + } + /// Gets the ERC20 symbol value + access(all) view fun getSymbol(): String { + return {{CONTRACT_NAME}}.symbol + } + /// Gets the ERC20 decimals value + access(all) view fun getDecimals(): UInt8 { + return {{CONTRACT_NAME}}.decimals + } + /// Returns the EVM contract address of the fungible token + access(all) view fun getEVMContractAddress(): EVM.EVMAddress { + return {{CONTRACT_NAME}}.getEVMContractAddress() + } + + access(all) view fun getViews(): [Type] { + return {{CONTRACT_NAME}}.getContractViews(resourceType: nil) + } + + access(all) fun resolveView(_ view: Type): AnyStruct? { + return {{CONTRACT_NAME}}.resolveContractView(resourceType: nil, viewType: view) + } + + /// getSupportedVaultTypes optionally returns a list of vault types that this receiver accepts + access(all) view fun getSupportedVaultTypes(): {Type: Bool} { + return { self.getType(): true } + } + + access(all) view fun isSupportedVaultType(type: Type): Bool { + return self.getSupportedVaultTypes()[type] ?? false + } + + /// Asks if the amount can be withdrawn from this vault + access(all) view fun isAvailableToWithdraw(amount: UFix64): Bool { + return amount <= self.balance + } + + /// deposit + /// + /// Function that takes a Vault object as an argument and adds + /// its balance to the balance of the owners Vault. + /// + /// It is allowed to destroy the sent Vault because the Vault + /// was a temporary holder of the tokens. The Vault's balance has + /// been consumed and therefore can be destroyed. + /// + access(all) fun deposit(from: @{FungibleToken.Vault}) { + let vault <- from as! @Vault + self.balance = self.balance + vault.balance + vault.balance = 0.0 + destroy vault + } + + /// createEmptyVault + /// + /// Function that creates a new Vault with a balance of zero + /// and returns it to the calling context. A user must call this function + /// and store the returned Vault in their storage in order to allow their + /// account to be able to receive deposits of this token type. + /// + access(all) fun createEmptyVault(): @Vault { + return <-create Vault(balance: 0.0) + } + + /// withdraw + /// + /// Function that takes an amount as an argument + /// and withdraws that amount from the Vault. + /// + /// It creates a new temporary Vault that is used to hold + /// the tokens that are being transferred. It returns the newly + /// created Vault to the context that called so it can be deposited + /// elsewhere. + /// + access(FungibleToken.Withdraw) fun withdraw(amount: UFix64): @Vault { + self.balance = self.balance - amount + return <-create Vault(balance: amount) + } + + /// Called when a fungible token is burned via the `Burner.burn()` method + access(contract) fun burnCallback() { + if self.balance > 0.0 { + {{CONTRACT_NAME}}.totalSupply = {{CONTRACT_NAME}}.totalSupply - self.balance + } + self.balance = 0.0 + } + } + + /// createEmptyVault + /// + /// Function that creates a new Vault with a balance of zero and returns it to the calling context. A user must call + /// this function and store the returned Vault in their storage in order to allow their account to be able to + /// receive deposits of this token type. + /// + access(all) fun createEmptyVault(vaultType: Type): @{{CONTRACT_NAME}}.Vault { + return <- create Vault(balance: 0.0) + } + + /********************** + Getters + ***********************/ + + /// Returns the EVM contract address of the fungible token this contract represents + /// + access(all) view fun getEVMContractAddress(): EVM.EVMAddress { + return self.evmTokenContractAddress + } + + /// Function that returns all the Metadata Views implemented by this fungible token contract. + /// + /// @return An array of Types defining the implemented views. This value will be used by + /// developers to know which parameter to pass to the resolveView() method. + /// + access(all) view fun getContractViews(resourceType: Type?): [Type] { + return [ + Type(), + Type(), + Type(), + Type(), + Type() + ] + } + + /// Function that resolves a metadata view for this contract. + /// + /// @param view: The Type of the desired view. + /// + /// @return A structure representing the requested view. + /// + access(all) fun resolveContractView(resourceType: Type?, viewType: Type): AnyStruct? { + switch viewType { + case Type(): + return FungibleTokenMetadataViews.FTView( + ftDisplay: self.resolveContractView(resourceType: nil, viewType: Type()) as! FungibleTokenMetadataViews.FTDisplay?, + ftVaultData: self.resolveContractView(resourceType: nil, viewType: Type()) as! FungibleTokenMetadataViews.FTVaultData? + ) + case Type(): + let media = MetadataViews.Media( + file: MetadataViews.HTTPFile( + url: "https://assets.website-files.com/5f6294c0c7a8cdd643b1c820/5f6294c0c7a8cda55cb1c936_Flow_Wordmark.svg" + ), + mediaType: "image/svg+xml" + ) + let medias = MetadataViews.Medias([media]) + return FungibleTokenMetadataViews.FTDisplay( + // TODO: Decide on how we want to represent bridged token media + name: self.name, + symbol: self.symbol, + description: "This fungible token was bridged from Flow EVM.", + externalURL: MetadataViews.ExternalURL("https://bridge.flow.com/fungible-token"), + logos: medias, + socials: {} + ) + case Type(): + return FungibleTokenMetadataViews.FTVaultData( + storagePath: /storage/{{CONTRACT_NAME}}Vault, + receiverPath: /public/{{CONTRACT_NAME}}Receiver, + metadataPath: /public/{{CONTRACT_NAME}}Vault, + receiverLinkedType: Type<&{{CONTRACT_NAME}}.Vault>(), + metadataLinkedType: Type<&{{CONTRACT_NAME}}.Vault>(), + createEmptyVaultFunction: (fun(): @{FungibleToken.Vault} { + return <-self.createEmptyVault(vaultType: Type<@{{CONTRACT_NAME}}.Vault>()) + }) + ) + case Type(): + return FungibleTokenMetadataViews.TotalSupply( + totalSupply: self.totalSupply + ) + case Type(): + return CrossVMNFT.EVMBridgedMetadata( + name: self.name, + symbol: self.symbol, + uri: self.contractURI != nil ? CrossVMNFT.URI(baseURI: nil, value: self.contractURI!) : CrossVMNFT.URI(baseURI: nil, value: "") + ) + } + return nil + } + + /********************** + Internal Methods + ***********************/ + + /// Allows the bridge to mint tokens from bridge-defined fungible token contracts + /// + access(account) fun mintTokens(amount: UFix64): @{FungibleToken.Vault} { + self.totalSupply = self.totalSupply + amount + return <- create Vault(balance: amount) + } + + init(name: String, symbol: String, decimals: UInt8, evmContractAddress: EVM.EVMAddress, contractURI: String?) { + self.evmTokenContractAddress = evmContractAddress + self.name = name + self.symbol = symbol + self.decimals = decimals + self.contractURI = contractURI + self.totalSupply = 0.0 + self.vault <- create Vault(balance: 0.0) + + FlowEVMBridgeConfig.associateType(Type<@{{CONTRACT_NAME}}.Vault>(), with: self.evmTokenContractAddress) + FlowEVMBridgeTokenEscrow.initializeEscrow( + with: <-create Vault(balance: 0.0), + name: name, + symbol: symbol, + decimals: decimals, + evmTokenAddress: self.evmTokenContractAddress + ) + } +} diff --git a/cadence/contracts/templates/testing/EVMBridgedNFTTemplate.cdc b/cadence/contracts/templates/testing/EVMBridgedNFTTemplate.cdc index e6f52428..86288041 100644 --- a/cadence/contracts/templates/testing/EVMBridgedNFTTemplate.cdc +++ b/cadence/contracts/templates/testing/EVMBridgedNFTTemplate.cdc @@ -20,14 +20,13 @@ import CrossVMNFT from 0x0000000000000007 /// prepared as chunks in FlowEVMBridgeTemplates before being deployed to the Flow EVM Bridge account. /// /// On bridging, the ERC721 is transferred to the bridge's CadenceOwnedAccount EVM address and a new NFT is minted from -/// this contract to the bridging caller. On return to Flow EVM, the reverse process is followed - the token is burned -/// in this contract and the ERC721 is transferred to the defined recipient. In this way, the Cadence token acts as a +/// this contract to the bridging caller. On return to Flow EVM, the reverse process is followed - the token is locked +/// in NFT escrow and the ERC721 is transferred to the defined recipient. In this way, the Cadence token acts as a /// representation of both the EVM NFT and thus ownership rights to it upon bridging back to Flow EVM. /// -/// To bridge between VMs, a caller can either use the contract methods defined below, or use the FlowEVMBridge's -/// bridging methods which will programatically route bridging calls to this contract. +/// To bridge between VMs, a caller can either use the interface exposed on CadenceOwnedAccount or use FlowEVMBridge +/// public contract methods. /// -// TODO: Implement NFT contract interface once v2 available locally access(all) contract {{CONTRACT_NAME}} : ICrossVM, IEVMBridgeNFTMinter, NonFungibleToken { /// Pointer to the Factory deployed Solidity contract address defining the bridged asset @@ -47,26 +46,18 @@ access(all) contract {{CONTRACT_NAME}} : ICrossVM, IEVMBridgeNFTMinter, NonFungi /// The NFT resource representing the bridged ERC721 token /// - access(all) resource NFT: CrossVMNFT.EVMNFT { + access(all) resource NFT : CrossVMNFT.EVMNFT { /// The Cadence ID of the NFT access(all) let id: UInt64 /// The ERC721 ID of the NFT access(all) let evmID: UInt256 - /// The name of the NFT as defined in the ERC721 contract - access(all) let name: String - /// The symbol of the NFT as defined in the ERC721 contract - access(all) let symbol: String /// Additional onchain metadata access(all) let metadata: {String: AnyStruct} init( - name: String, - symbol: String, evmID: UInt256, metadata: {String: AnyStruct} ) { - self.name = name - self.symbol = symbol self.id = self.uuid self.evmID = evmID self.metadata = metadata @@ -82,6 +73,18 @@ access(all) contract {{CONTRACT_NAME}} : ICrossVM, IEVMBridgeNFTMinter, NonFungi ] } + access(all) view fun getName(): String { + return {{CONTRACT_NAME}}.name + } + + access(all) view fun getSymbol(): String { + return {{CONTRACT_NAME}}.symbol + } + + access(all) view fun tokenURI(): String { + return {{CONTRACT_NAME}}.tokenURIs[self.evmID] ?? "" + } + /// Resolves a metadata view for this NFT access(all) fun resolveView(_ view: Type): AnyStruct? { switch view { @@ -89,8 +92,8 @@ access(all) contract {{CONTRACT_NAME}} : ICrossVM, IEVMBridgeNFTMinter, NonFungi // with the URI as thumbnail - we may a new standard view for EVM NFTs - this is interim case Type(): return CrossVMNFT.EVMBridgedMetadata( - name: self.name, - symbol: self.symbol, + name: self.getName(), + symbol: self.getSymbol(), uri: CrossVMNFT.URI(baseURI: nil, value: self.tokenURI()) ) case Type(): @@ -122,15 +125,10 @@ access(all) contract {{CONTRACT_NAME}} : ICrossVM, IEVMBridgeNFTMinter, NonFungi access(all) view fun getEVMContractAddress(): EVM.EVMAddress { return {{CONTRACT_NAME}}.getEVMContractAddress() } - - /// Similar to ERC721.tokenURI method, returns the URI of the NFT with self.evmID at time of bridging - access(all) view fun tokenURI(): String { - return {{CONTRACT_NAME}}.tokenURIs[self.evmID] ?? "" - } } /// This resource holds associated NFTs, and serves queries about stored NFTs - access(all) resource Collection: NonFungibleToken.Collection, CrossVMNFT.EVMNFTCollection { + access(all) resource Collection : CrossVMNFT.EVMNFTCollection { /// dictionary of NFT conforming tokens indexed on their ID access(contract) var ownedNFTs: @{UInt64: {{CONTRACT_NAME}}.NFT} /// Mapping of EVM IDs to Flow NFT IDs @@ -151,6 +149,14 @@ access(all) contract {{CONTRACT_NAME}} : ICrossVM, IEVMBridgeNFTMinter, NonFungi self.publicPath = collectionData.publicPath } + access(all) view fun getName(): String { + return {{CONTRACT_NAME}}.name + } + + access(all) view fun getSymbol(): String { + return {{CONTRACT_NAME}}.symbol + } + /// Returns a list of NFT types that this receiver accepts access(all) view fun getSupportedNFTTypes(): {Type: Bool} { return { Type<@{{CONTRACT_NAME}}.NFT>(): true } @@ -171,11 +177,10 @@ access(all) contract {{CONTRACT_NAME}} : ICrossVM, IEVMBridgeNFTMinter, NonFungi } /// Withdraws an NFT from the collection by its EVM ID - access(NonFungibleToken.Withdraw | NonFungibleToken.Owner) fun withdrawByEVMID(_ id: UInt64): @{NonFungibleToken.NFT} { - let token <- self.ownedNFTs.remove(key: id) - ?? panic("Could not withdraw an NFT with the provided ID from the collection") - - return <-token + access(NonFungibleToken.Withdraw | NonFungibleToken.Owner) fun withdrawByEVMID(_ id: UInt256): @{NonFungibleToken.NFT} { + return <- self.withdraw(withdrawID: + self.getCadenceID(from: id) ?? panic("Could not withdraw an NFT with the provided EVM ID from the collection") + ) } /// Ttakes a NFT and adds it to the collections dictionary and adds the ID to the evmIDToFlowID mapping @@ -337,8 +342,6 @@ access(all) contract {{CONTRACT_NAME}} : ICrossVM, IEVMBridgeNFTMinter, NonFungi } self.tokenURIs[id] = tokenURI return <-create NFT( - name: self.name, - symbol: self.symbol, evmID: id, metadata: { "Bridged Block": getCurrentBlock().height, @@ -372,6 +375,8 @@ access(all) contract {{CONTRACT_NAME}} : ICrossVM, IEVMBridgeNFTMinter, NonFungi FlowEVMBridgeConfig.associateType(Type<@{{CONTRACT_NAME}}.NFT>(), with: self.evmNFTContractAddress) FlowEVMBridgeNFTEscrow.initializeEscrow( forType: Type<@{{CONTRACT_NAME}}.NFT>(), + name: name, + symbol: symbol, erc721Address: self.evmNFTContractAddress ) } diff --git a/cadence/contracts/templates/testing/EVMBridgedTokenTemplate.cdc b/cadence/contracts/templates/testing/EVMBridgedTokenTemplate.cdc new file mode 100644 index 00000000..b69ab766 --- /dev/null +++ b/cadence/contracts/templates/testing/EVMBridgedTokenTemplate.cdc @@ -0,0 +1,271 @@ +import NonFungibleToken from 0x0000000000000001 +import MetadataViews from 0x0000000000000001 +import FungibleTokenMetadataViews from 0x0000000000000002 +import ViewResolver from 0x0000000000000001 +import FungibleToken from 0x0000000000000002 +import FlowToken from 0x0000000000000003 + +import EVM from 0x0000000000000001 + +import ICrossVM from 0x0000000000000007 +import IEVMBridgeTokenMinter from 0x0000000000000007 +import FlowEVMBridgeTokenEscrow from 0x0000000000000007 +import FlowEVMBridgeConfig from 0x0000000000000007 +import FlowEVMBridgeUtils from 0x0000000000000007 +import FlowEVMBridge from 0x0000000000000007 +import CrossVMNFT from 0x0000000000000007 +import CrossVMToken from 0x0000000000000007 + +/// This contract is a template used by FlowEVMBridge to define EVM-native fungible tokens bridged from Flow EVM to +/// Cadence. Upon deployment of this contract, the contract name is derived as a function of the asset type (here an +/// ERC20) and the contract's EVM address. The derived contract name is then joined with this contract's code, +/// prepared as chunks in FlowEVMBridgeTemplates before being deployed to the Flow EVM Bridge account. +/// +/// On bridging, the ERC20 is transferred to the bridge's CadenceOwnedAccount EVM address and tokens are minted from +/// this contract to the bridging caller. On return to Flow EVM, the reverse process is followed - the token is burned +/// in this contract and the ERC20 is transferred to the defined recipient. In this way, the Cadence Vault acts as a +/// representation of both the EVM tokens and thus ownership rights to it upon bridging back to Flow EVM. +/// +/// To bridge between VMs, a caller can either use the interface exposed on CadenceOwnedAccount or use FlowEVMBridge +/// public contract methods. +/// +access(all) contract {{CONTRACT_NAME}} : ICrossVM, IEVMBridgeTokenMinter, FungibleToken { + + /// Pointer to the Factory deployed Solidity contract address defining the bridged asset + access(all) let evmTokenContractAddress: EVM.EVMAddress + /// Name of the fungible token defined in the corresponding ERC20 contract + access(all) let name: String + /// Symbol of the fungible token defined in the corresponding ERC20 contract + access(all) let symbol: String + /// Decimal place value defined in the source ERC20 contract + access(all) let decimals: UInt8 + /// URI of the contract, if available as a var in case the bridge enables cross-VM Metadata syncing in the future + access(all) var contractURI: String? + /// Total supply of this Cadence token in circulation + /// NOTE: This does not reflect the total supply of the source ERC20 in circulation within EVM + access(all) var totalSupply: UFix64 + /// Retain a Vault to reference when resolving Vault Metadata + access(self) let vault: @Vault + + /// The Vault resource representing the bridged ERC20 token + /// + access(all) resource Vault : CrossVMToken.EVMTokenInfo, FungibleToken.Vault { + /// Balance of the tokens in a given Vault + access(all) var balance: UFix64 + + init(balance: UFix64) { + self.balance = balance + } + + /* --- CrossVMToken.EVMFTVault conformance --- */ + // + /// Gets the ERC20 name value + access(all) view fun getName(): String { + return {{CONTRACT_NAME}}.name + } + /// Gets the ERC20 symbol value + access(all) view fun getSymbol(): String { + return {{CONTRACT_NAME}}.symbol + } + /// Gets the ERC20 decimals value + access(all) view fun getDecimals(): UInt8 { + return {{CONTRACT_NAME}}.decimals + } + /// Returns the EVM contract address of the fungible token + access(all) view fun getEVMContractAddress(): EVM.EVMAddress { + return {{CONTRACT_NAME}}.getEVMContractAddress() + } + + access(all) view fun getViews(): [Type] { + return {{CONTRACT_NAME}}.getContractViews(resourceType: nil) + } + + access(all) fun resolveView(_ view: Type): AnyStruct? { + return {{CONTRACT_NAME}}.resolveContractView(resourceType: nil, viewType: view) + } + + /// getSupportedVaultTypes optionally returns a list of vault types that this receiver accepts + access(all) view fun getSupportedVaultTypes(): {Type: Bool} { + return { self.getType(): true } + } + + access(all) view fun isSupportedVaultType(type: Type): Bool { + return self.getSupportedVaultTypes()[type] ?? false + } + + /// Asks if the amount can be withdrawn from this vault + access(all) view fun isAvailableToWithdraw(amount: UFix64): Bool { + return amount <= self.balance + } + + /// deposit + /// + /// Function that takes a Vault object as an argument and adds + /// its balance to the balance of the owners Vault. + /// + /// It is allowed to destroy the sent Vault because the Vault + /// was a temporary holder of the tokens. The Vault's balance has + /// been consumed and therefore can be destroyed. + /// + access(all) fun deposit(from: @{FungibleToken.Vault}) { + let vault <- from as! @Vault + self.balance = self.balance + vault.balance + vault.balance = 0.0 + destroy vault + } + + /// createEmptyVault + /// + /// Function that creates a new Vault with a balance of zero + /// and returns it to the calling context. A user must call this function + /// and store the returned Vault in their storage in order to allow their + /// account to be able to receive deposits of this token type. + /// + access(all) fun createEmptyVault(): @Vault { + return <-create Vault(balance: 0.0) + } + + /// withdraw + /// + /// Function that takes an amount as an argument + /// and withdraws that amount from the Vault. + /// + /// It creates a new temporary Vault that is used to hold + /// the tokens that are being transferred. It returns the newly + /// created Vault to the context that called so it can be deposited + /// elsewhere. + /// + access(FungibleToken.Withdraw) fun withdraw(amount: UFix64): @Vault { + self.balance = self.balance - amount + return <-create Vault(balance: amount) + } + + /// Called when a fungible token is burned via the `Burner.burn()` method + access(contract) fun burnCallback() { + if self.balance > 0.0 { + {{CONTRACT_NAME}}.totalSupply = {{CONTRACT_NAME}}.totalSupply - self.balance + } + self.balance = 0.0 + } + } + + /// createEmptyVault + /// + /// Function that creates a new Vault with a balance of zero and returns it to the calling context. A user must call + /// this function and store the returned Vault in their storage in order to allow their account to be able to + /// receive deposits of this token type. + /// + access(all) fun createEmptyVault(vaultType: Type): @{{CONTRACT_NAME}}.Vault { + return <- create Vault(balance: 0.0) + } + + /********************** + Getters + ***********************/ + + /// Returns the EVM contract address of the fungible token this contract represents + /// + access(all) view fun getEVMContractAddress(): EVM.EVMAddress { + return self.evmTokenContractAddress + } + + /// Function that returns all the Metadata Views implemented by this fungible token contract. + /// + /// @return An array of Types defining the implemented views. This value will be used by + /// developers to know which parameter to pass to the resolveView() method. + /// + access(all) view fun getContractViews(resourceType: Type?): [Type] { + return [ + Type(), + Type(), + Type(), + Type(), + Type() + ] + } + + /// Function that resolves a metadata view for this contract. + /// + /// @param view: The Type of the desired view. + /// + /// @return A structure representing the requested view. + /// + access(all) fun resolveContractView(resourceType: Type?, viewType: Type): AnyStruct? { + switch viewType { + case Type(): + return FungibleTokenMetadataViews.FTView( + ftDisplay: self.resolveContractView(resourceType: nil, viewType: Type()) as! FungibleTokenMetadataViews.FTDisplay?, + ftVaultData: self.resolveContractView(resourceType: nil, viewType: Type()) as! FungibleTokenMetadataViews.FTVaultData? + ) + case Type(): + let media = MetadataViews.Media( + file: MetadataViews.HTTPFile( + url: "https://assets.website-files.com/5f6294c0c7a8cdd643b1c820/5f6294c0c7a8cda55cb1c936_Flow_Wordmark.svg" + ), + mediaType: "image/svg+xml" + ) + let medias = MetadataViews.Medias([media]) + return FungibleTokenMetadataViews.FTDisplay( + // TODO: Decide on how we want to represent bridged token media + name: self.name, + symbol: self.symbol, + description: "This fungible token was bridged from Flow EVM.", + externalURL: MetadataViews.ExternalURL("https://bridge.flow.com/fungible-token"), + logos: medias, + socials: {} + ) + case Type(): + return FungibleTokenMetadataViews.FTVaultData( + storagePath: /storage/{{CONTRACT_NAME}}Vault, + receiverPath: /public/{{CONTRACT_NAME}}Receiver, + metadataPath: /public/{{CONTRACT_NAME}}Vault, + receiverLinkedType: Type<&{{CONTRACT_NAME}}.Vault>(), + metadataLinkedType: Type<&{{CONTRACT_NAME}}.Vault>(), + createEmptyVaultFunction: (fun(): @{FungibleToken.Vault} { + return <-self.createEmptyVault(vaultType: Type<@{{CONTRACT_NAME}}.Vault>()) + }) + ) + case Type(): + return FungibleTokenMetadataViews.TotalSupply( + totalSupply: self.totalSupply + ) + case Type(): + return CrossVMNFT.EVMBridgedMetadata( + name: self.name, + symbol: self.symbol, + uri: self.contractURI != nil ? CrossVMNFT.URI(baseURI: nil, value: self.contractURI!) : CrossVMNFT.URI(baseURI: nil, value: "") + ) + } + return nil + } + + /********************** + Internal Methods + ***********************/ + + /// Allows the bridge to mint tokens from bridge-defined fungible token contracts + /// + access(account) fun mintTokens(amount: UFix64): @{FungibleToken.Vault} { + self.totalSupply = self.totalSupply + amount + return <- create Vault(balance: amount) + } + + init(name: String, symbol: String, decimals: UInt8, evmContractAddress: EVM.EVMAddress, contractURI: String?) { + self.evmTokenContractAddress = evmContractAddress + self.name = name + self.symbol = symbol + self.decimals = decimals + self.contractURI = contractURI + self.totalSupply = 0.0 + self.vault <- create Vault(balance: 0.0) + + FlowEVMBridgeConfig.associateType(Type<@{{CONTRACT_NAME}}.Vault>(), with: self.evmTokenContractAddress) + FlowEVMBridgeTokenEscrow.initializeEscrow( + with: <-create Vault(balance: 0.0), + name: name, + symbol: symbol, + decimals: decimals, + evmTokenAddress: self.evmTokenContractAddress + ) + } +} diff --git a/cadence/contracts/test/EVMDeployer.cdc b/cadence/contracts/test/EVMDeployer.cdc index 56775b60..b12bf956 100644 --- a/cadence/contracts/test/EVMDeployer.cdc +++ b/cadence/contracts/test/EVMDeployer.cdc @@ -1,20 +1,36 @@ import "EVM" -/// This contract is intended for testing purposes for the sake of capturing a deployed contract address while native +/// NOTE: NOT INTENDED FOR PRODUCTION USE - USED FOR TEMPORARY TESTING PURPOSES ONLY +/// +/// This contract is intended for testing purposes for the sake of capturing a deployed contract addresses while native /// `evm.TransactionExecuted` event types are not available in Cadence testing framework. The deploying account should /// already be configured with a `CadenceOwnedAccount` resource in storage at `/storage/evm`. /// access(all) contract EVMDeployer { - access(all) let deployedAddress: EVM.EVMAddress + access(all) let deployedAddresses: {String: EVM.EVMAddress} - init(bytecode: String, value: UInt) { - let coa = self.account.storage.borrow(from: /storage/evm) - ?? panic("No COA found in storage") - self.deployedAddress = coa.deploy( + access(all) fun deploy(name: String, bytecode: String, value: UInt) { + pre { + self.deployedAddresses[name] == nil: "Already deployed contract under provided" + } + post { + self.deployedAddresses[name] != nil : "Deployment address was not stored" + } + let deploymentAddress = self.borrowCOA().deploy( code: bytecode.decodeHex(), gasLimit: 15_000_000, value: EVM.Balance(attoflow: value) ) + self.deployedAddresses[name] = deploymentAddress + } + + access(self) fun borrowCOA(): auth(EVM.Deploy) &EVM.CadenceOwnedAccount { + return self.account.storage.borrow(from: /storage/evm) + ?? panic("No COA found in storage") + } + + init() { + self.deployedAddresses = {} } } diff --git a/cadence/contracts/utils/SerializeNFT.cdc b/cadence/contracts/utils/SerializeNFT.cdc index 42cd631e..7c75e734 100644 --- a/cadence/contracts/utils/SerializeNFT.cdc +++ b/cadence/contracts/utils/SerializeNFT.cdc @@ -1,6 +1,7 @@ import "ViewResolver" import "MetadataViews" import "NonFungibleToken" +import "FungibleTokenMetadataViews" import "Serialize" @@ -17,8 +18,8 @@ access(all) contract SerializeNFT { /// Reference: https://docs.opensea.io/docs/metadata-standards /// /// - /// @returns: A JSON compatible string containing the serialized display & collection display views as: - /// `{ + /// @returns: A JSON compatible data URL string containing the serialized display & collection display views as: + /// `data:application/json;utf8,{ /// \"name\": \"\", /// \"description\": \"\", /// \"image\": \"\", @@ -132,4 +133,32 @@ access(all) contract SerializeNFT { } return serializedResult.concat("]") } + + /// Serializes the FTDisplay view of a given fungible token as a JSON compatible data URL. The value is returned as + /// contract-level metadata. + /// + /// @param ftDisplay: The tokens's FTDisplay view from which values `name`, `symbol`, `description`, and + /// `externaURL` are serialized + /// + /// @returns: A JSON compatible data URL string containing the serialized view as: + /// `data:application/json;utf8,{ + /// \"name\": \"\", + /// \"symbol\": \"\", + /// \"description\": \"\", + /// \"external_link\": \"\", + /// }` + access(all) + fun serializeFTDisplay(_ ftDisplay: FungibleTokenMetadataViews.FTDisplay): String { + let name = "\"name\": " + let symbol = "\"symbol\": " + let description = "\"description\": " + let externalLink = "\"external_link\": " + + return "data:application/json;utf8,{" + .concat(name).concat(Serialize.tryToJSONString(ftDisplay.name)!).concat(", ") + .concat(symbol).concat(Serialize.tryToJSONString(ftDisplay.symbol)!).concat(", ") + .concat(description).concat(Serialize.tryToJSONString(ftDisplay.description)!).concat(", ") + .concat(externalLink).concat(Serialize.tryToJSONString(ftDisplay.externalURL.url)!) + .concat("}") + } } diff --git a/cadence/scripts/test/get_deployed_address_string_from_deployer.cdc b/cadence/scripts/test/get_deployed_address_string_from_deployer.cdc new file mode 100644 index 00000000..7da0a811 --- /dev/null +++ b/cadence/scripts/test/get_deployed_address_string_from_deployer.cdc @@ -0,0 +1,12 @@ +import "EVM" + +import "EVMDeployer" + +import "FlowEVMBridgeUtils" + +access(all) +fun main(name: String): String { + return FlowEVMBridgeUtils.getEVMAddressAsHexString( + address: EVMDeployer.deployedAddresses[name] ?? panic("Could not find deployed address for: ".concat(name)) + ) +} \ No newline at end of file diff --git a/cadence/scripts/test/get_deployed_erc721_address_string.cdc b/cadence/scripts/test/get_deployed_erc721_address_string.cdc deleted file mode 100644 index 19830476..00000000 --- a/cadence/scripts/test/get_deployed_erc721_address_string.cdc +++ /dev/null @@ -1,10 +0,0 @@ -import "EVM" - -import "EVMDeployer" - -import "FlowEVMBridgeUtils" - -access(all) -fun main(): String { - return FlowEVMBridgeUtils.getEVMAddressAsHexString(address: EVMDeployer.deployedAddress) -} \ No newline at end of file diff --git a/cadence/scripts/tokens/get_balance.cdc b/cadence/scripts/tokens/get_balance.cdc new file mode 100644 index 00000000..331f2614 --- /dev/null +++ b/cadence/scripts/tokens/get_balance.cdc @@ -0,0 +1,15 @@ +import "FungibleToken" + +/// Returns the balance of the stored Vault at the given address if exists, otherwise nil +/// +/// @param address: The address of the account that owns the vault +/// @param vaultPathIdentifier: The identifier of the vault's storage path +/// +/// @returns The balance of the stored Vault at the given address +/// +access(all) fun main(address: Address, vaultPathIdentifier: String): UFix64? { + let path = StoragePath(identifier: vaultPathIdentifier) ?? panic("Malformed StoragePath identifier") + return getAuthAccount(address).storage.borrow<&{FungibleToken.Vault}>( + from: path + )?.balance ?? nil +} diff --git a/cadence/scripts/utils/balance_of.cdc b/cadence/scripts/utils/balance_of.cdc new file mode 100644 index 00000000..5fbee589 --- /dev/null +++ b/cadence/scripts/utils/balance_of.cdc @@ -0,0 +1,21 @@ +import "EVM" + +import "FlowEVMBridgeUtils" + +/// Returns the balance of the owner (hex-encoded EVM address - minus 0x prefix) of a given ERC20 fungible token defined +/// at the hex-encoded EVM contract address +/// +/// @param owner: The hex-encoded EVM address of the owner without the 0x prefix +/// @param evmContractAddress: The hex-encoded EVM contract address of the ERC20 contract without the 0x prefix +/// +/// @return The balance of the address, reverting if the given contract address does not implement the ERC20 method +/// "balanceOf(address)(uint256)" +/// +access(all) fun main(owner: String, evmContractAddress: String): UInt256 { + return FlowEVMBridgeUtils.balanceOf( + owner: FlowEVMBridgeUtils.getEVMAddressFromHexString(address: owner) + ?? panic("Invalid owner address"), + evmContractAddress: FlowEVMBridgeUtils.getEVMAddressFromHexString(address: evmContractAddress) + ?? panic("Invalid EVM contract address") + ) +} diff --git a/cadence/scripts/utils/derive_bridged_token_contract_name.cdc b/cadence/scripts/utils/derive_bridged_token_contract_name.cdc new file mode 100644 index 00000000..47162364 --- /dev/null +++ b/cadence/scripts/utils/derive_bridged_token_contract_name.cdc @@ -0,0 +1,10 @@ +import "EVM" + +import "FlowEVMBridgeUtils" + +access(all) +fun main(evmAddressHex: String): String { + return FlowEVMBridgeUtils.deriveBridgedTokenContractName( + from: FlowEVMBridgeUtils.getEVMAddressFromHexString(address: evmAddressHex) ?? panic("Could not parse EVM address from hex string") + ) +} diff --git a/cadence/scripts/utils/get_token_decimals.cdc b/cadence/scripts/utils/get_token_decimals.cdc new file mode 100644 index 00000000..3c690f21 --- /dev/null +++ b/cadence/scripts/utils/get_token_decimals.cdc @@ -0,0 +1,9 @@ +import "FlowEVMBridgeUtils" + +access(all) +fun main(erc20ContractAddressHex: String): UInt8 { + return FlowEVMBridgeUtils.getTokenDecimals( + evmContractAddress: FlowEVMBridgeUtils.getEVMAddressFromHexString(address: erc20ContractAddressHex) + ?? panic("Invalid ERC20 address") + ) +} diff --git a/cadence/scripts/utils/ufix64_to_uint256.cdc b/cadence/scripts/utils/ufix64_to_uint256.cdc new file mode 100644 index 00000000..3b8fd42d --- /dev/null +++ b/cadence/scripts/utils/ufix64_to_uint256.cdc @@ -0,0 +1,6 @@ +import "FlowEVMBridgeUtils" + +access(all) +fun main(value: UFix64, decimals: UInt8): UInt256 { + return FlowEVMBridgeUtils.ufix64ToUInt256(value: value, decimals: decimals) +} diff --git a/cadence/scripts/utils/uint256_to_ufix64.cdc b/cadence/scripts/utils/uint256_to_ufix64.cdc new file mode 100644 index 00000000..ed5d4c4f --- /dev/null +++ b/cadence/scripts/utils/uint256_to_ufix64.cdc @@ -0,0 +1,6 @@ +import "FlowEVMBridgeUtils" + +access(all) +fun main(value: UInt256, decimals: UInt8): UFix64 { + return FlowEVMBridgeUtils.uint256ToUFix64(value: value, decimals: decimals) +} diff --git a/cadence/tests/flow_evm_bridge_tests.cdc b/cadence/tests/flow_evm_bridge_tests.cdc index e553bfd4..59d11b44 100644 --- a/cadence/tests/flow_evm_bridge_tests.cdc +++ b/cadence/tests/flow_evm_bridge_tests.cdc @@ -1,6 +1,7 @@ import Test import BlockchainHelpers +import "FungibleToken" import "NonFungibleToken" import "test_helpers.cdc" @@ -8,8 +9,9 @@ import "test_helpers.cdc" access(all) let serviceAccount = Test.serviceAccount() access(all) let bridgeAccount = Test.getAccount(0x0000000000000007) access(all) let exampleNFTAccount = Test.getAccount(0x0000000000000008) -access(all) let exampleERC721Account = Test.getAccount(0x0000000000000009) -access(all) let alice = Test.createAccount() +access(all) let exampleERCAccount = Test.getAccount(0x0000000000000009) +access(all) let exampleTokenAccount = Test.getAccount(0x0000000000000010) +access(all) let alice = Test.createAccount() // ExampleNFT values access(all) let exampleNFTIdentifier = "A.0000000000000008.ExampleNFT.NFT" @@ -18,12 +20,19 @@ access(all) let exampleNFTTokenDescription = "Example NFT token description" access(all) let exampleNFTTokenThumbnail = "https://examplenft.com/thumbnail.png" access(all) var mintedNFTID: UInt64 = 0 +// ExampleToken +access(all) let exampleTokenIdentifier = "A.0000000000000010.ExampleToken.Vault" +access(all) let exampleTokenMintAmount = 100.0 + // ERC721 values access(all) let erc721Name = "NAME" access(all) let erc721Symbol = "SYMBOL" access(all) let erc721ID: UInt256 = 42 access(all) let erc721URI = "URI" +// ERC20 values +access(all) let erc20MintAmount: UInt256 = 100_000_000_000_000_000_000 + access(all) fun setup() { // Deploy supporting util contracts @@ -88,6 +97,12 @@ fun setup() { arguments: [] ) Test.expect(err, Test.beNil()) + err = Test.deployContract( + name: "CrossVMToken", + path: "../contracts/bridge/CrossVMToken.cdc", + arguments: [] + ) + Test.expect(err, Test.beNil()) err = Test.deployContract( name: "FlowEVMBridgeConfig", path: "../contracts/bridge/FlowEVMBridgeConfig.cdc", @@ -106,6 +121,12 @@ fun setup() { arguments: [] ) Test.expect(err, Test.beNil()) + err = Test.deployContract( + name: "FlowEVMBridgeTokenEscrow", + path: "../contracts/bridge/FlowEVMBridgeTokenEscrow.cdc", + arguments: [] + ) + Test.expect(err, Test.beNil()) err = Test.deployContract( name: "FlowEVMBridgeTemplates", path: "../contracts/bridge/FlowEVMBridgeTemplates.cdc", @@ -119,6 +140,13 @@ fun setup() { bridgeAccount ) Test.expect(bridgedNFTChunkResult, Test.beSucceeded()) + // Commit bridged Token code + let bridgedTokenChunkResult = executeTransaction( + "../transactions/bridge/admin/upsert_contract_code_chunks.cdc", + ["bridgedToken", getBridgedTokenCodeChunks()], + bridgeAccount + ) + Test.expect(bridgedNFTChunkResult, Test.beSucceeded()) err = Test.deployContract( name: "IEVMBridgeNFTMinter", @@ -126,12 +154,24 @@ fun setup() { arguments: [] ) Test.expect(err, Test.beNil()) + err = Test.deployContract( + name: "IEVMBridgeTokenMinter", + path: "../contracts/bridge/IEVMBridgeTokenMinter.cdc", + arguments: [] + ) + Test.expect(err, Test.beNil()) err = Test.deployContract( name: "IFlowEVMNFTBridge", path: "../contracts/bridge/IFlowEVMNFTBridge.cdc", arguments: [] ) Test.expect(err, Test.beNil()) + err = Test.deployContract( + name: "IFlowEVMTokenBridge", + path: "../contracts/bridge/IFlowEVMTokenBridge.cdc", + arguments: [] + ) + Test.expect(err, Test.beNil()) err = Test.deployContract( name: "FlowEVMBridge", path: "../contracts/bridge/FlowEVMBridge.cdc", @@ -139,16 +179,23 @@ fun setup() { ) Test.expect(err, Test.beNil()) err = Test.deployContract( - name: "EVMBridgeRouter", - path: "../contracts/bridge/EVMBridgeRouter.cdc", - arguments: [bridgeAccount.address, "FlowEVMBridge"] + name: "FlowEVMBridgeAccessor", + path: "../contracts/bridge/FlowEVMBridgeAccessor.cdc", + arguments: [serviceAccount.address] ) Test.expect(err, Test.beNil()) + let claimAccessorResult = executeTransaction( + "../transactions/bridge/admin/claim_accessor_capability_and_save_router.cdc", + ["FlowEVMBridgeAccessor", bridgeAccount.address], + serviceAccount + ) + Test.expect(claimAccessorResult, Test.beSucceeded()) + // Transfer ERC721 deployer some $FLOW - transferFlow(signer: serviceAccount, recipient: exampleERC721Account.address, amount: 1_000.0) + transferFlow(signer: serviceAccount, recipient: exampleERCAccount.address, amount: 1_000.0) // Configure bridge account with a COA - createCOA(signer: exampleERC721Account, fundingAmount: 10.0) + createCOA(signer: exampleERCAccount, fundingAmount: 10.0) // Deploy the ERC721 from EVMDeployer (simply to capture deploye EVM contract address) // TODO: Replace this contract with the `deployedContractAddress` value emitted on deployment @@ -156,37 +203,90 @@ fun setup() { err = Test.deployContract( name: "EVMDeployer", path: "../contracts/test/EVMDeployer.cdc", - arguments: [getCompiledERC721Bytecode(), UInt(0)] + arguments: [] ) Test.expect(err, Test.beNil()) + let erc721DeployResult = executeTransaction( + "../transactions/test/deploy_using_evm_deployer.cdc", + ["erc721", getCompiledERC721Bytecode(), 0 as UInt], + exampleERCAccount + ) + Test.expect(erc721DeployResult, Test.beSucceeded()) + let erc20DeployResult = executeTransaction( + "../transactions/test/deploy_using_evm_deployer.cdc", + ["erc20", getCompiledERC20Bytecode(), 0 as UInt], + exampleERCAccount + ) + Test.expect(erc20DeployResult, Test.beSucceeded()) err = Test.deployContract( name: "ExampleNFT", path: "../contracts/example-assets/ExampleNFT.cdc", arguments: [] ) Test.expect(err, Test.beNil()) + err = Test.deployContract( + name: "ExampleToken", + path: "../contracts/example-assets/ExampleToken.cdc", + arguments: [] + ) + Test.expect(err, Test.beNil()) } +/* --- ASSET & ACCOUNT SETUP - Configure test accounts with assets to bridge --- */ + access(all) fun testCreateCOASucceeds() { transferFlow(signer: serviceAccount, recipient: alice.address, amount: 1_000.0) createCOA(signer: alice, fundingAmount: 100.0) let coaAddressHex = getCOAAddressHex(atFlowAddress: alice.address) - Test.assertEqual(40, coaAddressHex!.length) + Test.assertEqual(40, coaAddressHex.length) +} + +access(all) +fun testBridgeFlowToEVMSucceeds() { + // Get $FLOW balances before, making assertions based on values from previous case + let cadenceBalanceBefore = getBalance(ownerAddr: alice.address, storagePathIdentifier: "flowTokenVault") + ?? panic("Problem getting $FLOW balance") + Test.assertEqual(900.0, cadenceBalanceBefore) + + // Get EVM $FLOW balance before + var aliceCOAAddressHex = getCOAAddressHex(atFlowAddress: alice.address) + Test.assertEqual(40, aliceCOAAddressHex.length) + + let evmBalanceBefore = getEVMFlowBalance(of: aliceCOAAddressHex) + Test.assertEqual(100.0, evmBalanceBefore) + + // Execute bridge to EVM + let bridgeAmount = 100.0 + bridgeTokensToEVM( + signer: alice, + contractAddr: Address(0x03), + contractName: "FlowToken", + amount: bridgeAmount + ) + + // Confirm Alice's token balance is now 0.0 + let cadenceBalanceAfter = getBalance(ownerAddr: alice.address, storagePathIdentifier: "flowTokenVault") + ?? panic("Problem getting $FLOW balance") + Test.assertEqual(cadenceBalanceBefore - bridgeAmount, cadenceBalanceAfter) + + // Confirm balance on EVM side has been updated + let evmBalanceAfter = getEVMFlowBalance(of: aliceCOAAddressHex) + Test.assertEqual(evmBalanceBefore + bridgeAmount, evmBalanceAfter) } access(all) fun testMintExampleNFTSucceeds() { let setupCollectionResult = executeTransaction( - "../transactions/example-assets/setup_collection.cdc", + "../transactions/example-assets/example-nft/setup_collection.cdc", [], alice ) Test.expect(setupCollectionResult, Test.beSucceeded()) let mintExampleNFTResult = executeTransaction( - "../transactions/example-assets/mint_nft.cdc", + "../transactions/example-assets/example-nft/mint_nft.cdc", [alice.address, exampleNFTTokenName, exampleNFTTokenDescription, exampleNFTTokenThumbnail, [], [], []], exampleNFTAccount ) @@ -203,28 +303,72 @@ fun testMintExampleNFTSucceeds() { Test.assertEqual(aliceOwnedIDs[0], mintedNFTID) } +access(all) +fun testMintExampleTokenSucceeds() { + let setupCollectionResult = executeTransaction( + "../transactions/example-assets/example-token/setup_vault.cdc", + [], + alice + ) + Test.expect(setupCollectionResult, Test.beSucceeded()) + + let mintExampleTokenResult = executeTransaction( + "../transactions/example-assets/example-token/mint_tokens.cdc", + [alice.address, exampleTokenMintAmount], + exampleTokenAccount + ) + Test.expect(mintExampleTokenResult, Test.beSucceeded()) + + let aliceBalance = getBalance(ownerAddr: alice.address, storagePathIdentifier: "exampleTokenVault") + ?? panic("Problem getting ExampleToken balance") + Test.assertEqual(exampleTokenMintAmount, aliceBalance) + + let events = Test.eventsOfType(Type()) + let evt = events[events.length - 1] as! FungibleToken.Deposited + + Test.assertEqual(aliceBalance, evt.amount) +} + access(all) fun testMintERC721Succeeds() { let aliceCOAAddressHex = getCOAAddressHex(atFlowAddress: alice.address) Test.assertEqual(40, aliceCOAAddressHex.length) - let erc721AddressResult = executeScript( - "../scripts/test/get_deployed_erc721_address_string.cdc", - [] - ) - Test.expect(erc721AddressResult, Test.beSucceeded()) - let erc721AddressHex = erc721AddressResult.returnValue as! String? ?? panic("Problem getting COA address as String") + let erc721AddressHex = getDeployedAddressFromDeployer(name: "erc721") Test.assertEqual(40, erc721AddressHex.length) let mintERC721Result = executeTransaction( - "../transactions/example-assets/safe_mint_erc721.cdc", + "../transactions/example-assets/evm-assets/safe_mint_erc721.cdc", [aliceCOAAddressHex, erc721ID, erc721URI, erc721AddressHex, UInt64(200_000)], - exampleERC721Account + exampleERCAccount ) Test.expect(mintERC721Result, Test.beSucceeded()) + + let aliceIsOwner = isOwner(of: erc721ID, ownerEVMAddrHex: aliceCOAAddressHex, erc721AddressHex: erc721AddressHex) + Test.assertEqual(true, aliceIsOwner) } access(all) -fun testOnboardByTypeSucceeds() { +fun testMintERC20Succeeds() { + let aliceCOAAddressHex = getCOAAddressHex(atFlowAddress: alice.address) + Test.assertEqual(40, aliceCOAAddressHex.length) + let erc20AddressHex = getDeployedAddressFromDeployer(name: "erc20") + Test.assertEqual(40, erc20AddressHex.length) + + let mintERC20Result = executeTransaction( + "../transactions/example-assets/evm-assets/mint_erc20.cdc", + [aliceCOAAddressHex, erc20MintAmount, erc20AddressHex, UInt64(200_000)], + exampleERCAccount + ) + Test.expect(mintERC20Result, Test.beSucceeded()) + + let aliceBalance = balanceOf(evmAddressHex: aliceCOAAddressHex, erc20AddressHex: erc20AddressHex) + Test.assertEqual(erc20MintAmount, aliceBalance) +} + +/* --- ONBOARDING - Test asset onboarding to the bridge --- */ + +access(all) +fun testOnboardNFTByTypeSucceeds() { var onboaringRequiredResult = executeScript( "../scripts/bridge/type_requires_onboarding.cdc", [exampleNFTIdentifier] @@ -234,7 +378,7 @@ fun testOnboardByTypeSucceeds() { Test.assertEqual(true, requiresOnboarding) var onboardingResult = executeTransaction( - "../transactions/bridge/onboard_by_type.cdc", + "../transactions/bridge/onboarding/onboard_by_type.cdc", [exampleNFTIdentifier], alice ) @@ -249,7 +393,7 @@ fun testOnboardByTypeSucceeds() { Test.assertEqual(false, requiresOnboarding) onboardingResult = executeTransaction( - "../transactions/bridge/onboard_by_type.cdc", + "../transactions/bridge/onboarding/onboard_by_type.cdc", [exampleNFTIdentifier], alice ) @@ -257,13 +401,8 @@ fun testOnboardByTypeSucceeds() { } access(all) -fun testOnboardByEVMAddressSucceeds() { - let erc721AddressResult = executeScript( - "../scripts/test/get_deployed_erc721_address_string.cdc", - [] - ) - Test.expect(erc721AddressResult, Test.beSucceeded()) - let erc721AddressHex = erc721AddressResult.returnValue as! String? ?? panic("Problem getting COA address as String") +fun testOnboardERC721ByEVMAddressSucceeds() { + let erc721AddressHex = getDeployedAddressFromDeployer(name: "erc721") Test.assertEqual(40, erc721AddressHex.length) var onboaringRequiredResult = executeScript( @@ -275,7 +414,7 @@ fun testOnboardByEVMAddressSucceeds() { Test.assertEqual(true, requiresOnboarding) var onboardingResult = executeTransaction( - "../transactions/bridge/onboard_by_evm_address.cdc", + "../transactions/bridge/onboarding/onboard_by_evm_address.cdc", [erc721AddressHex], alice ) @@ -290,13 +429,84 @@ fun testOnboardByEVMAddressSucceeds() { Test.assertEqual(false, requiresOnboarding) onboardingResult = executeTransaction( - "../transactions/bridge/onboard_by_evm_address.cdc", + "../transactions/bridge/onboarding/onboard_by_evm_address.cdc", [erc721AddressHex], alice ) Test.expect(onboardingResult, Test.beFailed()) } +access(all) +fun testOnboardTokenByTypeSucceeds() { + var onboaringRequiredResult = executeScript( + "../scripts/bridge/type_requires_onboarding.cdc", + [exampleTokenIdentifier] + ) + Test.expect(onboaringRequiredResult, Test.beSucceeded()) + var requiresOnboarding = onboaringRequiredResult.returnValue as! Bool? ?? panic("Problem getting onboarding requirement") + Test.assertEqual(true, requiresOnboarding) + + var onboardingResult = executeTransaction( + "../transactions/bridge/onboarding/onboard_by_type.cdc", + [exampleTokenIdentifier], + alice + ) + Test.expect(onboardingResult, Test.beSucceeded()) + + onboaringRequiredResult = executeScript( + "../scripts/bridge/type_requires_onboarding.cdc", + [exampleTokenIdentifier] + ) + Test.expect(onboaringRequiredResult, Test.beSucceeded()) + requiresOnboarding = onboaringRequiredResult.returnValue as! Bool? ?? panic("Problem getting onboarding requirement") + Test.assertEqual(false, requiresOnboarding) + + onboardingResult = executeTransaction( + "../transactions/bridge/onboarding/onboard_by_type.cdc", + [exampleTokenIdentifier], + alice + ) + Test.expect(onboardingResult, Test.beFailed()) +} + +access(all) +fun testOnboardERC20ByEVMAddressSucceeds() { + let erc20AddressHex = getDeployedAddressFromDeployer(name: "erc20") + Test.assertEqual(40, erc20AddressHex.length) + + var onboaringRequiredResult = executeScript( + "../scripts/bridge/evm_address_requires_onboarding.cdc", + [erc20AddressHex] + ) + Test.expect(onboaringRequiredResult, Test.beSucceeded()) + var requiresOnboarding = onboaringRequiredResult.returnValue as! Bool? ?? panic("Problem getting onboarding requirement") + Test.assertEqual(true, requiresOnboarding) + + var onboardingResult = executeTransaction( + "../transactions/bridge/onboarding/onboard_by_evm_address.cdc", + [erc20AddressHex], + alice + ) + Test.expect(onboardingResult, Test.beSucceeded()) + + onboaringRequiredResult = executeScript( + "../scripts/bridge/evm_address_requires_onboarding.cdc", + [erc20AddressHex] + ) + Test.expect(onboaringRequiredResult, Test.beSucceeded()) + requiresOnboarding = onboaringRequiredResult.returnValue as! Bool? ?? panic("Problem getting onboarding requirement") + Test.assertEqual(false, requiresOnboarding) + + onboardingResult = executeTransaction( + "../transactions/bridge/onboarding/onboard_by_evm_address.cdc", + [erc20AddressHex], + alice + ) + Test.expect(onboardingResult, Test.beFailed()) +} + +/* --- BRIDGING NFTS - Test bridging both Cadence- & EVM-native NFTs --- */ + access(all) fun testBridgeCadenceNativeNFTToEVMSucceeds() { var aliceOwnedIDs = getIDs(ownerAddr: alice.address, storagePathIdentifier: "cadenceExampleNFTCollection") @@ -314,7 +524,7 @@ fun testBridgeCadenceNativeNFTToEVMSucceeds() { // Confirm the NFT is no longer in Alice's Collection aliceOwnedIDs = getIDs(ownerAddr: alice.address, storagePathIdentifier: "cadenceExampleNFTCollection") Test.assertEqual(0, aliceOwnedIDs.length) - + // Confirm ownership on EVM side with Alice COA as owner of ERC721 representation let isOwnerResult = executeScript( "../scripts/utils/is_owner.cdc", @@ -328,7 +538,7 @@ access(all) fun testBridgeCadenceNativeNFTFromEVMSucceeds() { let aliceCOAAddressHex = getCOAAddressHex(atFlowAddress: alice.address) Test.assertEqual(40, aliceCOAAddressHex.length) - + let associatedEVMAddressHex = getAssociatedEVMAddressHex(with: exampleNFTIdentifier) Test.assertEqual(40, associatedEVMAddressHex.length) @@ -351,14 +561,9 @@ fun testBridgeCadenceNativeNFTFromEVMSucceeds() { access(all) fun testBridgeEVMNativeNFTFromEVMSucceeds() { - let erc721AddressResult = executeScript( - "../scripts/test/get_deployed_erc721_address_string.cdc", - [] - ) - Test.expect(erc721AddressResult, Test.beSucceeded()) - let erc721AddressHex = erc721AddressResult.returnValue as! String? ?? panic("Problem getting COA address as String") + let erc721AddressHex = getDeployedAddressFromDeployer(name: "erc721") Test.assertEqual(40, erc721AddressHex.length) - + let derivedERC721ContractName = deriveBridgedNFTContractName(evmAddressHex: erc721AddressHex) let bridgedCollectionPathIdentifier = derivedERC721ContractName.concat("Collection") let aliceCOAAddressHex = getCOAAddressHex(atFlowAddress: alice.address) @@ -380,24 +585,19 @@ fun testBridgeEVMNativeNFTFromEVMSucceeds() { access(all) fun testBridgeEVMNativeNFTToEVMSucceeds() { - let erc721AddressResult = executeScript( - "../scripts/test/get_deployed_erc721_address_string.cdc", - [] - ) - Test.expect(erc721AddressResult, Test.beSucceeded()) - let erc721AddressHex = erc721AddressResult.returnValue as! String? ?? panic("Problem getting COA address as String") + let erc721AddressHex = getDeployedAddressFromDeployer(name: "erc721") Test.assertEqual(40, erc721AddressHex.length) - + let derivedERC721ContractName = deriveBridgedNFTContractName(evmAddressHex: erc721AddressHex) let bridgedCollectionPathIdentifier = derivedERC721ContractName.concat("Collection") let aliceCOAAddressHex = getCOAAddressHex(atFlowAddress: alice.address) Test.assertEqual(40, aliceCOAAddressHex.length) - + var aliceOwnedIDs = getIDs(ownerAddr: alice.address, storagePathIdentifier: bridgedCollectionPathIdentifier) Test.assertEqual(1, aliceOwnedIDs.length) - + bridgeNFTToEVM(signer: alice, contractAddr: bridgeAccount.address, contractName: derivedERC721ContractName, nftID: aliceOwnedIDs[0]) - + aliceOwnedIDs = getIDs(ownerAddr: alice.address, storagePathIdentifier: bridgedCollectionPathIdentifier) Test.assertEqual(0, aliceOwnedIDs.length) @@ -405,6 +605,174 @@ fun testBridgeEVMNativeNFTToEVMSucceeds() { Test.assertEqual(true, aliceIsOwner) } +/* --- BRIDGING FUNGIBLE TOKENS - Test bridging both Cadence- & EVM-native fungible tokens --- */ + +access(all) +fun testBridgeCadenceNativeTokenToEVMSucceeds() { + var cadenceBalance = getBalance(ownerAddr: alice.address, storagePathIdentifier: "exampleTokenVault") + ?? panic("Problem getting ExampleToken balance") + Test.assert(cadenceBalance == exampleTokenMintAmount) + + var aliceCOAAddressHex = getCOAAddressHex(atFlowAddress: alice.address) + Test.assertEqual(40, aliceCOAAddressHex.length) + + // Execute bridge to EVM + bridgeTokensToEVM( + signer: alice, + contractAddr: exampleTokenAccount.address, + contractName: "ExampleToken", + amount: cadenceBalance + ) + + let associatedEVMAddressHex = getAssociatedEVMAddressHex(with: exampleTokenIdentifier) + Test.assertEqual(40, associatedEVMAddressHex.length) + + // Confirm Alice's token balance is now 0.0 + cadenceBalance = getBalance(ownerAddr: alice.address, storagePathIdentifier: "exampleTokenVault") + ?? panic("Problem getting ExampleToken balance") + Test.assertEqual(0.0, cadenceBalance) + + // Confirm balance on EVM side has been updated + let decimals = getTokenDecimals(erc20AddressHex: associatedEVMAddressHex) + let expectedEVMBalance = ufix64ToUInt256(exampleTokenMintAmount, decimals: decimals) + let evmBalance = balanceOf(evmAddressHex: aliceCOAAddressHex, erc20AddressHex: associatedEVMAddressHex) + Test.assertEqual(expectedEVMBalance, evmBalance) +} + +access(all) +fun testBridgeCadenceNativeTokenFromEVMSucceeds() { + let associatedEVMAddressHex = getAssociatedEVMAddressHex(with: exampleTokenIdentifier) + Test.assertEqual(40, associatedEVMAddressHex.length) + + var aliceCOAAddressHex = getCOAAddressHex(atFlowAddress: alice.address) + Test.assertEqual(40, aliceCOAAddressHex.length) + + // Confirm Alice is starting with 0.0 balance in their Cadence Vault + var cadenceBalance = getBalance(ownerAddr: alice.address, storagePathIdentifier: "exampleTokenVault") + ?? panic("Problem getting ExampleToken balance") + Test.assertEqual(0.0, cadenceBalance) + + // Get Alice's ERC20 balance & convert to UFix64 + var evmBalance = balanceOf(evmAddressHex: aliceCOAAddressHex, erc20AddressHex: associatedEVMAddressHex) + let decimals = getTokenDecimals(erc20AddressHex: associatedEVMAddressHex) + let ufixValue = uint256ToUFix64(evmBalance, decimals: decimals) + // Assert the converted balance is equal to the originally minted amount that was bridged in the previous step + Test.assertEqual(exampleTokenMintAmount, ufixValue) + + // Execute bridge from EVM + bridgeTokensFromEVM( + signer: alice, + contractAddr: exampleTokenAccount.address, + contractName: "ExampleToken", + amount: evmBalance + ) + + // Confirm ExampleToken balance has been bridged back to Alice's Cadence vault + cadenceBalance = getBalance(ownerAddr: alice.address, storagePathIdentifier: "exampleTokenVault") + ?? panic("Problem getting ExampleToken balance") + Test.assertEqual(ufixValue, cadenceBalance) + + // Confirm ownership on EVM side with Alice COA as owner of ERC721 representation + evmBalance = balanceOf(evmAddressHex: aliceCOAAddressHex, erc20AddressHex: associatedEVMAddressHex) + Test.assertEqual(UInt256(0), evmBalance) +} + +access(all) +fun testBridgeEVMNativeTokenFromEVMSucceeds() { + let erc20AddressHex = getDeployedAddressFromDeployer(name: "erc20") + Test.assertEqual(40, erc20AddressHex.length) + + let derivedERC20ContractName = deriveBridgedTokenContractName(evmAddressHex: erc20AddressHex) + let bridgedVaultPathIdentifier = derivedERC20ContractName.concat("Vault") + let aliceCOAAddressHex = getCOAAddressHex(atFlowAddress: alice.address) + Test.assertEqual(40, aliceCOAAddressHex.length) + + // Confirm ownership on EVM side with Alice COA as owner of ERC721 representation + var evmBalance = balanceOf(evmAddressHex: aliceCOAAddressHex, erc20AddressHex: erc20AddressHex) + Test.assertEqual(erc20MintAmount, evmBalance) + + // Confirm Alice does not yet have a bridged Vault configured + var cadenceBalance = getBalance(ownerAddr: alice.address, storagePathIdentifier: bridgedVaultPathIdentifier) + Test.assertEqual(nil, cadenceBalance) + + // Execute bridge from EVM + bridgeTokensFromEVM( + signer: alice, + contractAddr: bridgeAccount.address, + contractName: derivedERC20ContractName, + amount: evmBalance + ) + + // Confirm EVM balance is no 0 + evmBalance = balanceOf(evmAddressHex: aliceCOAAddressHex, erc20AddressHex: erc20AddressHex) + Test.assertEqual(UInt256(0), evmBalance) + + // Confirm the Cadence Vault is now configured and contains the bridged balance + cadenceBalance = getBalance(ownerAddr: alice.address, storagePathIdentifier: bridgedVaultPathIdentifier) + ?? panic("Bridged token Vault was not found in Alice's account after bridging") + let decimals = getTokenDecimals(erc20AddressHex: erc20AddressHex) + let expectedCadenceBalance = uint256ToUFix64(erc20MintAmount, decimals: decimals) + Test.assertEqual(expectedCadenceBalance, cadenceBalance!) + + // With the bridge executed, confirm the bridge COA escrows the ERC20 tokens + let bridgeCOAAddressHex = getCOAAddressHex(atFlowAddress: bridgeAccount.address) + Test.assertEqual(40, bridgeCOAAddressHex.length) + let bridgeCOAEscrowBalance = balanceOf(evmAddressHex: bridgeCOAAddressHex, erc20AddressHex: erc20AddressHex) + Test.assertEqual(erc20MintAmount, bridgeCOAEscrowBalance) +} + +access(all) +fun testBridgeEVMNativeTokenToEVMSucceeds() { + let erc20AddressHex = getDeployedAddressFromDeployer(name: "erc20") + Test.assertEqual(40, erc20AddressHex.length) + + let derivedERC20ContractName = deriveBridgedTokenContractName(evmAddressHex: erc20AddressHex) + let bridgedVaultPathIdentifier = derivedERC20ContractName.concat("Vault") + let aliceCOAAddressHex = getCOAAddressHex(atFlowAddress: alice.address) + Test.assertEqual(40, aliceCOAAddressHex.length) + + // Confirm Cadence Vault has the expected balance + var cadenceBalance = getBalance(ownerAddr: alice.address, storagePathIdentifier: bridgedVaultPathIdentifier) + ?? panic("Bridged token Vault was not found in Alice's account after bridging") + let decimals = getTokenDecimals(erc20AddressHex: erc20AddressHex) + let expectedCadenceBalance = uint256ToUFix64(erc20MintAmount, decimals: decimals) + Test.assertEqual(expectedCadenceBalance, cadenceBalance) + + // Confirm EVM balance is 0 + var evmBalance = balanceOf(evmAddressHex: aliceCOAAddressHex, erc20AddressHex: erc20AddressHex) + Test.assertEqual(UInt256(0), evmBalance) + + // Confirm the bridge COA currently escrows the ERC20 tokens we will be bridging + let bridgeCOAAddressHex = getCOAAddressHex(atFlowAddress: bridgeAccount.address) + Test.assertEqual(40, bridgeCOAAddressHex.length) + var bridgeCOAEscrowBalance = balanceOf(evmAddressHex: bridgeCOAAddressHex, erc20AddressHex: erc20AddressHex) + Test.assertEqual(erc20MintAmount, bridgeCOAEscrowBalance) + + // Execute bridge from EVM + bridgeTokensToEVM( + signer: alice, + contractAddr: bridgeAccount.address, + contractName: derivedERC20ContractName, + amount: cadenceBalance + ) + + // Confirm ownership on EVM side with Alice COA as owner of ERC721 representation + evmBalance = balanceOf(evmAddressHex: aliceCOAAddressHex, erc20AddressHex: erc20AddressHex) + Test.assertEqual(erc20MintAmount, evmBalance) + + cadenceBalance = getBalance(ownerAddr: alice.address, storagePathIdentifier: bridgedVaultPathIdentifier) + ?? panic("Bridged token Vault was not found in Alice's account after bridging") + Test.assertEqual(0.0, cadenceBalance) + + // Confirm the bridge COA no longer escrows the ERC20 tokens + bridgeCOAEscrowBalance = balanceOf(evmAddressHex: bridgeCOAAddressHex, erc20AddressHex: erc20AddressHex) + Test.assertEqual(UInt256(0), bridgeCOAEscrowBalance) +} + +/* ---------------------------------------------- */ +/* --------------- END TEST CASES --------------- */ +/* ---------------------------------------------- */ + /* --- Script Helpers --- */ access(all) @@ -427,6 +795,16 @@ fun getAssociatedEVMAddressHex(with typeIdentifier: String): String { return associatedEVMAddressResult.returnValue as! String? ?? panic("Problem getting EVM Address as String") } +access(all) +fun getDeployedAddressFromDeployer(name: String): String { + let erc721AddressResult = executeScript( + "../scripts/test/get_deployed_address_string_from_deployer.cdc", + [name] + ) + Test.expect(erc721AddressResult, Test.beSucceeded()) + return erc721AddressResult.returnValue as! String? ?? panic("Problem getting COA address as String") +} + access(all) fun getIDs(ownerAddr: Address, storagePathIdentifier: String): [UInt64] { let idResult = executeScript( @@ -437,6 +815,66 @@ fun getIDs(ownerAddr: Address, storagePathIdentifier: String): [UInt64] { return idResult.returnValue as! [UInt64]? ?? panic("Problem getting NFT IDs") } +access(all) +fun getBalance(ownerAddr: Address, storagePathIdentifier: String): UFix64? { + let balanceResult = executeScript( + "../scripts/tokens/get_balance.cdc", + [ownerAddr, storagePathIdentifier] + ) + Test.expect(balanceResult, Test.beSucceeded()) + return balanceResult.returnValue as! UFix64? +} + +access(all) +fun balanceOf(evmAddressHex: String, erc20AddressHex: String): UInt256 { + let balanceOfResult = executeScript( + "../scripts/utils/balance_of.cdc", + [evmAddressHex, erc20AddressHex] + ) + Test.expect(balanceOfResult, Test.beSucceeded()) + return balanceOfResult.returnValue as! UInt256? ?? panic("Problem getting ERC20 balance") +} + +access(all) +fun getEVMFlowBalance(of evmAddressHex: String): UFix64 { + let balanceResult = executeScript( + "../scripts/evm/get_balance.cdc", + [evmAddressHex] + ) + Test.expect(balanceResult, Test.beSucceeded()) + return balanceResult.returnValue as! UFix64? ?? panic("Problem getting EVM balance") +} + +access(all) +fun getTokenDecimals(erc20AddressHex: String): UInt8 { + let decimalsResult = executeScript( + "../scripts/utils/get_token_decimals.cdc", + [erc20AddressHex] + ) + Test.expect(decimalsResult, Test.beSucceeded()) + return decimalsResult.returnValue as! UInt8? ?? panic("Problem getting ERC20 decimals") +} + +access(all) +fun ufix64ToUInt256(_ value: UFix64, decimals: UInt8): UInt256 { + let convertedResult = executeScript( + "../scripts/utils/ufix64_to_uint256.cdc", + [value, decimals] + ) + Test.expect(convertedResult, Test.beSucceeded()) + return convertedResult.returnValue as! UInt256? ?? panic("Problem converting UFix64 to UInt256") +} + +access(all) +fun uint256ToUFix64(_ value: UInt256, decimals: UInt8): UFix64 { + let convertedResult = executeScript( + "../scripts/utils/uint256_to_ufix64.cdc", + [value, decimals] + ) + Test.expect(convertedResult, Test.beSucceeded()) + return convertedResult.returnValue as! UFix64? ?? panic("Problem converting UInt256 to UFix64") +} + access(all) fun isOwner(of: UInt256, ownerEVMAddrHex: String, erc721AddressHex: String): Bool { let isOwnerResult = executeScript( @@ -457,6 +895,16 @@ fun deriveBridgedNFTContractName(evmAddressHex: String): String { return nameResult.returnValue as! String? ?? panic("Problem getting derived contract name") } +access(all) +fun deriveBridgedTokenContractName(evmAddressHex: String): String { + let nameResult = executeScript( + "../scripts/utils/derive_bridged_token_contract_name.cdc", + [evmAddressHex] + ) + Test.expect(nameResult, Test.beSucceeded()) + return nameResult.returnValue as! String? ?? panic("Problem getting derived contract name") +} + /* --- Transaction Helpers --- */ access(all) @@ -482,7 +930,7 @@ fun createCOA(signer: Test.TestAccount, fundingAmount: UFix64) { access(all) fun bridgeNFTToEVM(signer: Test.TestAccount, contractAddr: Address, contractName: String, nftID: UInt64) { let bridgeResult = executeTransaction( - "../transactions/bridge/bridge_nft_to_evm.cdc", + "../transactions/bridge/nft/bridge_nft_to_evm.cdc", [contractAddr, contractName, nftID], signer ) @@ -502,7 +950,7 @@ fun bridgeNFTToEVM(signer: Test.TestAccount, contractAddr: Address, contractName access(all) fun bridgeNFTFromEVM(signer: Test.TestAccount, contractAddr: Address, contractName: String, erc721ID: UInt256) { let bridgeResult = executeTransaction( - "../transactions/bridge/bridge_nft_from_evm.cdc", + "../transactions/bridge/nft/bridge_nft_from_evm.cdc", [contractAddr, contractName, erc721ID], signer ) @@ -517,3 +965,28 @@ fun bridgeNFTFromEVM(signer: Test.TestAccount, contractAddr: Address, contractNa Test.assertEqual(signer.address, depositedEvent.to!) } +access(all) +fun bridgeTokensToEVM(signer: Test.TestAccount, contractAddr: Address, contractName: String, amount: UFix64) { + let bridgeResult = executeTransaction( + "../transactions/bridge/tokens/bridge_tokens_to_evm.cdc", + [contractAddr, contractName, amount], + signer + ) + Test.expect(bridgeResult, Test.beSucceeded()) + + // TODO: Add event assertions on bridge events. We can't currently import the event types to do this + // so state assertions beyond call scope will need to suffice for now +} + +access(all) +fun bridgeTokensFromEVM(signer: Test.TestAccount, contractAddr: Address, contractName: String, amount: UInt256) { + let bridgeResult = executeTransaction( + "../transactions/bridge/tokens/bridge_tokens_from_evm.cdc", + [contractAddr, contractName, amount], + signer + ) + Test.expect(bridgeResult, Test.beSucceeded()) + + // TODO: Add event assertions on bridge events. We can't currently import the event types to do this + // so state assertions beyond call scope will need to suffice for now +} diff --git a/cadence/tests/serialize_nft_tests.cdc b/cadence/tests/serialize_nft_tests.cdc index 644d9456..06ad51bf 100644 --- a/cadence/tests/serialize_nft_tests.cdc +++ b/cadence/tests/serialize_nft_tests.cdc @@ -36,14 +36,14 @@ fun setup() { access(all) fun testSerializeNFTSucceeds() { let setupResult = executeTransaction( - "../transactions/example-assets/setup_collection.cdc", + "../transactions/example-assets/example-nft/setup_collection.cdc", [], alice ) Test.expect(setupResult, Test.beSucceeded()) let mintResult = executeTransaction( - "../transactions/example-assets/mint_nft.cdc", + "../transactions/example-assets/example-nft/mint_nft.cdc", [alice.address, "ExampleNFT", "Example NFT Collection", "https://flow.com/examplenft.jpg", [], [], []], admin ) diff --git a/cadence/tests/test_helpers.cdc b/cadence/tests/test_helpers.cdc index 141dc73a..3614d7e2 100644 --- a/cadence/tests/test_helpers.cdc +++ b/cadence/tests/test_helpers.cdc @@ -2,27 +2,33 @@ /// 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 evmUpdateCode = "696d706f72742043727970746f0a0a696d706f7274204e6f6e46756e6769626c65546f6b656e2066726f6d203078303030303030303030303030303030310a696d706f72742046756e6769626c65546f6b656e2066726f6d203078303030303030303030303030303030320a696d706f727420466c6f77546f6b656e2066726f6d203078303030303030303030303030303030330a0a61636365737328616c6c290a636f6e74726163742045564d207b0a0a202020202f2f20456e7469746c656d656e747320656e61626c696e672066696e65722d6772616e65642061636365737320636f6e74726f6c206f6e206120436164656e63654f776e65644163636f756e740a2020202061636365737328616c6c2920656e7469746c656d656e742056616c69646174650a2020202061636365737328616c6c2920656e7469746c656d656e742057697468647261770a2020202061636365737328616c6c2920656e7469746c656d656e742043616c6c0a2020202061636365737328616c6c2920656e7469746c656d656e74204465706c6f790a2020202061636365737328616c6c2920656e7469746c656d656e74204f776e65720a2020202061636365737328616c6c2920656e7469746c656d656e74204272696467650a0a2020202061636365737328616c6c290a202020206576656e7420436164656e63654f776e65644163636f756e7443726561746564286164647265737342797465733a205b55496e74383b2032305d290a0a202020202f2f2f2045564d4164647265737320697320616e2045564d2d636f6d70617469626c6520616464726573730a2020202061636365737328616c6c290a202020207374727563742045564d41646472657373207b0a0a20202020202020202f2f2f204279746573206f662074686520616464726573730a202020202020202061636365737328616c6c290a20202020202020206c65742062797465733a205b55496e74383b2032305d0a0a20202020202020202f2f2f20436f6e737472756374732061206e65772045564d20616464726573732066726f6d2074686520676976656e206279746520726570726573656e746174696f6e0a20202020202020207669657720696e69742862797465733a205b55496e74383b2032305d29207b0a20202020202020202020202073656c662e6279746573203d2062797465730a20202020202020207d0a0a20202020202020202f2f2f2042616c616e6365206f662074686520616464726573730a202020202020202061636365737328616c6c290a2020202020202020766965772066756e2062616c616e636528293a2042616c616e6365207b0a2020202020202020202020206c65742062616c616e6365203d20496e7465726e616c45564d2e62616c616e6365280a20202020202020202020202020202020616464726573733a2073656c662e62797465730a202020202020202020202020290a20202020202020202020202072657475726e2042616c616e6365286174746f666c6f773a2062616c616e6365290a20202020202020207d0a202020207d0a0a2020202061636365737328616c6c290a202020207374727563742042616c616e6365207b0a0a20202020202020202f2f2f205468652062616c616e636520696e206174746f2d464c4f570a20202020202020202f2f2f204174746f2d464c4f572069732074686520736d616c6c6573742064656e6f6d696e6174696f6e206f6620464c4f5720283165313820464c4f57290a20202020202020202f2f2f2074686174206973207573656420746f2073746f7265206163636f756e742062616c616e63657320696e736964652045564d0a20202020202020202f2f2f2073696d696c617220746f207468652077617920574549206973207573656420746f2073746f72652045544820646976697369626c6520746f20313820646563696d616c20706c616365732e0a202020202020202061636365737328616c6c290a2020202020202020766172206174746f666c6f773a2055496e740a0a20202020202020202f2f2f20436f6e737472756374732061206e65772062616c616e63650a202020202020202061636365737328616c6c290a20202020202020207669657720696e6974286174746f666c6f773a2055496e7429207b0a20202020202020202020202073656c662e6174746f666c6f77203d206174746f666c6f770a20202020202020207d0a0a20202020202020202f2f2f2053657473207468652062616c616e636520627920612055466978363420283820646563696d616c20706f696e7473292c2074686520666f726d61740a20202020202020202f2f2f2074686174206973207573656420696e20436164656e636520746f2073746f726520464c4f5720746f6b656e732e0a202020202020202061636365737328616c6c290a202020202020202066756e20736574464c4f5728666c6f773a20554669783634297b0a20202020202020202020202073656c662e6174746f666c6f77203d20496e7465726e616c45564d2e63617374546f4174746f464c4f572862616c616e63653a20666c6f77290a20202020202020207d0a0a20202020202020202f2f2f204361737473207468652062616c616e636520746f2061205546697836342028726f756e64696e6720646f776e290a20202020202020202f2f2f205761726e696e67212063617374696e6720612062616c616e636520746f20612055466978363420776869636820737570706f7274732061206c6f776572206c6576656c206f6620707265636973696f6e0a20202020202020202f2f2f20283820646563696d616c20706f696e747320696e20636f6d7061726520746f20313829206d6967687420726573756c7420696e20726f756e64696e6720646f776e206572726f722e0a20202020202020202f2f2f205573652074686520746f4174746f466c6f772066756e6374696f6e20696620796f752063617265206e656564206d6f72652061636375726163792e0a202020202020202061636365737328616c6c290a2020202020202020766965772066756e20696e464c4f5728293a20554669783634207b0a20202020202020202020202072657475726e20496e7465726e616c45564d2e63617374546f464c4f572862616c616e63653a2073656c662e6174746f666c6f77290a20202020202020207d0a0a20202020202020202f2f2f2052657475726e73207468652062616c616e636520696e204174746f2d464c4f570a202020202020202061636365737328616c6c290a2020202020202020766965772066756e20696e4174746f464c4f5728293a2055496e74207b0a20202020202020202020202072657475726e2073656c662e6174746f666c6f770a20202020202020207d0a202020207d0a0a202020202f2f2f207265706f7274732074686520737461747573206f662065766d20657865637574696f6e2e0a2020202061636365737328616c6c2920656e756d205374617475733a2055496e7438207b0a20202020202020202f2f2f2069732028726172656c79292072657475726e6564207768656e2073746174757320697320756e6b6e6f776e0a20202020202020202f2f2f20616e6420736f6d657468696e672068617320676f6e6520766572792077726f6e672e0a202020202020202061636365737328616c6c29206361736520756e6b6e6f776e0a0a20202020202020202f2f2f2069732072657475726e6564207768656e20657865637574696f6e206f6620616e2065766d207472616e73616374696f6e2f63616c6c0a20202020202020202f2f2f20686173206661696c6564206174207468652076616c69646174696f6e20737465702028652e672e206e6f6e6365206d69736d61746368292e0a20202020202020202f2f2f20416e20696e76616c6964207472616e73616374696f6e2f63616c6c2069732072656a656374656420746f2062652065786563757465640a20202020202020202f2f2f206f7220626520696e636c7564656420696e206120626c6f636b2e0a202020202020202061636365737328616c6c29206361736520696e76616c69640a0a20202020202020202f2f2f2069732072657475726e6564207768656e20657865637574696f6e206f6620616e2065766d207472616e73616374696f6e2f63616c6c0a20202020202020202f2f2f20686173206265656e207375636365737366756c206275742074686520766d20686173207265706f7274656420616e206572726f722061730a20202020202020202f2f2f20746865206f7574636f6d65206f6620657865637574696f6e2028652e672e2072756e6e696e67206f7574206f6620676173292e0a20202020202020202f2f2f2041206661696c65642074782f63616c6c20697320696e636c7564656420696e206120626c6f636b2e0a20202020202020202f2f2f204e6f746520746861742072657375626d697373696f6e206f662061206661696c6564207472616e73616374696f6e20776f756c640a20202020202020202f2f2f20726573756c7420696e20696e76616c69642073746174757320696e20746865207365636f6e6420617474656d70742c20676976656e0a20202020202020202f2f2f20746865206e6f6e636520776f756c6420626520636f6d6520696e76616c69642e0a202020202020202061636365737328616c6c292063617365206661696c65640a0a20202020202020202f2f2f2069732072657475726e6564207768656e20657865637574696f6e206f6620616e2065766d207472616e73616374696f6e2f63616c6c0a20202020202020202f2f2f20686173206265656e207375636365737366756c20616e64206e6f206572726f72206973207265706f727465642062792074686520766d2e0a202020202020202061636365737328616c6c292063617365207375636365737366756c0a202020207d0a0a202020202f2f2f207265706f72747320746865206f7574636f6d65206f662065766d207472616e73616374696f6e2f63616c6c20657865637574696f6e20617474656d70740a2020202061636365737328616c6c292073747275637420526573756c74207b0a20202020202020202f2f2f20737461747573206f662074686520657865637574696f6e0a202020202020202061636365737328616c6c290a20202020202020206c6574207374617475733a205374617475730a0a20202020202020202f2f2f206572726f7220636f646520286572726f7220636f6465207a65726f206d65616e73206e6f206572726f72290a202020202020202061636365737328616c6c290a20202020202020206c6574206572726f72436f64653a2055496e7436340a0a20202020202020202f2f2f2072657475726e732074686520616d6f756e74206f6620676173206d65746572656420647572696e670a20202020202020202f2f2f2065766d20657865637574696f6e0a202020202020202061636365737328616c6c290a20202020202020206c657420676173557365643a2055496e7436340a0a20202020202020202f2f2f2072657475726e7320746865206461746120746861742069732072657475726e65642066726f6d0a20202020202020202f2f2f207468652065766d20666f72207468652063616c6c2e20466f7220636f612e6465706c6f790a20202020202020202f2f2f2063616c6c732069742072657475726e73207468652061646472657373206279746573206f66207468650a20202020202020202f2f2f206e65776c79206465706c6f79656420636f6e74726163742e0a202020202020202061636365737328616c6c290a20202020202020206c657420646174613a205b55496e74385d0a0a2020202020202020696e6974280a2020202020202020202020207374617475733a205374617475732c0a2020202020202020202020206572726f72436f64653a2055496e7436342c0a202020202020202020202020676173557365643a2055496e7436342c0a202020202020202020202020646174613a205b55496e74385d0a202020202020202029207b0a20202020202020202020202073656c662e737461747573203d207374617475730a20202020202020202020202073656c662e6572726f72436f6465203d206572726f72436f64650a20202020202020202020202073656c662e67617355736564203d20676173557365640a20202020202020202020202073656c662e64617461203d20646174610a20202020202020207d0a202020207d0a0a2020202061636365737328616c6c290a202020207265736f7572636520696e74657266616365204164647265737361626c65207b0a20202020202020202f2f2f205468652045564d20616464726573730a202020202020202061636365737328616c6c290a2020202020202020766965772066756e206164647265737328293a2045564d416464726573730a202020207d0a0a2020202061636365737328616c6c290a202020207265736f7572636520436164656e63654f776e65644163636f756e743a204164647265737361626c65207b0a0a20202020202020206163636573732873656c66290a2020202020202020766172206164647265737342797465733a205b55496e74383b2032305d0a0a2020202020202020696e69742829207b0a2020202020202020202020202f2f206164647265737320697320696e697469616c6c792073657420746f207a65726f0a2020202020202020202020202f2f206275742075706461746564207468726f75676820696e697441646472657373206c617465720a2020202020202020202020202f2f207765206861766520746f20646f20746869732073696e6365207765206e656564207265736f75726365206964202875756964290a2020202020202020202020202f2f20746f2063616c63756c617465207468652045564d206164647265737320666f72207468697320636164656e6365206f776e6564206163636f756e740a20202020202020202020202073656c662e616464726573734279746573203d205b302c20302c20302c20302c20302c20302c20302c20302c20302c20302c20302c20302c20302c20302c20302c20302c20302c20302c20302c20305d0a20202020202020207d0a0a202020202020202061636365737328636f6e7472616374290a202020202020202066756e20696e697441646472657373286164647265737342797465733a205b55496e74383b2032305d29207b0a20202020202020202020202f2f206f6e6c7920616c6c6f7720736574206164647265737320666f72207468652066697273742074696d650a20202020202020202020202f2f20636865636b206164647265737320697320656d7074790a202020202020202020202020666f72206974656d20696e2073656c662e616464726573734279746573207b0a20202020202020202020202020202020617373657274286974656d203d3d20302c206d6573736167653a2022616464726573732062797465206973206e6f7420656d70747922290a2020202020202020202020207d0a202020202020202020202073656c662e616464726573734279746573203d206164647265737342797465730a20202020202020207d0a0a20202020202020202f2f2f205468652045564d2061646472657373206f662074686520636164656e6365206f776e6564206163636f756e740a202020202020202061636365737328616c6c290a2020202020202020766965772066756e206164647265737328293a2045564d41646472657373207b0a2020202020202020202020202f2f20416c77617973206372656174652061206e65772045564d4164647265737320696e7374616e63650a20202020202020202020202072657475726e2045564d416464726573732862797465733a2073656c662e616464726573734279746573290a20202020202020207d0a0a20202020202020202f2f2f204765742062616c616e6365206f662074686520636164656e6365206f776e6564206163636f756e740a202020202020202061636365737328616c6c290a2020202020202020766965772066756e2062616c616e636528293a2042616c616e6365207b0a20202020202020202020202072657475726e2073656c662e6164647265737328292e62616c616e636528290a20202020202020207d0a0a20202020202020202f2f2f204465706f736974732074686520676976656e207661756c7420696e746f2074686520636164656e6365206f776e6564206163636f756e7427732062616c616e63650a202020202020202061636365737328616c6c290a202020202020202066756e206465706f7369742866726f6d3a2040466c6f77546f6b656e2e5661756c7429207b0a202020202020202020202020496e7465726e616c45564d2e6465706f736974280a2020202020202020202020202020202066726f6d3a203c2d66726f6d2c0a20202020202020202020202020202020746f3a2073656c662e6164647265737342797465730a202020202020202020202020290a20202020202020207d0a0a20202020202020202f2f2f205468652045564d2061646472657373206f662074686520636164656e6365206f776e6564206163636f756e7420626568696e6420616e20656e7469746c656d656e742c20616374696e672061732070726f6f66206f66206163636573730a2020202020202020616363657373284f776e6572207c2056616c6964617465290a2020202020202020766965772066756e2070726f7465637465644164647265737328293a2045564d41646472657373207b0a20202020202020202020202072657475726e2073656c662e6164647265737328290a20202020202020207d0a0a20202020202020202f2f2f20576974686472617773207468652062616c616e63652066726f6d2074686520636164656e6365206f776e6564206163636f756e7427732062616c616e63650a20202020202020202f2f2f204e6f7465207468617420616d6f756e747320736d616c6c6572207468616e2031306e4620283130652d38292063616e27742062652077697468647261776e0a20202020202020202f2f2f20676976656e207468617420466c6f7720546f6b656e205661756c747320757365205546697836347320746f2073746f72652062616c616e6365732e0a20202020202020202f2f2f2049662074686520676976656e2062616c616e636520636f6e76657273696f6e20746f2055466978363420726573756c747320696e0a20202020202020202f2f2f20726f756e64696e67206572726f722c20746869732066756e6374696f6e20776f756c64206661696c2e0a2020202020202020616363657373284f776e6572207c205769746864726177290a202020202020202066756e2077697468647261772862616c616e63653a2042616c616e6365293a2040466c6f77546f6b656e2e5661756c74207b0a2020202020202020202020206c6574207661756c74203c2d20496e7465726e616c45564d2e7769746864726177280a2020202020202020202020202020202066726f6d3a2073656c662e6164647265737342797465732c0a20202020202020202020202020202020616d6f756e743a2062616c616e63652e6174746f666c6f770a20202020202020202020202029206173212040466c6f77546f6b656e2e5661756c740a20202020202020202020202072657475726e203c2d7661756c740a20202020202020207d0a0a20202020202020202f2f2f204465706c6f7973206120636f6e747261637420746f207468652045564d20656e7669726f6e6d656e742e0a20202020202020202f2f2f2052657475726e73207468652061646472657373206f6620746865206e65776c79206465706c6f79656420636f6e74726163740a2020202020202020616363657373284f776e6572207c204465706c6f79290a202020202020202066756e206465706c6f79280a202020202020202020202020636f64653a205b55496e74385d2c0a2020202020202020202020206761734c696d69743a2055496e7436342c0a20202020202020202020202076616c75653a2042616c616e63650a2020202020202020293a2045564d41646472657373207b0a2020202020202020202020206c657420616464726573734279746573203d20496e7465726e616c45564d2e6465706c6f79280a2020202020202020202020202020202066726f6d3a2073656c662e6164647265737342797465732c0a20202020202020202020202020202020636f64653a20636f64652c0a202020202020202020202020202020206761734c696d69743a206761734c696d69742c0a2020202020202020202020202020202076616c75653a2076616c75652e6174746f666c6f770a202020202020202020202020290a20202020202020202020202072657475726e2045564d416464726573732862797465733a20616464726573734279746573290a20202020202020207d0a0a20202020202020202f2f2f2043616c6c7320612066756e6374696f6e20776974682074686520676976656e20646174612e0a20202020202020202f2f2f2054686520657865637574696f6e206973206c696d697465642062792074686520676976656e20616d6f756e74206f66206761730a2020202020202020616363657373284f776e6572207c2043616c6c290a202020202020202066756e2063616c6c280a202020202020202020202020746f3a2045564d416464726573732c0a202020202020202020202020646174613a205b55496e74385d2c0a2020202020202020202020206761734c696d69743a2055496e7436342c0a20202020202020202020202076616c75653a2042616c616e63650a2020202020202020293a20526573756c74207b0a20202020202020202020202072657475726e20496e7465726e616c45564d2e63616c6c280a2020202020202020202020202020202066726f6d3a2073656c662e6164647265737342797465732c0a20202020202020202020202020202020746f3a20746f2e62797465732c0a20202020202020202020202020202020646174613a20646174612c0a202020202020202020202020202020206761734c696d69743a206761734c696d69742c0a2020202020202020202020202020202076616c75653a2076616c75652e6174746f666c6f770a202020202020202020202020292061732120526573756c740a20202020202020207d0a0a20202020202020202f2f2f20427269646765732074686520676976656e204e465420746f207468652045564d20656e7669726f6e6d656e742c20726571756972696e6720612050726f76696465722066726f6d20776869636820746f20776974686472617720612066656520746f2066756c66696c6c0a20202020202020202f2f2f207468652062726964676520726571756573740a202020202020202061636365737328616c6c290a202020202020202066756e206465706f7369744e4654280a2020202020202020202020206e66743a20407b4e6f6e46756e6769626c65546f6b656e2e4e46547d2c0a20202020202020202020202066656550726f76696465723a20617574682846756e6769626c65546f6b656e2e57697468647261772920267b46756e6769626c65546f6b656e2e50726f76696465727d0a202020202020202029207b0a20202020202020202020202045564d2e626f72726f774272696467654163636573736f7228292e6465706f7369744e4654286e66743a203c2d6e66742c20746f3a2073656c662e6164647265737328292c2066656550726f76696465723a2066656550726f7669646572290a20202020202020207d0a0a20202020202020202f2f2f20427269646765732074686520676976656e204e465420746f207468652045564d20656e7669726f6e6d656e742c20726571756972696e6720612050726f76696465722066726f6d20776869636820746f20776974686472617720612066656520746f2066756c66696c6c0a20202020202020202f2f2f207468652062726964676520726571756573740a2020202020202020616363657373284f776e6572207c20427269646765290a202020202020202066756e2077697468647261774e4654280a202020202020202020202020747970653a20547970652c0a20202020202020202020202069643a2055496e743235362c0a20202020202020202020202066656550726f76696465723a20617574682846756e6769626c65546f6b656e2e57697468647261772920267b46756e6769626c65546f6b656e2e50726f76696465727d0a2020202020202020293a20407b4e6f6e46756e6769626c65546f6b656e2e4e46547d207b0a20202020202020202020202072657475726e203c2d2045564d2e626f72726f774272696467654163636573736f7228292e77697468647261774e4654280a2020202020202020202020202020202063616c6c65723a202673656c6620617320617574682843616c6c292026436164656e63654f776e65644163636f756e742c0a20202020202020202020202020202020747970653a20747970652c0a2020202020202020202020202020202069643a2069642c0a2020202020202020202020202020202066656550726f76696465723a2066656550726f76696465720a202020202020202020202020290a20202020202020207d0a202020207d0a0a202020202f2f2f20437265617465732061206e657720636164656e6365206f776e6564206163636f756e740a2020202061636365737328616c6c290a2020202066756e20637265617465436164656e63654f776e65644163636f756e7428293a2040436164656e63654f776e65644163636f756e74207b0a20202020202020206c657420616363203c2d63726561746520436164656e63654f776e65644163636f756e7428290a20202020202020206c65742061646472203d20496e7465726e616c45564d2e637265617465436164656e63654f776e65644163636f756e7428757569643a206163632e75756964290a20202020202020206163632e696e697441646472657373286164647265737342797465733a2061646472290a2020202020202020656d697420436164656e63654f776e65644163636f756e7443726561746564286164647265737342797465733a2061646472290a202020202020202072657475726e203c2d6163630a202020207d0a0a202020202f2f2f2052756e7320616e206120524c502d656e636f6465642045564d207472616e73616374696f6e2c2064656475637473207468652067617320666565732c0a202020202f2f2f20616e64206465706f736974732074686520676173206665657320696e746f207468652070726f766964656420636f696e6261736520616464726573732e0a2020202061636365737328616c6c290a2020202066756e2072756e2874783a205b55496e74385d2c20636f696e626173653a2045564d41646472657373293a20526573756c74207b0a202020202020202072657475726e20496e7465726e616c45564d2e72756e280a2020202020202020202020202020202074783a2074782c0a20202020202020202020202020202020636f696e626173653a20636f696e626173652e62797465730a2020202020202020292061732120526573756c740a202020207d0a0a202020202f2f2f206d75737452756e2072756e7320746865207472616e73616374696f6e207573696e672045564d2e72756e207965742069740a202020202f2f2f20726f6c6c6261636b2069662074686520747820657865637574696f6e2073746174757320697320756e6b6e6f776e206f7220696e76616c69642e0a202020202f2f2f204e6f746520746861742074686973206d6574686f6420646f6573206e6f7420726f6c6c6261636b206966207472616e73616374696f6e0a202020202f2f2f2069732065786563757465642062757420616e20766d206572726f72206973207265706f7274656420617320746865206f7574636f6d650a202020202f2f2f206f662074686520657865637574696f6e20287374617475733a206661696c6564292e0a2020202061636365737328616c6c290a2020202066756e206d75737452756e2874783a205b55496e74385d2c20636f696e626173653a2045564d41646472657373293a20526573756c74207b0a20202020202020206c65742072756e526573756c74203d2073656c662e72756e2874783a2074782c20636f696e626173653a20636f696e62617365290a2020202020202020617373657274280a20202020202020202020202072756e526573756c742e737461747573203d3d205374617475732e6661696c6564207c7c2072756e526573756c742e737461747573203d3d205374617475732e7375636365737366756c2c0a2020202020202020202020206d6573736167653a20227478206973206e6f742076616c696420666f7220657865637574696f6e220a2020202020202020290a202020202020202072657475726e2072756e526573756c740a202020207d0a0a2020202061636365737328616c6c290a2020202066756e20656e636f6465414249285f2076616c7565733a205b416e795374727563745d293a205b55496e74385d207b0a202020202020202072657475726e20496e7465726e616c45564d2e656e636f64654142492876616c756573290a202020207d0a0a2020202061636365737328616c6c290a2020202066756e206465636f64654142492874797065733a205b547970655d2c20646174613a205b55496e74385d293a205b416e795374727563745d207b0a202020202020202072657475726e20496e7465726e616c45564d2e6465636f64654142492874797065733a2074797065732c20646174613a2064617461290a202020207d0a0a2020202061636365737328616c6c290a2020202066756e20656e636f6465414249576974685369676e6174757265280a20202020202020205f207369676e61747572653a20537472696e672c0a20202020202020205f2076616c7565733a205b416e795374727563745d0a20202020293a205b55496e74385d207b0a20202020202020206c6574206d6574686f644944203d2048617368416c676f726974686d2e4b454343414b5f3235362e68617368280a2020202020202020202020207369676e61747572652e757466380a2020202020202020292e736c6963652866726f6d3a20302c207570546f3a2034290a20202020202020206c657420617267756d656e7473203d20496e7465726e616c45564d2e656e636f64654142492876616c756573290a0a202020202020202072657475726e206d6574686f6449442e636f6e63617428617267756d656e7473290a202020207d0a0a2020202061636365737328616c6c290a2020202066756e206465636f6465414249576974685369676e6174757265280a20202020202020205f207369676e61747572653a20537472696e672c0a202020202020202074797065733a205b547970655d2c0a2020202020202020646174613a205b55496e74385d0a20202020293a205b416e795374727563745d207b0a20202020202020206c6574206d6574686f644944203d2048617368416c676f726974686d2e4b454343414b5f3235362e68617368280a2020202020202020202020207369676e61747572652e757466380a2020202020202020292e736c6963652866726f6d3a20302c207570546f3a2034290a0a2020202020202020666f72206279746520696e206d6574686f644944207b0a2020202020202020202020206966206279746520213d20646174612e72656d6f766546697273742829207b0a2020202020202020202020202020202070616e696328227369676e6174757265206d69736d6174636822290a2020202020202020202020207d0a20202020202020207d0a0a202020202020202072657475726e20496e7465726e616c45564d2e6465636f64654142492874797065733a2074797065732c20646174613a2064617461290a202020207d0a0a202020202f2f2f2056616c69646174696f6e526573756c742072657475726e732074686520726573756c74206f6620434f41206f776e6572736869702070726f6f662076616c69646174696f6e0a2020202061636365737328616c6c290a202020207374727563742056616c69646174696f6e526573756c74207b0a202020202020202061636365737328616c6c290a20202020202020206c657420697356616c69643a20426f6f6c0a0a202020202020202061636365737328616c6c290a20202020202020206c65742070726f626c656d3a20537472696e673f0a0a2020202020202020696e697428697356616c69643a20426f6f6c2c2070726f626c656d3a20537472696e673f29207b0a20202020202020202020202073656c662e697356616c6964203d20697356616c69640a20202020202020202020202073656c662e70726f626c656d203d2070726f626c656d0a20202020202020207d0a202020207d0a0a202020202f2f2f2076616c6964617465434f414f776e65727368697050726f6f662076616c696461746573206120434f41206f776e6572736869702070726f6f660a2020202061636365737328616c6c290a2020202066756e2076616c6964617465434f414f776e65727368697050726f6f66280a2020202020202020616464726573733a20416464726573732c0a2020202020202020706174683a205075626c6963506174682c0a20202020202020207369676e6564446174613a205b55496e74385d2c0a20202020202020206b6579496e64696365733a205b55496e7436345d2c0a20202020202020207369676e6174757265733a205b5b55496e74385d5d2c0a202020202020202065766d416464726573733a205b55496e74383b2032305d0a20202020293a2056616c69646174696f6e526573756c74207b0a0a20202020202020202f2f206d616b65207369676e6174757265207365742066697273740a20202020202020202f2f20636865636b206e756d626572206f66207369676e617475726573206d617463686573206e756d626572206f66206b657920696e64696365730a20202020202020206966206b6579496e64696365732e6c656e67746820213d207369676e6174757265732e6c656e677468207b0a20202020202020202020202072657475726e2056616c69646174696f6e526573756c74280a20202020202020202020202020202020697356616c69643a2066616c73652c0a2020202020202020202020202020202070726f626c656d3a20226b657920696e64696365732073697a6520646f65736e2774206d6174636820746865207369676e617475726573220a202020202020202020202020290a20202020202020207d0a0a2020202020202020766172207369676e61747572655365743a205b43727970746f2e4b65794c6973745369676e61747572655d203d205b5d0a2020202020202020666f72207369676e6174757265496e6465782c207369676e617475726520696e207369676e6174757265737b0a2020202020202020202020207369676e61747572655365742e617070656e642843727970746f2e4b65794c6973745369676e6174757265280a202020202020202020202020202020206b6579496e6465783a20496e74286b6579496e64696365735b7369676e6174757265496e6465785d292c0a202020202020202020202020202020207369676e61747572653a207369676e61747572650a20202020202020202020202029290a20202020202020207d0a0a20202020202020202f2f206665746368206163636f756e740a20202020202020206c657420616363203d206765744163636f756e742861646472657373290a0a20202020202020202f2f20636f6e737472756374696e67206b6579206c6973740a20202020202020206c6574206b65794c697374203d2043727970746f2e4b65794c69737428290a2020202020202020666f72207369676e617475726520696e207369676e6174757265536574207b0a2020202020202020202020206c6574206b6579203d206163632e6b6579732e676574286b6579496e6465783a207369676e61747572652e6b6579496e64657829210a20202020202020202020202061737365727428216b65792e69735265766f6b65642c206d6573736167653a20227265766f6b6564206b6579206973207573656422290a2020202020202020202020206b65794c6973742e616464280a20202020202020202020202020206b65792e7075626c69634b65792c0a202020202020202020202020202068617368416c676f726974686d3a206b65792e68617368416c676f726974686d2c0a20202020202020202020202020207765696768743a206b65792e7765696768742c0a2020202020202020202020290a20202020202020207d0a0a20202020202020206c657420697356616c6964203d206b65794c6973742e766572696679280a2020202020202020202020207369676e61747572655365743a207369676e61747572655365742c0a2020202020202020202020207369676e6564446174613a207369676e6564446174612c0a202020202020202020202020646f6d61696e53657061726174696f6e5461673a2022464c4f572d56302e302d75736572220a2020202020202020290a0a202020202020202069662021697356616c69647b0a20202020202020202020202072657475726e2056616c69646174696f6e526573756c74280a20202020202020202020202020202020697356616c69643a2066616c73652c0a2020202020202020202020202020202070726f626c656d3a202274686520676976656e207369676e61747572657320617265206e6f742076616c6964206f722070726f7669646520656e6f75676820776569676874220a202020202020202020202020290a20202020202020207d0a0a20202020202020206c657420636f61526566203d206163632e6361706162696c69746965732e626f72726f773c2645564d2e436164656e63654f776e65644163636f756e743e2870617468290a0a2020202020202020696620636f61526566203d3d206e696c207b0a2020202020202020202020202072657475726e2056616c69646174696f6e526573756c74280a2020202020202020202020202020202020697356616c69643a2066616c73652c0a202020202020202020202020202020202070726f626c656d3a2022636f756c64206e6f7420626f72726f7720627269646765206163636f756e742773207265736f75726365220a20202020202020202020202020290a20202020202020207d0a0a20202020202020202f2f207665726966792065766d2061646472657373206d61746368696e670a20202020202020207661722061646472203d20636f61526566212e6164647265737328290a2020202020202020666f7220696e6465782c206974656d20696e20636f61526566212e6164647265737328292e6279746573207b0a2020202020202020202020206966206974656d20213d2065766d416464726573735b696e6465785d207b0a2020202020202020202020202020202072657475726e2056616c69646174696f6e526573756c74280a2020202020202020202020202020202020202020697356616c69643a2066616c73652c0a202020202020202020202020202020202020202070726f626c656d3a202265766d2061646472657373206d69736d61746368220a20202020202020202020202020202020290a2020202020202020202020207d0a20202020202020207d0a0a202020202020202072657475726e2056616c69646174696f6e526573756c74280a202020202020202020202020697356616c69643a20747275652c0a20202020202020202020202070726f626c656d3a206e696c0a2020202020202020290a202020207d0a0a202020202f2f2f2052657475726e732061207265666572656e636520746f20746865204272696467654163636573736f722064657369676e6174656420666f7220696e7465726e616c206272696467652072657175657374730a202020206163636573732873656c66290a20202020766965772066756e20626f72726f774272696467654163636573736f7228293a2061757468284272696467652920267b4272696467654163636573736f727d207b0a202020202020202072657475726e2073656c662e6163636f756e742e73746f726167652e626f72726f773c61757468284272696467652920267b4272696467654163636573736f727d3e2866726f6d3a202f73746f726167652f65766d427269646765526f75746572290a2020202020202020202020203f3f2070616e69632822436f756c64206e6f7420626f72726f77207265666572656e636520746f207468652045564d2062726964676522290a202020207d0a0a202020202f2f2f20496e7465726661636520666f722061207265736f75726365207768696368206163747320617320616e20656e747279706f696e7420746f2074686520564d206272696467650a2020202061636365737328616c6c290a202020207265736f7572636520696e74657266616365204272696467654163636573736f72207b0a0a20202020202020202f2f2f20456e64706f696e7420656e61626c696e67207468652062726964696e67206f6620616e204e465420746f2045564d0a202020202020202061636365737328427269646765290a202020202020202066756e206465706f7369744e4654280a2020202020202020202020206e66743a20407b4e6f6e46756e6769626c65546f6b656e2e4e46547d2c0a202020202020202020202020746f3a2045564d2e45564d416464726573732c0a20202020202020202020202066656550726f76696465723a20617574682846756e6769626c65546f6b656e2e57697468647261772920267b46756e6769626c65546f6b656e2e50726f76696465727d0a2020202020202020290a0a20202020202020202f2f2f20456e64706f696e7420656e61626c696e67207468652062726964696e67206f6620616e204e46542066726f6d2045564d0a202020202020202061636365737328427269646765290a202020202020202066756e2077697468647261774e4654280a20202020202020202020202063616c6c65723a20617574682843616c6c292026436164656e63654f776e65644163636f756e742c0a202020202020202020202020747970653a20547970652c0a20202020202020202020202069643a2055496e743235362c0a20202020202020202020202066656550726f76696465723a20617574682846756e6769626c65546f6b656e2e57697468647261772920267b46756e6769626c65546f6b656e2e50726f76696465727d0a2020202020202020293a20407b4e6f6e46756e6769626c65546f6b656e2e4e46547d0a202020207d0a7d0a" +access(all) let evmUpdateCode = "696d706f72742043727970746f0a696d706f7274204e6f6e46756e6769626c65546f6b656e2066726f6d203078303030303030303030303030303030310a696d706f72742046756e6769626c65546f6b656e2066726f6d203078303030303030303030303030303030320a696d706f727420466c6f77546f6b656e2066726f6d203078303030303030303030303030303030330a0a61636365737328616c6c290a636f6e74726163742045564d207b0a0a202020202f2f20456e7469746c656d656e747320656e61626c696e672066696e65722d6772616e65642061636365737320636f6e74726f6c206f6e206120436164656e63654f776e65644163636f756e740a2020202061636365737328616c6c2920656e7469746c656d656e742056616c69646174650a2020202061636365737328616c6c2920656e7469746c656d656e742057697468647261770a2020202061636365737328616c6c2920656e7469746c656d656e742043616c6c0a2020202061636365737328616c6c2920656e7469746c656d656e74204465706c6f790a2020202061636365737328616c6c2920656e7469746c656d656e74204f776e65720a2020202061636365737328616c6c2920656e7469746c656d656e74204272696467650a0a2020202061636365737328616c6c290a202020206576656e7420436164656e63654f776e65644163636f756e7443726561746564286164647265737342797465733a205b55496e74383b2032305d290a0a202020202f2f2f20464c4f57546f6b656e734465706f736974656420697320656d6974746564207768656e20464c4f5720746f6b656e7320697320627269646765640a202020202f2f2f20696e746f207468652045564d20656e7669726f6e6d656e742e204e6f746520746861742074686973206576656e74206973206e6f7420656d69747465640a202020202f2f2f20666f72207472616e73666572206f6620666c6f7720746f6b656e73206265747765656e2074776f2045564d206164647265737365732e0a2020202061636365737328616c6c290a202020206576656e7420464c4f57546f6b656e734465706f7369746564286164647265737342797465733a205b55496e74383b2032305d2c20616d6f756e743a20554669783634290a0a202020202f2f2f20464c4f57546f6b656e7357697468647261776e20697320656d6974746564207768656e20464c4f5720746f6b656e732061726520627269646765640a202020202f2f2f206f7574206f66207468652045564d20656e7669726f6e6d656e742e204e6f746520746861742074686973206576656e74206973206e6f7420656d69747465640a202020202f2f2f20666f72207472616e73666572206f6620666c6f7720746f6b656e73206265747765656e2074776f2045564d206164647265737365732e0a2020202061636365737328616c6c290a202020206576656e7420464c4f57546f6b656e7357697468647261776e286164647265737342797465733a205b55496e74383b2032305d2c20616d6f756e743a20554669783634290a0a202020202f2f2f2045564d4164647265737320697320616e2045564d2d636f6d70617469626c6520616464726573730a2020202061636365737328616c6c290a202020207374727563742045564d41646472657373207b0a0a20202020202020202f2f2f204279746573206f662074686520616464726573730a202020202020202061636365737328616c6c290a20202020202020206c65742062797465733a205b55496e74383b2032305d0a0a20202020202020202f2f2f20436f6e737472756374732061206e65772045564d20616464726573732066726f6d2074686520676976656e206279746520726570726573656e746174696f6e0a20202020202020207669657720696e69742862797465733a205b55496e74383b2032305d29207b0a20202020202020202020202073656c662e6279746573203d2062797465730a20202020202020207d0a0a20202020202020202f2f2f2042616c616e6365206f662074686520616464726573730a202020202020202061636365737328616c6c290a2020202020202020766965772066756e2062616c616e636528293a2042616c616e6365207b0a2020202020202020202020206c65742062616c616e6365203d20496e7465726e616c45564d2e62616c616e6365280a20202020202020202020202020202020616464726573733a2073656c662e62797465730a202020202020202020202020290a20202020202020202020202072657475726e2042616c616e6365286174746f666c6f773a2062616c616e6365290a20202020202020207d0a0a20202020202020202f2f2f204e6f6e6365206f662074686520616464726573730a202020202020202061636365737328616c6c290a202020202020202066756e206e6f6e636528293a2055496e743634207b0a20202020202020202020202072657475726e20496e7465726e616c45564d2e6e6f6e6365280a20202020202020202020202020202020616464726573733a2073656c662e62797465730a202020202020202020202020290a20202020202020207d0a0a20202020202020202f2f2f20436f6465206f662074686520616464726573730a202020202020202061636365737328616c6c290a202020202020202066756e20636f646528293a205b55496e74385d207b0a20202020202020202020202072657475726e20496e7465726e616c45564d2e636f6465280a20202020202020202020202020202020616464726573733a2073656c662e62797465730a202020202020202020202020290a20202020202020207d0a0a20202020202020202f2f2f20436f646548617368206f662074686520616464726573730a202020202020202061636365737328616c6c290a202020202020202066756e20636f64654861736828293a205b55496e74385d207b0a20202020202020202020202072657475726e20496e7465726e616c45564d2e636f646548617368280a20202020202020202020202020202020616464726573733a2073656c662e62797465730a202020202020202020202020290a20202020202020207d0a0a20202020202020202f2f2f204465706f736974732074686520676976656e207661756c7420696e746f207468652045564d206163636f756e7420776974682074686520676976656e20616464726573730a202020202020202061636365737328616c6c290a202020202020202066756e206465706f7369742866726f6d3a2040466c6f77546f6b656e2e5661756c7429207b0a2020202020202020202020206c657420616d6f756e74203d2066726f6d2e62616c616e63650a202020202020202020202020696620616d6f756e74203d3d20302e30207b0a2020202020202020202020202020202070616e6963282263616c6c696e67206465706f7369742066756e6374696f6e207769746820616e20656d707479207661756c74206973206e6f7420616c6c6f77656422290a2020202020202020202020207d0a202020202020202020202020496e7465726e616c45564d2e6465706f736974280a2020202020202020202020202020202066726f6d3a203c2d66726f6d2c0a20202020202020202020202020202020746f3a2073656c662e62797465730a202020202020202020202020290a202020202020202020202020656d697420464c4f57546f6b656e734465706f7369746564286164647265737342797465733a2073656c662e62797465732c20616d6f756e743a20616d6f756e74290a20202020202020207d0a202020207d0a0a2020202061636365737328616c6c290a202020207374727563742042616c616e6365207b0a0a20202020202020202f2f2f205468652062616c616e636520696e206174746f2d464c4f570a20202020202020202f2f2f204174746f2d464c4f572069732074686520736d616c6c6573742064656e6f6d696e6174696f6e206f6620464c4f5720283165313820464c4f57290a20202020202020202f2f2f2074686174206973207573656420746f2073746f7265206163636f756e742062616c616e63657320696e736964652045564d0a20202020202020202f2f2f2073696d696c617220746f207468652077617920574549206973207573656420746f2073746f72652045544820646976697369626c6520746f20313820646563696d616c20706c616365732e0a202020202020202061636365737328616c6c290a2020202020202020766172206174746f666c6f773a2055496e740a0a20202020202020202f2f2f20436f6e737472756374732061206e65772062616c616e63650a202020202020202061636365737328616c6c290a20202020202020207669657720696e6974286174746f666c6f773a2055496e7429207b0a20202020202020202020202073656c662e6174746f666c6f77203d206174746f666c6f770a20202020202020207d0a0a20202020202020202f2f2f2053657473207468652062616c616e636520627920612055466978363420283820646563696d616c20706f696e7473292c2074686520666f726d61740a20202020202020202f2f2f2074686174206973207573656420696e20436164656e636520746f2073746f726520464c4f5720746f6b656e732e0a202020202020202061636365737328616c6c290a202020202020202066756e20736574464c4f5728666c6f773a20554669783634297b0a20202020202020202020202073656c662e6174746f666c6f77203d20496e7465726e616c45564d2e63617374546f4174746f464c4f572862616c616e63653a20666c6f77290a20202020202020207d0a0a20202020202020202f2f2f204361737473207468652062616c616e636520746f2061205546697836342028726f756e64696e6720646f776e290a20202020202020202f2f2f205761726e696e67212063617374696e6720612062616c616e636520746f20612055466978363420776869636820737570706f7274732061206c6f776572206c6576656c206f6620707265636973696f6e0a20202020202020202f2f2f20283820646563696d616c20706f696e747320696e20636f6d7061726520746f20313829206d6967687420726573756c7420696e20726f756e64696e6720646f776e206572726f722e0a20202020202020202f2f2f205573652074686520746f4174746f466c6f772066756e6374696f6e20696620796f752063617265206e656564206d6f72652061636375726163792e0a202020202020202061636365737328616c6c290a2020202020202020766965772066756e20696e464c4f5728293a20554669783634207b0a20202020202020202020202072657475726e20496e7465726e616c45564d2e63617374546f464c4f572862616c616e63653a2073656c662e6174746f666c6f77290a20202020202020207d0a0a20202020202020202f2f2f2052657475726e73207468652062616c616e636520696e204174746f2d464c4f570a202020202020202061636365737328616c6c290a2020202020202020766965772066756e20696e4174746f464c4f5728293a2055496e74207b0a20202020202020202020202072657475726e2073656c662e6174746f666c6f770a20202020202020207d0a0a20202020202020202f2f2f2052657475726e732074727565206966207468652062616c616e6365206973207a65726f0a202020202020202061636365737328616c6c290a202020202020202066756e2069735a65726f28293a20426f6f6c207b0a20202020202020202020202072657475726e2073656c662e6174746f666c6f77203d3d20300a20202020202020207d0a202020207d0a0a202020202f2f2f207265706f7274732074686520737461747573206f662065766d20657865637574696f6e2e0a2020202061636365737328616c6c2920656e756d205374617475733a2055496e7438207b0a20202020202020202f2f2f2069732028726172656c79292072657475726e6564207768656e2073746174757320697320756e6b6e6f776e0a20202020202020202f2f2f20616e6420736f6d657468696e672068617320676f6e6520766572792077726f6e672e0a202020202020202061636365737328616c6c29206361736520756e6b6e6f776e0a0a20202020202020202f2f2f2069732072657475726e6564207768656e20657865637574696f6e206f6620616e2065766d207472616e73616374696f6e2f63616c6c0a20202020202020202f2f2f20686173206661696c6564206174207468652076616c69646174696f6e20737465702028652e672e206e6f6e6365206d69736d61746368292e0a20202020202020202f2f2f20416e20696e76616c6964207472616e73616374696f6e2f63616c6c2069732072656a656374656420746f2062652065786563757465640a20202020202020202f2f2f206f7220626520696e636c7564656420696e206120626c6f636b2e0a202020202020202061636365737328616c6c29206361736520696e76616c69640a0a20202020202020202f2f2f2069732072657475726e6564207768656e20657865637574696f6e206f6620616e2065766d207472616e73616374696f6e2f63616c6c0a20202020202020202f2f2f20686173206265656e207375636365737366756c206275742074686520766d20686173207265706f7274656420616e206572726f722061730a20202020202020202f2f2f20746865206f7574636f6d65206f6620657865637574696f6e2028652e672e2072756e6e696e67206f7574206f6620676173292e0a20202020202020202f2f2f2041206661696c65642074782f63616c6c20697320696e636c7564656420696e206120626c6f636b2e0a20202020202020202f2f2f204e6f746520746861742072657375626d697373696f6e206f662061206661696c6564207472616e73616374696f6e20776f756c640a20202020202020202f2f2f20726573756c7420696e20696e76616c69642073746174757320696e20746865207365636f6e6420617474656d70742c20676976656e0a20202020202020202f2f2f20746865206e6f6e636520776f756c6420626520636f6d6520696e76616c69642e0a202020202020202061636365737328616c6c292063617365206661696c65640a0a20202020202020202f2f2f2069732072657475726e6564207768656e20657865637574696f6e206f6620616e2065766d207472616e73616374696f6e2f63616c6c0a20202020202020202f2f2f20686173206265656e207375636365737366756c20616e64206e6f206572726f72206973207265706f727465642062792074686520766d2e0a202020202020202061636365737328616c6c292063617365207375636365737366756c0a202020207d0a0a202020202f2f2f207265706f72747320746865206f7574636f6d65206f662065766d207472616e73616374696f6e2f63616c6c20657865637574696f6e20617474656d70740a2020202061636365737328616c6c292073747275637420526573756c74207b0a20202020202020202f2f2f20737461747573206f662074686520657865637574696f6e0a202020202020202061636365737328616c6c290a20202020202020206c6574207374617475733a205374617475730a0a20202020202020202f2f2f206572726f7220636f646520286572726f7220636f6465207a65726f206d65616e73206e6f206572726f72290a202020202020202061636365737328616c6c290a20202020202020206c6574206572726f72436f64653a2055496e7436340a0a20202020202020202f2f2f2072657475726e732074686520616d6f756e74206f6620676173206d65746572656420647572696e670a20202020202020202f2f2f2065766d20657865637574696f6e0a202020202020202061636365737328616c6c290a20202020202020206c657420676173557365643a2055496e7436340a0a20202020202020202f2f2f2072657475726e7320746865206461746120746861742069732072657475726e65642066726f6d0a20202020202020202f2f2f207468652065766d20666f72207468652063616c6c2e20466f7220636f612e6465706c6f790a20202020202020202f2f2f2063616c6c732069742072657475726e73207468652061646472657373206279746573206f66207468650a20202020202020202f2f2f206e65776c79206465706c6f79656420636f6e74726163742e0a202020202020202061636365737328616c6c290a20202020202020206c657420646174613a205b55496e74385d0a0a2020202020202020696e6974280a2020202020202020202020207374617475733a205374617475732c0a2020202020202020202020206572726f72436f64653a2055496e7436342c0a202020202020202020202020676173557365643a2055496e7436342c0a202020202020202020202020646174613a205b55496e74385d0a202020202020202029207b0a20202020202020202020202073656c662e737461747573203d207374617475730a20202020202020202020202073656c662e6572726f72436f6465203d206572726f72436f64650a20202020202020202020202073656c662e67617355736564203d20676173557365640a20202020202020202020202073656c662e64617461203d20646174610a20202020202020207d0a202020207d0a0a2020202061636365737328616c6c290a202020207265736f7572636520696e74657266616365204164647265737361626c65207b0a20202020202020202f2f2f205468652045564d20616464726573730a202020202020202061636365737328616c6c290a2020202020202020766965772066756e206164647265737328293a2045564d416464726573730a202020207d0a0a2020202061636365737328616c6c290a202020207265736f7572636520436164656e63654f776e65644163636f756e743a204164647265737361626c65207b0a0a20202020202020206163636573732873656c66290a2020202020202020766172206164647265737342797465733a205b55496e74383b2032305d0a0a2020202020202020696e69742829207b0a2020202020202020202020202f2f206164647265737320697320696e697469616c6c792073657420746f207a65726f0a2020202020202020202020202f2f206275742075706461746564207468726f75676820696e697441646472657373206c617465720a2020202020202020202020202f2f207765206861766520746f20646f20746869732073696e6365207765206e656564207265736f75726365206964202875756964290a2020202020202020202020202f2f20746f2063616c63756c617465207468652045564d206164647265737320666f72207468697320636164656e6365206f776e6564206163636f756e740a20202020202020202020202073656c662e616464726573734279746573203d205b302c20302c20302c20302c20302c20302c20302c20302c20302c20302c20302c20302c20302c20302c20302c20302c20302c20302c20302c20305d0a20202020202020207d0a0a202020202020202061636365737328636f6e7472616374290a202020202020202066756e20696e697441646472657373286164647265737342797465733a205b55496e74383b2032305d29207b0a20202020202020202020202f2f206f6e6c7920616c6c6f7720736574206164647265737320666f72207468652066697273742074696d650a20202020202020202020202f2f20636865636b206164647265737320697320656d7074790a202020202020202020202020666f72206974656d20696e2073656c662e616464726573734279746573207b0a20202020202020202020202020202020617373657274286974656d203d3d20302c206d6573736167653a2022616464726573732062797465206973206e6f7420656d70747922290a2020202020202020202020207d0a202020202020202020202073656c662e616464726573734279746573203d206164647265737342797465730a20202020202020207d0a0a20202020202020202f2f2f205468652045564d2061646472657373206f662074686520636164656e6365206f776e6564206163636f756e740a202020202020202061636365737328616c6c290a2020202020202020766965772066756e206164647265737328293a2045564d41646472657373207b0a2020202020202020202020202f2f20416c77617973206372656174652061206e65772045564d4164647265737320696e7374616e63650a20202020202020202020202072657475726e2045564d416464726573732862797465733a2073656c662e616464726573734279746573290a20202020202020207d0a0a20202020202020202f2f2f204765742062616c616e6365206f662074686520636164656e6365206f776e6564206163636f756e740a202020202020202061636365737328616c6c290a2020202020202020766965772066756e2062616c616e636528293a2042616c616e6365207b0a20202020202020202020202072657475726e2073656c662e6164647265737328292e62616c616e636528290a20202020202020207d0a0a20202020202020202f2f2f204465706f736974732074686520676976656e207661756c7420696e746f2074686520636164656e6365206f776e6564206163636f756e7427732062616c616e63650a202020202020202061636365737328616c6c290a202020202020202066756e206465706f7369742866726f6d3a2040466c6f77546f6b656e2e5661756c7429207b0a20202020202020202020202073656c662e6164647265737328292e6465706f7369742866726f6d3a203c2d66726f6d290a20202020202020207d0a0a20202020202020202f2f2f205468652045564d2061646472657373206f662074686520636164656e6365206f776e6564206163636f756e7420626568696e6420616e20656e7469746c656d656e742c20616374696e672061732070726f6f66206f66206163636573730a2020202020202020616363657373284f776e6572207c2056616c6964617465290a2020202020202020766965772066756e2070726f7465637465644164647265737328293a2045564d41646472657373207b0a20202020202020202020202072657475726e2073656c662e6164647265737328290a20202020202020207d0a0a20202020202020202f2f2f20576974686472617773207468652062616c616e63652066726f6d2074686520636164656e6365206f776e6564206163636f756e7427732062616c616e63650a20202020202020202f2f2f204e6f7465207468617420616d6f756e747320736d616c6c6572207468616e2031306e4620283130652d38292063616e27742062652077697468647261776e0a20202020202020202f2f2f20676976656e207468617420466c6f7720546f6b656e205661756c747320757365205546697836347320746f2073746f72652062616c616e6365732e0a20202020202020202f2f2f2049662074686520676976656e2062616c616e636520636f6e76657273696f6e20746f2055466978363420726573756c747320696e0a20202020202020202f2f2f20726f756e64696e67206572726f722c20746869732066756e6374696f6e20776f756c64206661696c2e0a2020202020202020616363657373284f776e6572207c205769746864726177290a202020202020202066756e2077697468647261772862616c616e63653a2042616c616e6365293a2040466c6f77546f6b656e2e5661756c74207b0a20202020202020202020202069662062616c616e63652e69735a65726f2829207b0a2020202020202020202020202020202070616e6963282263616c6c696e672077697468647261772066756e6374696f6e2077697468207a65726f2062616c616e6365206973206e6f7420616c6c6f77656422290a2020202020202020202020207d0a2020202020202020202020206c6574207661756c74203c2d20496e7465726e616c45564d2e7769746864726177280a2020202020202020202020202020202066726f6d3a2073656c662e6164647265737342797465732c0a20202020202020202020202020202020616d6f756e743a2062616c616e63652e6174746f666c6f770a20202020202020202020202029206173212040466c6f77546f6b656e2e5661756c740a202020202020202020202020656d697420464c4f57546f6b656e7357697468647261776e286164647265737342797465733a2073656c662e6164647265737342797465732c20616d6f756e743a2062616c616e63652e696e464c4f572829290a20202020202020202020202072657475726e203c2d7661756c740a20202020202020207d0a0a20202020202020202f2f2f204465706c6f7973206120636f6e747261637420746f207468652045564d20656e7669726f6e6d656e742e0a20202020202020202f2f2f2052657475726e73207468652061646472657373206f6620746865206e65776c79206465706c6f79656420636f6e74726163740a2020202020202020616363657373284f776e6572207c204465706c6f79290a202020202020202066756e206465706c6f79280a202020202020202020202020636f64653a205b55496e74385d2c0a2020202020202020202020206761734c696d69743a2055496e7436342c0a20202020202020202020202076616c75653a2042616c616e63650a2020202020202020293a2045564d41646472657373207b0a2020202020202020202020206c657420616464726573734279746573203d20496e7465726e616c45564d2e6465706c6f79280a2020202020202020202020202020202066726f6d3a2073656c662e6164647265737342797465732c0a20202020202020202020202020202020636f64653a20636f64652c0a202020202020202020202020202020206761734c696d69743a206761734c696d69742c0a2020202020202020202020202020202076616c75653a2076616c75652e6174746f666c6f770a202020202020202020202020290a20202020202020202020202072657475726e2045564d416464726573732862797465733a20616464726573734279746573290a20202020202020207d0a0a20202020202020202f2f2f2043616c6c7320612066756e6374696f6e20776974682074686520676976656e20646174612e0a20202020202020202f2f2f2054686520657865637574696f6e206973206c696d697465642062792074686520676976656e20616d6f756e74206f66206761730a2020202020202020616363657373284f776e6572207c2043616c6c290a202020202020202066756e2063616c6c280a202020202020202020202020746f3a2045564d416464726573732c0a202020202020202020202020646174613a205b55496e74385d2c0a2020202020202020202020206761734c696d69743a2055496e7436342c0a20202020202020202020202076616c75653a2042616c616e63650a2020202020202020293a20526573756c74207b0a20202020202020202020202072657475726e20496e7465726e616c45564d2e63616c6c280a2020202020202020202020202020202066726f6d3a2073656c662e6164647265737342797465732c0a20202020202020202020202020202020746f3a20746f2e62797465732c0a20202020202020202020202020202020646174613a20646174612c0a202020202020202020202020202020206761734c696d69743a206761734c696d69742c0a2020202020202020202020202020202076616c75653a2076616c75652e6174746f666c6f770a202020202020202020202020292061732120526573756c740a20202020202020207d0a0a20202020202020202f2f2f20427269646765732074686520676976656e204e465420746f207468652045564d20656e7669726f6e6d656e742c20726571756972696e6720612050726f76696465722066726f6d20776869636820746f20776974686472617720612066656520746f2066756c66696c6c0a20202020202020202f2f2f207468652062726964676520726571756573740a202020202020202061636365737328616c6c290a202020202020202066756e206465706f7369744e4654280a2020202020202020202020206e66743a20407b4e6f6e46756e6769626c65546f6b656e2e4e46547d2c0a20202020202020202020202066656550726f76696465723a20617574682846756e6769626c65546f6b656e2e57697468647261772920267b46756e6769626c65546f6b656e2e50726f76696465727d0a202020202020202029207b0a20202020202020202020202045564d2e626f72726f774272696467654163636573736f7228292e6465706f7369744e4654286e66743a203c2d6e66742c20746f3a2073656c662e6164647265737328292c2066656550726f76696465723a2066656550726f7669646572290a20202020202020207d0a0a20202020202020202f2f2f20427269646765732074686520676976656e204e46542066726f6d207468652045564d20656e7669726f6e6d656e742c20726571756972696e6720612050726f76696465722066726f6d20776869636820746f20776974686472617720612066656520746f2066756c66696c6c0a20202020202020202f2f2f207468652062726964676520726571756573742e204e6f74653a207468652063616c6c65722073686f756c64206f776e2074686520726571756573746564204e465420696e2045564d0a2020202020202020616363657373284f776e6572207c20427269646765290a202020202020202066756e2077697468647261774e4654280a202020202020202020202020747970653a20547970652c0a20202020202020202020202069643a2055496e743235362c0a20202020202020202020202066656550726f76696465723a20617574682846756e6769626c65546f6b656e2e57697468647261772920267b46756e6769626c65546f6b656e2e50726f76696465727d0a2020202020202020293a20407b4e6f6e46756e6769626c65546f6b656e2e4e46547d207b0a20202020202020202020202072657475726e203c2d2045564d2e626f72726f774272696467654163636573736f7228292e77697468647261774e4654280a2020202020202020202020202020202063616c6c65723a202673656c6620617320617574682843616c6c292026436164656e63654f776e65644163636f756e742c0a20202020202020202020202020202020747970653a20747970652c0a2020202020202020202020202020202069643a2069642c0a2020202020202020202020202020202066656550726f76696465723a2066656550726f76696465720a202020202020202020202020290a20202020202020207d0a0a20202020202020202f2f2f20427269646765732074686520676976656e205661756c7420746f207468652045564d20656e7669726f6e6d656e742c20726571756972696e6720612050726f76696465722066726f6d20776869636820746f20776974686472617720612066656520746f2066756c66696c6c0a20202020202020202f2f2f207468652062726964676520726571756573740a202020202020202061636365737328616c6c290a202020202020202066756e206465706f736974546f6b656e73280a2020202020202020202020207661756c743a20407b46756e6769626c65546f6b656e2e5661756c747d2c0a20202020202020202020202066656550726f76696465723a20617574682846756e6769626c65546f6b656e2e57697468647261772920267b46756e6769626c65546f6b656e2e50726f76696465727d0a202020202020202029207b0a20202020202020202020202045564d2e626f72726f774272696467654163636573736f7228292e6465706f736974546f6b656e73287661756c743a203c2d7661756c742c20746f3a2073656c662e6164647265737328292c2066656550726f76696465723a2066656550726f7669646572290a20202020202020207d0a0a20202020202020202f2f2f20427269646765732074686520676976656e2066756e6769626c6520746f6b656e732066726f6d207468652045564d20656e7669726f6e6d656e742c20726571756972696e6720612050726f76696465722066726f6d20776869636820746f20776974686472617720610a20202020202020202f2f2f2066656520746f2066756c66696c6c207468652062726964676520726571756573742e204e6f74653a207468652063616c6c65722073686f756c64206f776e207468652072657175657374656420746f6b656e7320262073756666696369656e742062616c616e6365206f660a20202020202020202f2f2f2072657175657374656420746f6b656e7320696e2045564d0a2020202020202020616363657373284f776e6572207c20427269646765290a202020202020202066756e207769746864726177546f6b656e73280a202020202020202020202020747970653a20547970652c0a202020202020202020202020616d6f756e743a2055496e743235362c0a20202020202020202020202066656550726f76696465723a20617574682846756e6769626c65546f6b656e2e57697468647261772920267b46756e6769626c65546f6b656e2e50726f76696465727d0a2020202020202020293a20407b46756e6769626c65546f6b656e2e5661756c747d207b0a20202020202020202020202072657475726e203c2d2045564d2e626f72726f774272696467654163636573736f7228292e7769746864726177546f6b656e73280a2020202020202020202020202020202063616c6c65723a202673656c6620617320617574682843616c6c292026436164656e63654f776e65644163636f756e742c0a20202020202020202020202020202020747970653a20747970652c0a20202020202020202020202020202020616d6f756e743a20616d6f756e742c0a2020202020202020202020202020202066656550726f76696465723a2066656550726f76696465720a202020202020202020202020290a20202020202020207d0a202020207d0a0a202020202f2f2f20437265617465732061206e657720636164656e6365206f776e6564206163636f756e740a2020202061636365737328616c6c290a2020202066756e20637265617465436164656e63654f776e65644163636f756e7428293a2040436164656e63654f776e65644163636f756e74207b0a20202020202020206c657420616363203c2d63726561746520436164656e63654f776e65644163636f756e7428290a20202020202020206c65742061646472203d20496e7465726e616c45564d2e637265617465436164656e63654f776e65644163636f756e7428757569643a206163632e75756964290a20202020202020206163632e696e697441646472657373286164647265737342797465733a2061646472290a2020202020202020656d697420436164656e63654f776e65644163636f756e7443726561746564286164647265737342797465733a2061646472290a202020202020202072657475726e203c2d6163630a202020207d0a0a202020202f2f2f2052756e7320616e206120524c502d656e636f6465642045564d207472616e73616374696f6e2c2064656475637473207468652067617320666565732c0a202020202f2f2f20616e64206465706f736974732074686520676173206665657320696e746f207468652070726f766964656420636f696e6261736520616464726573732e0a2020202061636365737328616c6c290a2020202066756e2072756e2874783a205b55496e74385d2c20636f696e626173653a2045564d41646472657373293a20526573756c74207b0a202020202020202072657475726e20496e7465726e616c45564d2e72756e280a2020202020202020202020202020202074783a2074782c0a20202020202020202020202020202020636f696e626173653a20636f696e626173652e62797465730a2020202020202020292061732120526573756c740a202020207d0a0a202020202f2f2f206d75737452756e2072756e7320746865207472616e73616374696f6e207573696e672045564d2e72756e207965742069740a202020202f2f2f20726f6c6c6261636b2069662074686520747820657865637574696f6e2073746174757320697320756e6b6e6f776e206f7220696e76616c69642e0a202020202f2f2f204e6f746520746861742074686973206d6574686f6420646f6573206e6f7420726f6c6c6261636b206966207472616e73616374696f6e0a202020202f2f2f2069732065786563757465642062757420616e20766d206572726f72206973207265706f7274656420617320746865206f7574636f6d650a202020202f2f2f206f662074686520657865637574696f6e20287374617475733a206661696c6564292e0a2020202061636365737328616c6c290a2020202066756e206d75737452756e2874783a205b55496e74385d2c20636f696e626173653a2045564d41646472657373293a20526573756c74207b0a20202020202020206c65742072756e526573756c74203d2073656c662e72756e2874783a2074782c20636f696e626173653a20636f696e62617365290a2020202020202020617373657274280a20202020202020202020202072756e526573756c742e737461747573203d3d205374617475732e6661696c6564207c7c2072756e526573756c742e737461747573203d3d205374617475732e7375636365737366756c2c0a2020202020202020202020206d6573736167653a20227478206973206e6f742076616c696420666f7220657865637574696f6e220a2020202020202020290a202020202020202072657475726e2072756e526573756c740a202020207d0a0a2020202061636365737328616c6c290a2020202066756e20656e636f6465414249285f2076616c7565733a205b416e795374727563745d293a205b55496e74385d207b0a202020202020202072657475726e20496e7465726e616c45564d2e656e636f64654142492876616c756573290a202020207d0a0a2020202061636365737328616c6c290a2020202066756e206465636f64654142492874797065733a205b547970655d2c20646174613a205b55496e74385d293a205b416e795374727563745d207b0a202020202020202072657475726e20496e7465726e616c45564d2e6465636f64654142492874797065733a2074797065732c20646174613a2064617461290a202020207d0a0a2020202061636365737328616c6c290a2020202066756e20656e636f6465414249576974685369676e6174757265280a20202020202020205f207369676e61747572653a20537472696e672c0a20202020202020205f2076616c7565733a205b416e795374727563745d0a20202020293a205b55496e74385d207b0a20202020202020206c6574206d6574686f644944203d2048617368416c676f726974686d2e4b454343414b5f3235362e68617368280a2020202020202020202020207369676e61747572652e757466380a2020202020202020292e736c6963652866726f6d3a20302c207570546f3a2034290a20202020202020206c657420617267756d656e7473203d20496e7465726e616c45564d2e656e636f64654142492876616c756573290a0a202020202020202072657475726e206d6574686f6449442e636f6e63617428617267756d656e7473290a202020207d0a0a2020202061636365737328616c6c290a2020202066756e206465636f6465414249576974685369676e6174757265280a20202020202020205f207369676e61747572653a20537472696e672c0a202020202020202074797065733a205b547970655d2c0a2020202020202020646174613a205b55496e74385d0a20202020293a205b416e795374727563745d207b0a20202020202020206c6574206d6574686f644944203d2048617368416c676f726974686d2e4b454343414b5f3235362e68617368280a2020202020202020202020207369676e61747572652e757466380a2020202020202020292e736c6963652866726f6d3a20302c207570546f3a2034290a0a2020202020202020666f72206279746520696e206d6574686f644944207b0a2020202020202020202020206966206279746520213d20646174612e72656d6f766546697273742829207b0a2020202020202020202020202020202070616e696328227369676e6174757265206d69736d6174636822290a2020202020202020202020207d0a20202020202020207d0a0a202020202020202072657475726e20496e7465726e616c45564d2e6465636f64654142492874797065733a2074797065732c20646174613a2064617461290a202020207d0a0a202020202f2f2f2056616c69646174696f6e526573756c742072657475726e732074686520726573756c74206f6620434f41206f776e6572736869702070726f6f662076616c69646174696f6e0a2020202061636365737328616c6c290a202020207374727563742056616c69646174696f6e526573756c74207b0a202020202020202061636365737328616c6c290a20202020202020206c657420697356616c69643a20426f6f6c0a0a202020202020202061636365737328616c6c290a20202020202020206c65742070726f626c656d3a20537472696e673f0a0a2020202020202020696e697428697356616c69643a20426f6f6c2c2070726f626c656d3a20537472696e673f29207b0a20202020202020202020202073656c662e697356616c6964203d20697356616c69640a20202020202020202020202073656c662e70726f626c656d203d2070726f626c656d0a20202020202020207d0a202020207d0a0a202020202f2f2f2076616c6964617465434f414f776e65727368697050726f6f662076616c696461746573206120434f41206f776e6572736869702070726f6f660a2020202061636365737328616c6c290a2020202066756e2076616c6964617465434f414f776e65727368697050726f6f66280a2020202020202020616464726573733a20416464726573732c0a2020202020202020706174683a205075626c6963506174682c0a20202020202020207369676e6564446174613a205b55496e74385d2c0a20202020202020206b6579496e64696365733a205b55496e7436345d2c0a20202020202020207369676e6174757265733a205b5b55496e74385d5d2c0a202020202020202065766d416464726573733a205b55496e74383b2032305d0a20202020293a2056616c69646174696f6e526573756c74207b0a0a20202020202020202f2f206d616b65207369676e6174757265207365742066697273740a20202020202020202f2f20636865636b206e756d626572206f66207369676e617475726573206d617463686573206e756d626572206f66206b657920696e64696365730a20202020202020206966206b6579496e64696365732e6c656e67746820213d207369676e6174757265732e6c656e677468207b0a20202020202020202020202072657475726e2056616c69646174696f6e526573756c74280a20202020202020202020202020202020697356616c69643a2066616c73652c0a2020202020202020202020202020202070726f626c656d3a20226b657920696e64696365732073697a6520646f65736e2774206d6174636820746865207369676e617475726573220a202020202020202020202020290a20202020202020207d0a0a2020202020202020766172207369676e61747572655365743a205b43727970746f2e4b65794c6973745369676e61747572655d203d205b5d0a2020202020202020666f72207369676e6174757265496e6465782c207369676e617475726520696e207369676e6174757265737b0a2020202020202020202020207369676e61747572655365742e617070656e642843727970746f2e4b65794c6973745369676e6174757265280a202020202020202020202020202020206b6579496e6465783a20496e74286b6579496e64696365735b7369676e6174757265496e6465785d292c0a202020202020202020202020202020207369676e61747572653a207369676e61747572650a20202020202020202020202029290a20202020202020207d0a0a20202020202020202f2f206665746368206163636f756e740a20202020202020206c657420616363203d206765744163636f756e742861646472657373290a0a20202020202020202f2f20636f6e737472756374696e67206b6579206c6973740a20202020202020206c6574206b65794c697374203d2043727970746f2e4b65794c69737428290a2020202020202020666f72207369676e617475726520696e207369676e6174757265536574207b0a2020202020202020202020206c6574206b6579203d206163632e6b6579732e676574286b6579496e6465783a207369676e61747572652e6b6579496e64657829210a20202020202020202020202061737365727428216b65792e69735265766f6b65642c206d6573736167653a20227265766f6b6564206b6579206973207573656422290a2020202020202020202020206b65794c6973742e616464280a20202020202020202020202020206b65792e7075626c69634b65792c0a202020202020202020202020202068617368416c676f726974686d3a206b65792e68617368416c676f726974686d2c0a20202020202020202020202020207765696768743a206b65792e7765696768742c0a2020202020202020202020290a20202020202020207d0a0a20202020202020206c657420697356616c6964203d206b65794c6973742e766572696679280a2020202020202020202020207369676e61747572655365743a207369676e61747572655365742c0a2020202020202020202020207369676e6564446174613a207369676e6564446174612c0a202020202020202020202020646f6d61696e53657061726174696f6e5461673a2022464c4f572d56302e302d75736572220a2020202020202020290a0a202020202020202069662021697356616c69647b0a20202020202020202020202072657475726e2056616c69646174696f6e526573756c74280a20202020202020202020202020202020697356616c69643a2066616c73652c0a2020202020202020202020202020202070726f626c656d3a202274686520676976656e207369676e61747572657320617265206e6f742076616c6964206f722070726f7669646520656e6f75676820776569676874220a202020202020202020202020290a20202020202020207d0a0a20202020202020206c657420636f61526566203d206163632e6361706162696c69746965732e626f72726f773c2645564d2e436164656e63654f776e65644163636f756e743e2870617468290a2020202020202020696620636f61526566203d3d206e696c207b0a2020202020202020202020202072657475726e2056616c69646174696f6e526573756c74280a2020202020202020202020202020202020697356616c69643a2066616c73652c0a202020202020202020202020202020202070726f626c656d3a2022636f756c64206e6f7420626f72726f7720627269646765206163636f756e742773207265736f75726365220a20202020202020202020202020290a20202020202020207d0a0a20202020202020202f2f207665726966792065766d2061646472657373206d61746368696e670a20202020202020207661722061646472203d20636f61526566212e6164647265737328290a2020202020202020666f7220696e6465782c206974656d20696e20636f61526566212e6164647265737328292e6279746573207b0a2020202020202020202020206966206974656d20213d2065766d416464726573735b696e6465785d207b0a2020202020202020202020202020202072657475726e2056616c69646174696f6e526573756c74280a2020202020202020202020202020202020202020697356616c69643a2066616c73652c0a202020202020202020202020202020202020202070726f626c656d3a202265766d2061646472657373206d69736d61746368220a20202020202020202020202020202020290a2020202020202020202020207d0a20202020202020207d0a0a202020202020202072657475726e2056616c69646174696f6e526573756c74280a202020202020202020202020697356616c69643a20747275652c0a20202020202020202020202070726f626c656d3a206e696c0a2020202020202020290a202020207d0a0a202020202f2f2f20426c6f636b2072657475726e7320696e666f726d6174696f6e2061626f757420746865206c617465737420657865637574656420626c6f636b2e0a2020202061636365737328616c6c290a202020207374727563742045564d426c6f636b207b0a202020202020202061636365737328616c6c290a20202020202020206c6574206865696768743a2055496e7436340a0a202020202020202061636365737328616c6c290a20202020202020206c657420686173683a20537472696e670a0a202020202020202061636365737328616c6c290a20202020202020206c657420746f74616c537570706c793a20496e740a0a2020202020202020696e6974286865696768743a2055496e7436342c20686173683a20537472696e672c20746f74616c537570706c793a20496e7429207b0a20202020202020202020202073656c662e686569676874203d206865696768740a20202020202020202020202073656c662e68617368203d20686173680a20202020202020202020202073656c662e746f74616c537570706c79203d20746f74616c537570706c790a20202020202020207d0a202020207d0a0a202020202f2f2f2052657475726e7320746865206c617465737420657865637574656420626c6f636b2e0a2020202061636365737328616c6c290a2020202066756e206765744c6174657374426c6f636b28293a2045564d426c6f636b207b0a202020202020202072657475726e20496e7465726e616c45564d2e6765744c6174657374426c6f636b2829206173212045564d426c6f636b0a202020207d0a0a202020202f2f2f20496e7465726661636520666f722061207265736f75726365207768696368206163747320617320616e20656e747279706f696e7420746f2074686520564d206272696467650a2020202061636365737328616c6c290a202020207265736f7572636520696e74657266616365204272696467654163636573736f72207b0a0a20202020202020202f2f2f20456e64706f696e7420656e61626c696e6720746865206272696467696e67206f6620616e204e465420746f2045564d0a202020202020202061636365737328427269646765290a202020202020202066756e206465706f7369744e4654280a2020202020202020202020206e66743a20407b4e6f6e46756e6769626c65546f6b656e2e4e46547d2c0a202020202020202020202020746f3a2045564d416464726573732c0a20202020202020202020202066656550726f76696465723a20617574682846756e6769626c65546f6b656e2e57697468647261772920267b46756e6769626c65546f6b656e2e50726f76696465727d0a2020202020202020290a0a20202020202020202f2f2f20456e64706f696e7420656e61626c696e6720746865206272696467696e67206f6620616e204e46542066726f6d2045564d0a202020202020202061636365737328427269646765290a202020202020202066756e2077697468647261774e4654280a20202020202020202020202063616c6c65723a20617574682843616c6c292026436164656e63654f776e65644163636f756e742c0a202020202020202020202020747970653a20547970652c0a20202020202020202020202069643a2055496e743235362c0a20202020202020202020202066656550726f76696465723a20617574682846756e6769626c65546f6b656e2e57697468647261772920267b46756e6769626c65546f6b656e2e50726f76696465727d0a2020202020202020293a20407b4e6f6e46756e6769626c65546f6b656e2e4e46547d0a0a20202020202020202f2f2f20456e64706f696e7420656e61626c696e6720746865206272696467696e67206f6620612066756e6769626c6520746f6b656e207661756c7420746f2045564d0a202020202020202061636365737328427269646765290a202020202020202066756e206465706f736974546f6b656e73280a2020202020202020202020207661756c743a20407b46756e6769626c65546f6b656e2e5661756c747d2c0a202020202020202020202020746f3a2045564d416464726573732c0a20202020202020202020202066656550726f76696465723a20617574682846756e6769626c65546f6b656e2e57697468647261772920267b46756e6769626c65546f6b656e2e50726f76696465727d0a2020202020202020290a0a20202020202020202f2f2f20456e64706f696e7420656e61626c696e6720746865206272696467696e67206f662066756e6769626c6520746f6b656e732066726f6d2045564d0a202020202020202061636365737328427269646765290a202020202020202066756e207769746864726177546f6b656e73280a20202020202020202020202063616c6c65723a20617574682843616c6c292026436164656e63654f776e65644163636f756e742c0a202020202020202020202020747970653a20547970652c0a202020202020202020202020616d6f756e743a2055496e743235362c0a20202020202020202020202066656550726f76696465723a20617574682846756e6769626c65546f6b656e2e57697468647261772920267b46756e6769626c65546f6b656e2e50726f76696465727d0a2020202020202020293a20407b46756e6769626c65546f6b656e2e5661756c747d0a202020207d0a0a202020202f2f2f20496e746572666163652077686963682063617074757265732061204361706162696c69747920746f2074686520627269646765204163636573736f722c20736176696e672069742077697468696e2074686520427269646765526f75746572207265736f757263650a2020202061636365737328616c6c290a202020207265736f7572636520696e7465726661636520427269646765526f75746572207b0a0a20202020202020202f2f2f2052657475726e732061207265666572656e636520746f20746865204272696467654163636573736f722064657369676e6174656420666f7220696e7465726e616c206272696467652072657175657374730a2020202020202020616363657373284272696467652920766965772066756e20626f72726f774272696467654163636573736f7228293a2061757468284272696467652920267b4272696467654163636573736f727d0a202020207d0a0a202020202f2f2f2052657475726e732061207265666572656e636520746f20746865204272696467654163636573736f722064657369676e6174656420666f7220696e7465726e616c206272696467652072657175657374730a202020206163636573732873656c66290a20202020766965772066756e20626f72726f774272696467654163636573736f7228293a2061757468284272696467652920267b4272696467654163636573736f727d207b0a202020202020202072657475726e2073656c662e6163636f756e742e73746f726167652e626f72726f773c61757468284272696467652920267b427269646765526f757465727d3e2866726f6d3a202f73746f726167652f65766d427269646765526f75746572290a2020202020202020202020203f2e626f72726f774272696467654163636573736f7228290a2020202020202020202020203f3f2070616e69632822436f756c64206e6f7420626f72726f77207265666572656e636520746f207468652045564d2062726964676522290a202020207d0a7d0a" -access(all) let compiledFactoryBytecode = "608060405234801561001057600080fd5b50338061003757604051631e4fbdf760e01b81526000600482015260240160405180910390fd5b61004081610046565b50610096565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6129f4806100a56000396000f3fe60806040523480156200001157600080fd5b5060043610620000ab5760003560e01c80638da5cb5b116200006e5780638da5cb5b1462000155578063d56e0ccf1462000167578063daa09e54146200019e578063f2fde38b14620001b5578063f93241dd14620001cc57600080fd5b806304433bbc14620000b05780630a2c0ce914620000e4578063335f4c76146200010a57806361a169051462000132578063715018a61462000149575b600080fd5b620000c7620000c1366004620006ae565b620001e3565b6040516001600160a01b0390911681526020015b60405180910390f35b620000fb620000f5366004620006ef565b62000216565b604051620000db919062000775565b620001216200011b366004620006ef565b620002ca565b6040519015158152602001620000db565b620000c7620001433660046200078a565b620002f8565b62000153620003f9565b005b6000546001600160a01b0316620000c7565b620000c762000178366004620006ae565b80516020818301810180516001825292820191909301209152546001600160a01b031681565b62000121620001af366004620006ef565b62000411565b62000153620001c6366004620006ef565b6200048c565b620000fb620001dd366004620006ef565b620004d4565b6000600182604051620001f791906200086c565b908152604051908190036020019020546001600160a01b031692915050565b6001600160a01b03811660009081526002602052604090208054606091906200023f906200088a565b80601f01602080910402602001604051908101604052809291908181526020018280546200026d906200088a565b8015620002be5780601f106200029257610100808354040283529160200191620002be565b820191906000526020600020905b815481529060010190602001808311620002a057829003601f168201915b50505050509050919050565b6001600160a01b03811660009081526002602052604081208054620002ef906200088a565b15159392505050565b60006200030462000576565b600080546001600160a01b031687878787876040516200032490620005f5565b6200033596959493929190620008c6565b604051809103906000f08015801562000352573d6000803e3d6000fd5b509050806001856040516200036891906200086c565b908152604080516020928190038301902080546001600160a01b0319166001600160a01b039485161790559183166000908152600290915220620003ad8582620009a4565b507fbebce54951ebf20c0dcd195a45bb2388d9ac8e38b5974e00bb63c5822dbe65f08188888888604051620003e795949392919062000a71565b60405180910390a19695505050505050565b6200040362000576565b6200040f6000620005a5565b565b6040516301ffc9a760e01b81526380ac58cd60e01b60048201526000906001600160a01b038316906301ffc9a790602401602060405180830381865afa15801562000460573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000486919062000ae3565b92915050565b6200049662000576565b6001600160a01b038116620004c657604051631e4fbdf760e01b8152600060048201526024015b60405180910390fd5b620004d181620005a5565b50565b60026020526000908152604090208054620004ef906200088a565b80601f01602080910402602001604051908101604052809291908181526020018280546200051d906200088a565b80156200056e5780601f1062000542576101008083540402835291602001916200056e565b820191906000526020600020905b8154815290600101906020018083116200055057829003601f168201915b505050505081565b6000546001600160a01b031633146200040f5760405163118cdaa760e01b8152336004820152602401620004bd565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b611eb78062000b0883390190565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126200062b57600080fd5b813567ffffffffffffffff8082111562000649576200064962000603565b604051601f8301601f19908116603f0116810190828211818310171562000674576200067462000603565b816040528381528660208588010111156200068e57600080fd5b836020870160208301376000602085830101528094505050505092915050565b600060208284031215620006c157600080fd5b813567ffffffffffffffff811115620006d957600080fd5b620006e78482850162000619565b949350505050565b6000602082840312156200070257600080fd5b81356001600160a01b03811681146200071a57600080fd5b9392505050565b60005b838110156200073e57818101518382015260200162000724565b50506000910152565b600081518084526200076181602086016020860162000721565b601f01601f19169290920160200192915050565b6020815260006200071a602083018462000747565b600080600080600060a08688031215620007a357600080fd5b853567ffffffffffffffff80821115620007bc57600080fd5b620007ca89838a0162000619565b96506020880135915080821115620007e157600080fd5b620007ef89838a0162000619565b955060408801359150808211156200080657600080fd5b6200081489838a0162000619565b945060608801359150808211156200082b57600080fd5b6200083989838a0162000619565b935060808801359150808211156200085057600080fd5b506200085f8882890162000619565b9150509295509295909350565b600082516200088081846020870162000721565b9190910192915050565b600181811c908216806200089f57607f821691505b602082108103620008c057634e487b7160e01b600052602260045260246000fd5b50919050565b6001600160a01b038716815260c060208201819052600090620008ec9083018862000747565b828103604084015262000900818862000747565b9050828103606084015262000916818762000747565b905082810360808401526200092c818662000747565b905082810360a084015262000942818562000747565b9998505050505050505050565b601f8211156200099f576000816000526020600020601f850160051c810160208610156200097a5750805b601f850160051c820191505b818110156200099b5782815560010162000986565b5050505b505050565b815167ffffffffffffffff811115620009c157620009c162000603565b620009d981620009d284546200088a565b846200094f565b602080601f83116001811462000a115760008415620009f85750858301515b600019600386901b1c1916600185901b1785556200099b565b600085815260208120601f198616915b8281101562000a425788860151825594840194600190910190840162000a21565b508582101562000a615787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6001600160a01b038616815260a06020820181905260009062000a979083018762000747565b828103604084015262000aab818762000747565b9050828103606084015262000ac1818662000747565b9050828103608084015262000ad7818562000747565b98975050505050505050565b60006020828403121562000af657600080fd5b815180151581146200071a57600080fdfe60806040523480156200001157600080fd5b5060405162001eb738038062001eb7833981016040819052620000349162000202565b858585600062000045838262000386565b50600162000054828262000386565b5050506001600160a01b0381166200008657604051631e4fbdf760e01b81526000600482015260240160405180910390fd5b6200009181620000cb565b50600c620000a0848262000386565b50600d620000af838262000386565b50600e620000be828262000386565b5050505050505062000452565b600b80546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b80516001600160a01b03811681146200013557600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126200016257600080fd5b81516001600160401b03808211156200017f576200017f6200013a565b604051601f8301601f19908116603f01168101908282118183101715620001aa57620001aa6200013a565b8160405283815260209250866020858801011115620001c857600080fd5b600091505b83821015620001ec5785820183015181830184015290820190620001cd565b6000602085830101528094505050505092915050565b60008060008060008060c087890312156200021c57600080fd5b62000227876200011d565b60208801519096506001600160401b03808211156200024557600080fd5b620002538a838b0162000150565b965060408901519150808211156200026a57600080fd5b620002788a838b0162000150565b955060608901519150808211156200028f57600080fd5b6200029d8a838b0162000150565b94506080890151915080821115620002b457600080fd5b620002c28a838b0162000150565b935060a0890151915080821115620002d957600080fd5b50620002e889828a0162000150565b9150509295509295509295565b600181811c908216806200030a57607f821691505b6020821081036200032b57634e487b7160e01b600052602260045260246000fd5b50919050565b601f82111562000381576000816000526020600020601f850160051c810160208610156200035c5750805b601f850160051c820191505b818110156200037d5782815560010162000368565b5050505b505050565b81516001600160401b03811115620003a257620003a26200013a565b620003ba81620003b38454620002f5565b8462000331565b602080601f831160018114620003f25760008415620003d95750858301515b600019600386901b1c1916600185901b1785556200037d565b600085815260208120601f198616915b82811015620004235788860151825594840194600190910190840162000402565b5085821015620004425787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b611a5580620004626000396000f3fe608060405234801561001057600080fd5b50600436106101cf5760003560e01c806370a0823111610104578063a76b4d56116100a2578063cd279c7c11610071578063cd279c7c146103a8578063e8a3d485146103bb578063e985e9c5146103c3578063f2fde38b146103d657600080fd5b8063a76b4d5614610372578063b49bbd941461037a578063b88d4fde14610382578063c87b56dd1461039557600080fd5b806394e29329116100de57806394e293291461034757806395d89b411461034f578063a159047b14610357578063a22cb4651461035f57600080fd5b806370a082311461031b578063715018a61461032e5780638da5cb5b1461033657600080fd5b80632f745c59116101715780634f558e791161014b5780634f558e79146102c25780634f6ccce7146102ed5780635e0a9661146103005780636352211e1461030857600080fd5b80632f745c591461028957806342842e0e1461029c57806342966c68146102af57600080fd5b8063095ea7b3116101ad578063095ea7b31461023c57806318160ddd1461025157806318e97fd11461026357806323b872dd1461027657600080fd5b806301ffc9a7146101d457806306fdde03146101fc578063081812fc14610211575b600080fd5b6101e76101e2366004611494565b6103e9565b60405190151581526020015b60405180910390f35b6102046103fa565b6040516101f39190611501565b61022461021f366004611514565b61048c565b6040516001600160a01b0390911681526020016101f3565b61024f61024a366004611549565b6104b5565b005b6009545b6040519081526020016101f3565b61024f61027136600461161f565b6104c4565b61024f610284366004611666565b6104d6565b610255610297366004611549565b610566565b61024f6102aa366004611666565b6105cb565b61024f6102bd366004611514565b6105eb565b6101e76102d0366004611514565b6000908152600260205260409020546001600160a01b0316151590565b6102556102fb366004611514565b6105f7565b610204610650565b610224610316366004611514565b61065f565b6102556103293660046116a2565b61066a565b61024f6106b2565b600b546001600160a01b0316610224565b6102046106c6565b6102046106d5565b6102046106e4565b61024f61036d3660046116bd565b610772565b61020461077d565b61020461078a565b61024f6103903660046116f9565b610797565b6102046103a3366004611514565b6107ae565b61024f6103b6366004611775565b6107b9565b6102046107d5565b6101e76103d13660046117cc565b6107e4565b61024f6103e43660046116a2565b610812565b60006103f482610850565b92915050565b606060008054610409906117ff565b80601f0160208091040260200160405190810160405280929190818152602001828054610435906117ff565b80156104825780601f1061045757610100808354040283529160200191610482565b820191906000526020600020905b81548152906001019060200180831161046557829003601f168201915b5050505050905090565b600061049782610875565b506000828152600460205260409020546001600160a01b03166103f4565b6104c08282336108ae565b5050565b6104cc6108bb565b6104c082826108e8565b6001600160a01b03821661050557604051633250574960e11b8152600060048201526024015b60405180910390fd5b6000610512838333610938565b9050836001600160a01b0316816001600160a01b031614610560576040516364283d7b60e01b81526001600160a01b03808616600483015260248201849052821660448201526064016104fc565b50505050565b60006105718361066a565b82106105a25760405163295f44f760e21b81526001600160a01b0384166004820152602481018390526044016104fc565b506001600160a01b03919091166000908152600760209081526040808320938352929052205490565b6105e683838360405180602001604052806000815250610797565b505050565b6104c060008233610938565b600061060260095490565b821061062b5760405163295f44f760e21b815260006004820152602481018390526044016104fc565b6009828154811061063e5761063e611839565b90600052602060002001549050919050565b6060600d8054610409906117ff565b60006103f482610875565b60006001600160a01b038216610696576040516322718ad960e21b8152600060048201526024016104fc565b506001600160a01b031660009081526003602052604090205490565b6106ba6108bb565b6106c4600061094d565b565b6060600c8054610409906117ff565b606060018054610409906117ff565b600d80546106f1906117ff565b80601f016020809104026020016040519081016040528092919081815260200182805461071d906117ff565b801561076a5780601f1061073f5761010080835404028352916020019161076a565b820191906000526020600020905b81548152906001019060200180831161074d57829003601f168201915b505050505081565b6104c033838361099f565b600e80546106f1906117ff565b600c80546106f1906117ff565b6107a28484846104d6565b61056084848484610a3e565b60606103f482610b67565b6107c16108bb565b6107cb8383610c70565b6105e682826108e8565b6060600e8054610409906117ff565b6001600160a01b03918216600090815260056020908152604080832093909416825291909152205460ff1690565b61081a6108bb565b6001600160a01b03811661084457604051631e4fbdf760e01b8152600060048201526024016104fc565b61084d8161094d565b50565b60006001600160e01b0319821663780e9d6360e01b14806103f457506103f482610c8a565b6000818152600260205260408120546001600160a01b0316806103f457604051637e27328960e01b8152600481018490526024016104fc565b6105e68383836001610caf565b600b546001600160a01b031633146106c45760405163118cdaa760e01b81523360048201526024016104fc565b6000828152600660205260409020610900828261189f565b506040518281527ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79060200160405180910390a15050565b6000610945848484610db5565b949350505050565b600b80546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6001600160a01b0382166109d157604051630b61174360e31b81526001600160a01b03831660048201526024016104fc565b6001600160a01b03838116600081815260056020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b6001600160a01b0383163b1561056057604051630a85bd0160e11b81526001600160a01b0384169063150b7a0290610a8090339088908790879060040161195f565b6020604051808303816000875af1925050508015610abb575060408051601f3d908101601f19168201909252610ab89181019061199c565b60015b610b24573d808015610ae9576040519150601f19603f3d011682016040523d82523d6000602084013e610aee565b606091505b508051600003610b1c57604051633250574960e11b81526001600160a01b03851660048201526024016104fc565b805181602001fd5b6001600160e01b03198116630a85bd0160e11b14610b6057604051633250574960e11b81526001600160a01b03851660048201526024016104fc565b5050505050565b6060610b7282610875565b5060008281526006602052604081208054610b8c906117ff565b80601f0160208091040260200160405190810160405280929190818152602001828054610bb8906117ff565b8015610c055780601f10610bda57610100808354040283529160200191610c05565b820191906000526020600020905b815481529060010190602001808311610be857829003601f168201915b505050505090506000610c2360408051602081019091526000815290565b90508051600003610c35575092915050565b815115610c67578082604051602001610c4f9291906119b9565b60405160208183030381529060405292505050919050565b61094584610e82565b6104c0828260405180602001604052806000815250610ef7565b60006001600160e01b03198216632483248360e11b14806103f457506103f482610f0e565b8080610cc357506001600160a01b03821615155b15610d85576000610cd384610875565b90506001600160a01b03831615801590610cff5750826001600160a01b0316816001600160a01b031614155b8015610d125750610d1081846107e4565b155b15610d3b5760405163a9fbf51f60e01b81526001600160a01b03841660048201526024016104fc565b8115610d835783856001600160a01b0316826001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45b505b5050600090815260046020526040902080546001600160a01b0319166001600160a01b0392909216919091179055565b600080610dc3858585610f5e565b90506001600160a01b038116610e2057610e1b84600980546000838152600a60205260408120829055600182018355919091527f6e1540171b6c0c960b71a7020d9f60077f6af931a8bbf590da0223dacf75c7af0155565b610e43565b846001600160a01b0316816001600160a01b031614610e4357610e438185611057565b6001600160a01b038516610e5f57610e5a846110e8565b610945565b846001600160a01b0316816001600160a01b031614610945576109458585611197565b6060610e8d82610875565b506000610ea560408051602081019091526000815290565b90506000815111610ec55760405180602001604052806000815250610ef0565b80610ecf846111e7565b604051602001610ee09291906119b9565b6040516020818303038152906040525b9392505050565b610f01838361127a565b6105e66000848484610a3e565b60006001600160e01b031982166380ac58cd60e01b1480610f3f57506001600160e01b03198216635b5e139f60e01b145b806103f457506301ffc9a760e01b6001600160e01b03198316146103f4565b6000828152600260205260408120546001600160a01b0390811690831615610f8b57610f8b8184866112df565b6001600160a01b03811615610fc957610fa8600085600080610caf565b6001600160a01b038116600090815260036020526040902080546000190190555b6001600160a01b03851615610ff8576001600160a01b0385166000908152600360205260409020805460010190555b60008481526002602052604080822080546001600160a01b0319166001600160a01b0389811691821790925591518793918516917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4949350505050565b60006110628361066a565b6000838152600860205260409020549091508082146110b5576001600160a01b03841660009081526007602090815260408083208584528252808320548484528184208190558352600890915290208190555b5060009182526008602090815260408084208490556001600160a01b039094168352600781528383209183525290812055565b6009546000906110fa906001906119e8565b6000838152600a60205260408120546009805493945090928490811061112257611122611839565b90600052602060002001549050806009838154811061114357611143611839565b6000918252602080832090910192909255828152600a9091526040808220849055858252812055600980548061117b5761117b611a09565b6001900381819060005260206000200160009055905550505050565b600060016111a48461066a565b6111ae91906119e8565b6001600160a01b039093166000908152600760209081526040808320868452825280832085905593825260089052919091209190915550565b606060006111f483611343565b600101905060008167ffffffffffffffff81111561121457611214611573565b6040519080825280601f01601f19166020018201604052801561123e576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a850494508461124857509392505050565b6001600160a01b0382166112a457604051633250574960e11b8152600060048201526024016104fc565b60006112b283836000610938565b90506001600160a01b038116156105e6576040516339e3563760e11b8152600060048201526024016104fc565b6112ea83838361141b565b6105e6576001600160a01b03831661131857604051637e27328960e01b8152600481018290526024016104fc565b60405163177e802f60e01b81526001600160a01b0383166004820152602481018290526044016104fc565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b83106113825772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef810000000083106113ae576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc1000083106113cc57662386f26fc10000830492506010015b6305f5e10083106113e4576305f5e100830492506008015b61271083106113f857612710830492506004015b6064831061140a576064830492506002015b600a83106103f45760010192915050565b60006001600160a01b038316158015906109455750826001600160a01b0316846001600160a01b03161480611455575061145584846107e4565b806109455750506000908152600460205260409020546001600160a01b03908116911614919050565b6001600160e01b03198116811461084d57600080fd5b6000602082840312156114a657600080fd5b8135610ef08161147e565b60005b838110156114cc5781810151838201526020016114b4565b50506000910152565b600081518084526114ed8160208601602086016114b1565b601f01601f19169290920160200192915050565b602081526000610ef060208301846114d5565b60006020828403121561152657600080fd5b5035919050565b80356001600160a01b038116811461154457600080fd5b919050565b6000806040838503121561155c57600080fd5b6115658361152d565b946020939093013593505050565b634e487b7160e01b600052604160045260246000fd5b600067ffffffffffffffff808411156115a4576115a4611573565b604051601f8501601f19908116603f011681019082821181831017156115cc576115cc611573565b816040528093508581528686860111156115e557600080fd5b858560208301376000602087830101525050509392505050565b600082601f83011261161057600080fd5b610ef083833560208501611589565b6000806040838503121561163257600080fd5b82359150602083013567ffffffffffffffff81111561165057600080fd5b61165c858286016115ff565b9150509250929050565b60008060006060848603121561167b57600080fd5b6116848461152d565b92506116926020850161152d565b9150604084013590509250925092565b6000602082840312156116b457600080fd5b610ef08261152d565b600080604083850312156116d057600080fd5b6116d98361152d565b9150602083013580151581146116ee57600080fd5b809150509250929050565b6000806000806080858703121561170f57600080fd5b6117188561152d565b93506117266020860161152d565b925060408501359150606085013567ffffffffffffffff81111561174957600080fd5b8501601f8101871361175a57600080fd5b61176987823560208401611589565b91505092959194509250565b60008060006060848603121561178a57600080fd5b6117938461152d565b925060208401359150604084013567ffffffffffffffff8111156117b657600080fd5b6117c2868287016115ff565b9150509250925092565b600080604083850312156117df57600080fd5b6117e88361152d565b91506117f66020840161152d565b90509250929050565b600181811c9082168061181357607f821691505b60208210810361183357634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052603260045260246000fd5b601f8211156105e6576000816000526020600020601f850160051c810160208610156118785750805b601f850160051c820191505b8181101561189757828155600101611884565b505050505050565b815167ffffffffffffffff8111156118b9576118b9611573565b6118cd816118c784546117ff565b8461184f565b602080601f83116001811461190257600084156118ea5750858301515b600019600386901b1c1916600185901b178555611897565b600085815260208120601f198616915b8281101561193157888601518255948401946001909101908401611912565b508582101561194f5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6001600160a01b0385811682528416602082015260408101839052608060608201819052600090611992908301846114d5565b9695505050505050565b6000602082840312156119ae57600080fd5b8151610ef08161147e565b600083516119cb8184602088016114b1565b8351908301906119df8183602088016114b1565b01949350505050565b818103818111156103f457634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052603160045260246000fdfea26469706673582212206ff38700c73b602455dbb7964f2d3281f62efc77263f0f3bdb67f5e4ee5d4f3f64736f6c63430008170033a26469706673582212207f55223fc039b168a1e0c0bb9dc8d219b8219d1b2151fe8e9843aecefd41f82664736f6c63430008170033" +access(all) let compiledFactoryBytecode = "608060405234801561001057600080fd5b50338061003757604051631e4fbdf760e01b81526000600482015260240160405180910390fd5b61004081610046565b50610096565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b61484a806100a56000396000f3fe60806040523480156200001157600080fd5b5060043610620000c35760003560e01c8063715018a6116200007a578063715018a6146200018f5780638da5cb5b146200019b578063d56e0ccf14620001ad578063daa09e5414620001e4578063f2fde38b14620001fb578063f93241dd146200021257600080fd5b806304433bbc14620000c85780630a2c0ce914620000fc578063263e0c1b1462000122578063335f4c76146200014a57806340f8d42b146200016157806361a169051462000178575b600080fd5b620000df620000d936600462000c0a565b62000229565b6040516001600160a01b0390911681526020015b60405180910390f35b620001136200010d36600462000c4b565b6200025c565b604051620000f3919062000cd1565b620001396200013336600462000c4b565b62000310565b6040519015158152602001620000f3565b620001396200015b36600462000c4b565b62000724565b620000df6200017236600462000ce6565b62000752565b620000df6200018936600462000ce6565b62000853565b6200019962000942565b005b6000546001600160a01b0316620000df565b620000df620001be36600462000c0a565b80516020818301810180516001825292820191909301209152546001600160a01b031681565b62000139620001f536600462000c4b565b6200095a565b620001996200020c36600462000c4b565b620009da565b620001136200022336600462000c4b565b62000a22565b60006001826040516200023d919062000dc8565b908152604051908190036020019020546001600160a01b031692915050565b6001600160a01b0381166000908152600260205260409020805460609190620002859062000de6565b80601f0160208091040260200160405190810160405280929190818152602001828054620002b39062000de6565b8015620003045780601f10620002d85761010080835404028352916020019162000304565b820191906000526020600020905b815481529060010190602001808311620002e657829003601f168201915b50505050509050919050565b60408051600481526024810182526020810180516001600160e01b03166318160ddd60e01b1790529051600091829182916001600160a01b0386169162000358919062000dc8565b600060405180830381855afa9150503d806000811462000395576040519150601f19603f3d011682016040523d82523d6000602084013e6200039a565b606091505b5091509150811580620003ac57508051155b15620003bc575060009392505050565b604051600060248201526001600160a01b0385169060440160408051601f198184030181529181526020820180516001600160e01b03166370a0823160e01b179052516200040b919062000dc8565b600060405180830381855afa9150503d806000811462000448576040519150601f19603f3d011682016040523d82523d6000602084013e6200044d565b606091505b5090925090508115806200046057508051155b1562000470575060009392505050565b60405160006024820181905260448201526001600160a01b0385169060640160408051601f198184030181529181526020820180516001600160e01b0316636eb1769f60e11b17905251620004c6919062000dc8565b600060405180830381855afa9150503d806000811462000503576040519150601f19603f3d011682016040523d82523d6000602084013e62000508565b606091505b5090925090508115806200051b57508051155b156200052b575060009392505050565b60408051600481526024810182526020810180516001600160e01b03166306fdde0360e01b17905290516001600160a01b038616916200056b9162000dc8565b600060405180830381855afa9150503d8060008114620005a8576040519150601f19603f3d011682016040523d82523d6000602084013e620005ad565b606091505b509092509050811580620005c057508051155b15620005d0575060009392505050565b60408051600481526024810182526020810180516001600160e01b03166395d89b4160e01b17905290516001600160a01b03861691620006109162000dc8565b600060405180830381855afa9150503d80600081146200064d576040519150601f19603f3d011682016040523d82523d6000602084013e62000652565b606091505b5090925090508115806200066557508051155b1562000675575060009392505050565b60408051600481526024810182526020810180516001600160e01b031663313ce56760e01b17905290516001600160a01b03861691620006b59162000dc8565b600060405180830381855afa9150503d8060008114620006f2576040519150601f19603f3d011682016040523d82523d6000602084013e620006f7565b606091505b5090925090508115806200070a57508051155b156200071a575060009392505050565b5060019392505050565b6001600160a01b03811660009081526002602052604081208054620007499062000de6565b15159392505050565b60006200075e62000ac4565b600080546001600160a01b031687878787876040516200077e9062000b43565b6200078f9695949392919062000e22565b604051809103906000f080158015620007ac573d6000803e3d6000fd5b50905080600185604051620007c2919062000dc8565b908152604080516020928190038301902080546001600160a01b0319166001600160a01b03948516179055918316600090815260029091522062000807858262000f00565b507f99a64021330f1af36b3fd5f64a1d12b99b8ddf91fa553618c4df01ffba4c1cee81888888886040516200084195949392919062000fcd565b60405180910390a19695505050505050565b60006200085f62000ac4565b600080546001600160a01b031687878787876040516200087f9062000b51565b620008909695949392919062000e22565b604051809103906000f080158015620008ad573d6000803e3d6000fd5b50905080600185604051620008c3919062000dc8565b908152604080516020928190038301902080546001600160a01b0319166001600160a01b03948516179055918316600090815260029091522062000908858262000f00565b507fbebce54951ebf20c0dcd195a45bb2388d9ac8e38b5974e00bb63c5822dbe65f081888888886040516200084195949392919062000fcd565b6200094c62000ac4565b62000958600062000af3565b565b6040516301ffc9a760e01b81526380ac58cd60e01b60048201526000906001600160a01b038316906301ffc9a790602401602060405180830381865afa925050508015620009c7575060408051601f3d908101601f19168201909252620009c4918101906200103f565b60015b620009d457506000919050565b92915050565b620009e462000ac4565b6001600160a01b03811662000a1457604051631e4fbdf760e01b8152600060048201526024015b60405180910390fd5b62000a1f8162000af3565b50565b6002602052600090815260409020805462000a3d9062000de6565b80601f016020809104026020016040519081016040528092919081815260200182805462000a6b9062000de6565b801562000abc5780601f1062000a905761010080835404028352916020019162000abc565b820191906000526020600020905b81548152906001019060200180831162000a9e57829003601f168201915b505050505081565b6000546001600160a01b03163314620009585760405163118cdaa760e01b815233600482015260240162000a0b565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6118fa806200106483390190565b611eb7806200295e83390190565b634e487b7160e01b600052604160045260246000fd5b600082601f83011262000b8757600080fd5b813567ffffffffffffffff8082111562000ba55762000ba562000b5f565b604051601f8301601f19908116603f0116810190828211818310171562000bd05762000bd062000b5f565b8160405283815286602085880101111562000bea57600080fd5b836020870160208301376000602085830101528094505050505092915050565b60006020828403121562000c1d57600080fd5b813567ffffffffffffffff81111562000c3557600080fd5b62000c438482850162000b75565b949350505050565b60006020828403121562000c5e57600080fd5b81356001600160a01b038116811462000c7657600080fd5b9392505050565b60005b8381101562000c9a57818101518382015260200162000c80565b50506000910152565b6000815180845262000cbd81602086016020860162000c7d565b601f01601f19169290920160200192915050565b60208152600062000c76602083018462000ca3565b600080600080600060a0868803121562000cff57600080fd5b853567ffffffffffffffff8082111562000d1857600080fd5b62000d2689838a0162000b75565b9650602088013591508082111562000d3d57600080fd5b62000d4b89838a0162000b75565b9550604088013591508082111562000d6257600080fd5b62000d7089838a0162000b75565b9450606088013591508082111562000d8757600080fd5b62000d9589838a0162000b75565b9350608088013591508082111562000dac57600080fd5b5062000dbb8882890162000b75565b9150509295509295909350565b6000825162000ddc81846020870162000c7d565b9190910192915050565b600181811c9082168062000dfb57607f821691505b60208210810362000e1c57634e487b7160e01b600052602260045260246000fd5b50919050565b6001600160a01b038716815260c06020820181905260009062000e489083018862000ca3565b828103604084015262000e5c818862000ca3565b9050828103606084015262000e72818762000ca3565b9050828103608084015262000e88818662000ca3565b905082810360a084015262000e9e818562000ca3565b9998505050505050505050565b601f82111562000efb576000816000526020600020601f850160051c8101602086101562000ed65750805b601f850160051c820191505b8181101562000ef75782815560010162000ee2565b5050505b505050565b815167ffffffffffffffff81111562000f1d5762000f1d62000b5f565b62000f358162000f2e845462000de6565b8462000eab565b602080601f83116001811462000f6d576000841562000f545750858301515b600019600386901b1c1916600185901b17855562000ef7565b600085815260208120601f198616915b8281101562000f9e5788860151825594840194600190910190840162000f7d565b508582101562000fbd5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6001600160a01b038616815260a06020820181905260009062000ff39083018762000ca3565b828103604084015262001007818762000ca3565b905082810360608401526200101d818662000ca3565b9050828103608084015262001033818562000ca3565b98975050505050505050565b6000602082840312156200105257600080fd5b8151801515811462000c7657600080fdfe6101606040523480156200001257600080fd5b50604051620018fa380380620018fa833981016040819052620000359162000357565b6040805180820190915260018152603160f81b6020820152859081908882886003620000628382620004db565b506004620000718282620004db565b5050506001600160a01b038116620000a457604051631e4fbdf760e01b8152600060048201526024015b60405180910390fd5b620000af816200019f565b50620000bd826006620001f1565b61012052620000ce816007620001f1565b61014052815160208084019190912060e052815190820120610100524660a0526200015c60e05161010051604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201529081019290925260608201524660808201523060a082015260009060c00160405160208183030381529060405280519060200120905090565b60805250503060c052506009620001748482620004db565b50600a620001838382620004db565b50600b620001928282620004db565b5050505050505062000601565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6000602083511015620002115762000209836200022a565b905062000224565b816200021e8482620004db565b5060ff90505b92915050565b600080829050601f8151111562000258578260405163305a27a960e01b81526004016200009b9190620005a7565b80516200026582620005dc565b179392505050565b80516001600160a01b03811681146200028557600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60005b83811015620002bd578181015183820152602001620002a3565b50506000910152565b600082601f830112620002d857600080fd5b81516001600160401b0380821115620002f557620002f56200028a565b604051601f8301601f19908116603f011681019082821181831017156200032057620003206200028a565b816040528381528660208588010111156200033a57600080fd5b6200034d846020830160208901620002a0565b9695505050505050565b60008060008060008060c087890312156200037157600080fd5b6200037c876200026d565b60208801519096506001600160401b03808211156200039a57600080fd5b620003a88a838b01620002c6565b96506040890151915080821115620003bf57600080fd5b620003cd8a838b01620002c6565b95506060890151915080821115620003e457600080fd5b620003f28a838b01620002c6565b945060808901519150808211156200040957600080fd5b620004178a838b01620002c6565b935060a08901519150808211156200042e57600080fd5b506200043d89828a01620002c6565b9150509295509295509295565b600181811c908216806200045f57607f821691505b6020821081036200048057634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115620004d6576000816000526020600020601f850160051c81016020861015620004b15750805b601f850160051c820191505b81811015620004d257828155600101620004bd565b5050505b505050565b81516001600160401b03811115620004f757620004f76200028a565b6200050f816200050884546200044a565b8462000486565b602080601f8311600181146200054757600084156200052e5750858301515b600019600386901b1c1916600185901b178555620004d2565b600085815260208120601f198616915b82811015620005785788860151825594840194600190910190840162000557565b5085821015620005975787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6020815260008251806020840152620005c8816040850160208701620002a0565b601f01601f19169190910160400192915050565b80516020808301519190811015620004805760001960209190910360031b1b16919050565b60805160a05160c05160e05161010051610120516101405161129e6200065c6000396000610a8801526000610a5b01526000610918015260006108f00152600061084b015260006108750152600061089f015261129e6000f3fe608060405234801561001057600080fd5b50600436106101735760003560e01c8063715018a6116100de578063a76b4d5611610097578063dc9716eb11610071578063dc9716eb146102f8578063dd62ed3e14610300578063e8a3d48514610339578063f2fde38b1461034157600080fd5b8063a76b4d56146102ca578063a9059cbb146102d2578063d505accf146102e557600080fd5b8063715018a61461025e57806379cc6790146102665780637ecebe001461027957806384b0196e1461028c5780638da5cb5b146102a757806395d89b41146102c257600080fd5b8063313ce56711610130578063313ce567146101ee5780633644e515146101fd5780633fd4d4a81461020557806340c10f191461020d57806342966c681461022257806370a082311461023557600080fd5b806306fdde0314610178578063095ea7b3146101965780630cd9acb7146101b9578063120a88ad146101c157806318160ddd146101c957806323b872dd146101db575b600080fd5b610180610354565b60405161018d9190610fe8565b60405180910390f35b6101a96101a436600461101e565b6103e6565b604051901515815260200161018d565b610180610400565b61018061048e565b6002545b60405190815260200161018d565b6101a96101e9366004611048565b61049d565b6040516012815260200161018d565b6101cd6104c1565b6101806104d0565b61022061021b36600461101e565b6104df565b005b610220610230366004611084565b6104f5565b6101cd61024336600461109d565b6001600160a01b031660009081526020819052604090205490565b610220610502565b61022061027436600461101e565b610516565b6101cd61028736600461109d565b61052b565b610294610549565b60405161018d97969594939291906110b8565b6005546040516001600160a01b03909116815260200161018d565b61018061058f565b61018061059e565b6101a96102e036600461101e565b6105ab565b6102206102f3366004611151565b6105b9565b6101806106f8565b6101cd61030e3660046111c4565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b610180610705565b61022061034f36600461109d565b610714565b606060038054610363906111f7565b80601f016020809104026020016040519081016040528092919081815260200182805461038f906111f7565b80156103dc5780601f106103b1576101008083540402835291602001916103dc565b820191906000526020600020905b8154815290600101906020018083116103bf57829003601f168201915b5050505050905090565b6000336103f481858561074f565b60019150505b92915050565b6009805461040d906111f7565b80601f0160208091040260200160405190810160405280929190818152602001828054610439906111f7565b80156104865780601f1061045b57610100808354040283529160200191610486565b820191906000526020600020905b81548152906001019060200180831161046957829003601f168201915b505050505081565b606060098054610363906111f7565b6000336104ab858285610761565b6104b68585856107df565b506001949350505050565b60006104cb61083e565b905090565b6060600a8054610363906111f7565b6104e7610969565b6104f18282610996565b5050565b6104ff33826109cc565b50565b61050a610969565b6105146000610a02565b565b610521823383610761565b6104f182826109cc565b6001600160a01b0381166000908152600860205260408120546103fa565b60006060806000806000606061055d610a54565b610565610a81565b60408051600080825260208201909252600f60f81b9b939a50919850469750309650945092509050565b606060048054610363906111f7565b600b805461040d906111f7565b6000336103f48185856107df565b834211156105e25760405163313c898160e11b8152600481018590526024015b60405180910390fd5b60007f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c988888861062f8c6001600160a01b0316600090815260086020526040902080546001810190915590565b6040805160208101969096526001600160a01b0394851690860152929091166060840152608083015260a082015260c0810186905260e001604051602081830303815290604052805190602001209050600061068a82610aae565b9050600061069a82878787610adb565b9050896001600160a01b0316816001600160a01b0316146106e1576040516325c0072360e11b81526001600160a01b0380831660048301528b1660248201526044016105d9565b6106ec8a8a8a61074f565b50505050505050505050565b600a805461040d906111f7565b6060600b8054610363906111f7565b61071c610969565b6001600160a01b03811661074657604051631e4fbdf760e01b8152600060048201526024016105d9565b6104ff81610a02565b61075c8383836001610b09565b505050565b6001600160a01b0383811660009081526001602090815260408083209386168352929052205460001981146107d957818110156107ca57604051637dc7a0d960e11b81526001600160a01b038416600482015260248101829052604481018390526064016105d9565b6107d984848484036000610b09565b50505050565b6001600160a01b03831661080957604051634b637e8f60e11b8152600060048201526024016105d9565b6001600160a01b0382166108335760405163ec442f0560e01b8152600060048201526024016105d9565b61075c838383610bde565b6000306001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614801561089757507f000000000000000000000000000000000000000000000000000000000000000046145b156108c157507f000000000000000000000000000000000000000000000000000000000000000090565b6104cb604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201527f0000000000000000000000000000000000000000000000000000000000000000918101919091527f000000000000000000000000000000000000000000000000000000000000000060608201524660808201523060a082015260009060c00160405160208183030381529060405280519060200120905090565b6005546001600160a01b031633146105145760405163118cdaa760e01b81523360048201526024016105d9565b6001600160a01b0382166109c05760405163ec442f0560e01b8152600060048201526024016105d9565b6104f160008383610bde565b6001600160a01b0382166109f657604051634b637e8f60e11b8152600060048201526024016105d9565b6104f182600083610bde565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b60606104cb7f00000000000000000000000000000000000000000000000000000000000000006006610d08565b60606104cb7f00000000000000000000000000000000000000000000000000000000000000006007610d08565b60006103fa610abb61083e565b8360405161190160f01b8152600281019290925260228201526042902090565b600080600080610aed88888888610db3565b925092509250610afd8282610e82565b50909695505050505050565b6001600160a01b038416610b335760405163e602df0560e01b8152600060048201526024016105d9565b6001600160a01b038316610b5d57604051634a1406b160e11b8152600060048201526024016105d9565b6001600160a01b03808516600090815260016020908152604080832093871683529290522082905580156107d957826001600160a01b0316846001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92584604051610bd091815260200190565b60405180910390a350505050565b6001600160a01b038316610c09578060026000828254610bfe9190611231565b90915550610c7b9050565b6001600160a01b03831660009081526020819052604090205481811015610c5c5760405163391434e360e21b81526001600160a01b038516600482015260248101829052604481018390526064016105d9565b6001600160a01b03841660009081526020819052604090209082900390555b6001600160a01b038216610c9757600280548290039055610cb6565b6001600160a01b03821660009081526020819052604090208054820190555b816001600160a01b0316836001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef83604051610cfb91815260200190565b60405180910390a3505050565b606060ff8314610d2257610d1b83610f3b565b90506103fa565b818054610d2e906111f7565b80601f0160208091040260200160405190810160405280929190818152602001828054610d5a906111f7565b8015610da75780601f10610d7c57610100808354040283529160200191610da7565b820191906000526020600020905b815481529060010190602001808311610d8a57829003601f168201915b505050505090506103fa565b600080807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0841115610dee5750600091506003905082610e78565b604080516000808252602082018084528a905260ff891692820192909252606081018790526080810186905260019060a0016020604051602081039080840390855afa158015610e42573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116610e6e57506000925060019150829050610e78565b9250600091508190505b9450945094915050565b6000826003811115610e9657610e96611252565b03610e9f575050565b6001826003811115610eb357610eb3611252565b03610ed15760405163f645eedf60e01b815260040160405180910390fd5b6002826003811115610ee557610ee5611252565b03610f065760405163fce698f760e01b8152600481018290526024016105d9565b6003826003811115610f1a57610f1a611252565b036104f1576040516335e2f38360e21b8152600481018290526024016105d9565b60606000610f4883610f7a565b604080516020808252818301909252919250600091906020820181803683375050509182525060208101929092525090565b600060ff8216601f8111156103fa57604051632cd44ac360e21b815260040160405180910390fd5b6000815180845260005b81811015610fc857602081850181015186830182015201610fac565b506000602082860101526020601f19601f83011685010191505092915050565b602081526000610ffb6020830184610fa2565b9392505050565b80356001600160a01b038116811461101957600080fd5b919050565b6000806040838503121561103157600080fd5b61103a83611002565b946020939093013593505050565b60008060006060848603121561105d57600080fd5b61106684611002565b925061107460208501611002565b9150604084013590509250925092565b60006020828403121561109657600080fd5b5035919050565b6000602082840312156110af57600080fd5b610ffb82611002565b60ff60f81b881681526000602060e060208401526110d960e084018a610fa2565b83810360408501526110eb818a610fa2565b606085018990526001600160a01b038816608086015260a0850187905284810360c08601528551808252602080880193509091019060005b8181101561113f57835183529284019291840191600101611123565b50909c9b505050505050505050505050565b600080600080600080600060e0888a03121561116c57600080fd5b61117588611002565b965061118360208901611002565b95506040880135945060608801359350608088013560ff811681146111a757600080fd5b9699959850939692959460a0840135945060c09093013592915050565b600080604083850312156111d757600080fd5b6111e083611002565b91506111ee60208401611002565b90509250929050565b600181811c9082168061120b57607f821691505b60208210810361122b57634e487b7160e01b600052602260045260246000fd5b50919050565b808201808211156103fa57634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052602160045260246000fdfea26469706673582212200fea5736ecebd6f4f71e77a0743e7169bb21209a84517a64d4e0a6b0313817b864736f6c6343000817003360806040523480156200001157600080fd5b5060405162001eb738038062001eb7833981016040819052620000349162000202565b858585600062000045838262000386565b50600162000054828262000386565b5050506001600160a01b0381166200008657604051631e4fbdf760e01b81526000600482015260240160405180910390fd5b6200009181620000cb565b50600c620000a0848262000386565b50600d620000af838262000386565b50600e620000be828262000386565b5050505050505062000452565b600b80546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b80516001600160a01b03811681146200013557600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126200016257600080fd5b81516001600160401b03808211156200017f576200017f6200013a565b604051601f8301601f19908116603f01168101908282118183101715620001aa57620001aa6200013a565b8160405283815260209250866020858801011115620001c857600080fd5b600091505b83821015620001ec5785820183015181830184015290820190620001cd565b6000602085830101528094505050505092915050565b60008060008060008060c087890312156200021c57600080fd5b62000227876200011d565b60208801519096506001600160401b03808211156200024557600080fd5b620002538a838b0162000150565b965060408901519150808211156200026a57600080fd5b620002788a838b0162000150565b955060608901519150808211156200028f57600080fd5b6200029d8a838b0162000150565b94506080890151915080821115620002b457600080fd5b620002c28a838b0162000150565b935060a0890151915080821115620002d957600080fd5b50620002e889828a0162000150565b9150509295509295509295565b600181811c908216806200030a57607f821691505b6020821081036200032b57634e487b7160e01b600052602260045260246000fd5b50919050565b601f82111562000381576000816000526020600020601f850160051c810160208610156200035c5750805b601f850160051c820191505b818110156200037d5782815560010162000368565b5050505b505050565b81516001600160401b03811115620003a257620003a26200013a565b620003ba81620003b38454620002f5565b8462000331565b602080601f831160018114620003f25760008415620003d95750858301515b600019600386901b1c1916600185901b1785556200037d565b600085815260208120601f198616915b82811015620004235788860151825594840194600190910190840162000402565b5085821015620004425787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b611a5580620004626000396000f3fe608060405234801561001057600080fd5b50600436106101cf5760003560e01c806370a0823111610104578063a76b4d56116100a2578063cd279c7c11610071578063cd279c7c146103a8578063e8a3d485146103bb578063e985e9c5146103c3578063f2fde38b146103d657600080fd5b8063a76b4d5614610372578063b49bbd941461037a578063b88d4fde14610382578063c87b56dd1461039557600080fd5b806394e29329116100de57806394e293291461034757806395d89b411461034f578063a159047b14610357578063a22cb4651461035f57600080fd5b806370a082311461031b578063715018a61461032e5780638da5cb5b1461033657600080fd5b80632f745c59116101715780634f558e791161014b5780634f558e79146102c25780634f6ccce7146102ed5780635e0a9661146103005780636352211e1461030857600080fd5b80632f745c591461028957806342842e0e1461029c57806342966c68146102af57600080fd5b8063095ea7b3116101ad578063095ea7b31461023c57806318160ddd1461025157806318e97fd11461026357806323b872dd1461027657600080fd5b806301ffc9a7146101d457806306fdde03146101fc578063081812fc14610211575b600080fd5b6101e76101e2366004611494565b6103e9565b60405190151581526020015b60405180910390f35b6102046103fa565b6040516101f39190611501565b61022461021f366004611514565b61048c565b6040516001600160a01b0390911681526020016101f3565b61024f61024a366004611549565b6104b5565b005b6009545b6040519081526020016101f3565b61024f61027136600461161f565b6104c4565b61024f610284366004611666565b6104d6565b610255610297366004611549565b610566565b61024f6102aa366004611666565b6105cb565b61024f6102bd366004611514565b6105eb565b6101e76102d0366004611514565b6000908152600260205260409020546001600160a01b0316151590565b6102556102fb366004611514565b6105f7565b610204610650565b610224610316366004611514565b61065f565b6102556103293660046116a2565b61066a565b61024f6106b2565b600b546001600160a01b0316610224565b6102046106c6565b6102046106d5565b6102046106e4565b61024f61036d3660046116bd565b610772565b61020461077d565b61020461078a565b61024f6103903660046116f9565b610797565b6102046103a3366004611514565b6107ae565b61024f6103b6366004611775565b6107b9565b6102046107d5565b6101e76103d13660046117cc565b6107e4565b61024f6103e43660046116a2565b610812565b60006103f482610850565b92915050565b606060008054610409906117ff565b80601f0160208091040260200160405190810160405280929190818152602001828054610435906117ff565b80156104825780601f1061045757610100808354040283529160200191610482565b820191906000526020600020905b81548152906001019060200180831161046557829003601f168201915b5050505050905090565b600061049782610875565b506000828152600460205260409020546001600160a01b03166103f4565b6104c08282336108ae565b5050565b6104cc6108bb565b6104c082826108e8565b6001600160a01b03821661050557604051633250574960e11b8152600060048201526024015b60405180910390fd5b6000610512838333610938565b9050836001600160a01b0316816001600160a01b031614610560576040516364283d7b60e01b81526001600160a01b03808616600483015260248201849052821660448201526064016104fc565b50505050565b60006105718361066a565b82106105a25760405163295f44f760e21b81526001600160a01b0384166004820152602481018390526044016104fc565b506001600160a01b03919091166000908152600760209081526040808320938352929052205490565b6105e683838360405180602001604052806000815250610797565b505050565b6104c060008233610938565b600061060260095490565b821061062b5760405163295f44f760e21b815260006004820152602481018390526044016104fc565b6009828154811061063e5761063e611839565b90600052602060002001549050919050565b6060600d8054610409906117ff565b60006103f482610875565b60006001600160a01b038216610696576040516322718ad960e21b8152600060048201526024016104fc565b506001600160a01b031660009081526003602052604090205490565b6106ba6108bb565b6106c4600061094d565b565b6060600c8054610409906117ff565b606060018054610409906117ff565b600d80546106f1906117ff565b80601f016020809104026020016040519081016040528092919081815260200182805461071d906117ff565b801561076a5780601f1061073f5761010080835404028352916020019161076a565b820191906000526020600020905b81548152906001019060200180831161074d57829003601f168201915b505050505081565b6104c033838361099f565b600e80546106f1906117ff565b600c80546106f1906117ff565b6107a28484846104d6565b61056084848484610a3e565b60606103f482610b67565b6107c16108bb565b6107cb8383610c70565b6105e682826108e8565b6060600e8054610409906117ff565b6001600160a01b03918216600090815260056020908152604080832093909416825291909152205460ff1690565b61081a6108bb565b6001600160a01b03811661084457604051631e4fbdf760e01b8152600060048201526024016104fc565b61084d8161094d565b50565b60006001600160e01b0319821663780e9d6360e01b14806103f457506103f482610c8a565b6000818152600260205260408120546001600160a01b0316806103f457604051637e27328960e01b8152600481018490526024016104fc565b6105e68383836001610caf565b600b546001600160a01b031633146106c45760405163118cdaa760e01b81523360048201526024016104fc565b6000828152600660205260409020610900828261189f565b506040518281527ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79060200160405180910390a15050565b6000610945848484610db5565b949350505050565b600b80546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6001600160a01b0382166109d157604051630b61174360e31b81526001600160a01b03831660048201526024016104fc565b6001600160a01b03838116600081815260056020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b6001600160a01b0383163b1561056057604051630a85bd0160e11b81526001600160a01b0384169063150b7a0290610a8090339088908790879060040161195f565b6020604051808303816000875af1925050508015610abb575060408051601f3d908101601f19168201909252610ab89181019061199c565b60015b610b24573d808015610ae9576040519150601f19603f3d011682016040523d82523d6000602084013e610aee565b606091505b508051600003610b1c57604051633250574960e11b81526001600160a01b03851660048201526024016104fc565b805181602001fd5b6001600160e01b03198116630a85bd0160e11b14610b6057604051633250574960e11b81526001600160a01b03851660048201526024016104fc565b5050505050565b6060610b7282610875565b5060008281526006602052604081208054610b8c906117ff565b80601f0160208091040260200160405190810160405280929190818152602001828054610bb8906117ff565b8015610c055780601f10610bda57610100808354040283529160200191610c05565b820191906000526020600020905b815481529060010190602001808311610be857829003601f168201915b505050505090506000610c2360408051602081019091526000815290565b90508051600003610c35575092915050565b815115610c67578082604051602001610c4f9291906119b9565b60405160208183030381529060405292505050919050565b61094584610e82565b6104c0828260405180602001604052806000815250610ef7565b60006001600160e01b03198216632483248360e11b14806103f457506103f482610f0e565b8080610cc357506001600160a01b03821615155b15610d85576000610cd384610875565b90506001600160a01b03831615801590610cff5750826001600160a01b0316816001600160a01b031614155b8015610d125750610d1081846107e4565b155b15610d3b5760405163a9fbf51f60e01b81526001600160a01b03841660048201526024016104fc565b8115610d835783856001600160a01b0316826001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45b505b5050600090815260046020526040902080546001600160a01b0319166001600160a01b0392909216919091179055565b600080610dc3858585610f5e565b90506001600160a01b038116610e2057610e1b84600980546000838152600a60205260408120829055600182018355919091527f6e1540171b6c0c960b71a7020d9f60077f6af931a8bbf590da0223dacf75c7af0155565b610e43565b846001600160a01b0316816001600160a01b031614610e4357610e438185611057565b6001600160a01b038516610e5f57610e5a846110e8565b610945565b846001600160a01b0316816001600160a01b031614610945576109458585611197565b6060610e8d82610875565b506000610ea560408051602081019091526000815290565b90506000815111610ec55760405180602001604052806000815250610ef0565b80610ecf846111e7565b604051602001610ee09291906119b9565b6040516020818303038152906040525b9392505050565b610f01838361127a565b6105e66000848484610a3e565b60006001600160e01b031982166380ac58cd60e01b1480610f3f57506001600160e01b03198216635b5e139f60e01b145b806103f457506301ffc9a760e01b6001600160e01b03198316146103f4565b6000828152600260205260408120546001600160a01b0390811690831615610f8b57610f8b8184866112df565b6001600160a01b03811615610fc957610fa8600085600080610caf565b6001600160a01b038116600090815260036020526040902080546000190190555b6001600160a01b03851615610ff8576001600160a01b0385166000908152600360205260409020805460010190555b60008481526002602052604080822080546001600160a01b0319166001600160a01b0389811691821790925591518793918516917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4949350505050565b60006110628361066a565b6000838152600860205260409020549091508082146110b5576001600160a01b03841660009081526007602090815260408083208584528252808320548484528184208190558352600890915290208190555b5060009182526008602090815260408084208490556001600160a01b039094168352600781528383209183525290812055565b6009546000906110fa906001906119e8565b6000838152600a60205260408120546009805493945090928490811061112257611122611839565b90600052602060002001549050806009838154811061114357611143611839565b6000918252602080832090910192909255828152600a9091526040808220849055858252812055600980548061117b5761117b611a09565b6001900381819060005260206000200160009055905550505050565b600060016111a48461066a565b6111ae91906119e8565b6001600160a01b039093166000908152600760209081526040808320868452825280832085905593825260089052919091209190915550565b606060006111f483611343565b600101905060008167ffffffffffffffff81111561121457611214611573565b6040519080825280601f01601f19166020018201604052801561123e576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a850494508461124857509392505050565b6001600160a01b0382166112a457604051633250574960e11b8152600060048201526024016104fc565b60006112b283836000610938565b90506001600160a01b038116156105e6576040516339e3563760e11b8152600060048201526024016104fc565b6112ea83838361141b565b6105e6576001600160a01b03831661131857604051637e27328960e01b8152600481018290526024016104fc565b60405163177e802f60e01b81526001600160a01b0383166004820152602481018290526044016104fc565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b83106113825772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef810000000083106113ae576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc1000083106113cc57662386f26fc10000830492506010015b6305f5e10083106113e4576305f5e100830492506008015b61271083106113f857612710830492506004015b6064831061140a576064830492506002015b600a83106103f45760010192915050565b60006001600160a01b038316158015906109455750826001600160a01b0316846001600160a01b03161480611455575061145584846107e4565b806109455750506000908152600460205260409020546001600160a01b03908116911614919050565b6001600160e01b03198116811461084d57600080fd5b6000602082840312156114a657600080fd5b8135610ef08161147e565b60005b838110156114cc5781810151838201526020016114b4565b50506000910152565b600081518084526114ed8160208601602086016114b1565b601f01601f19169290920160200192915050565b602081526000610ef060208301846114d5565b60006020828403121561152657600080fd5b5035919050565b80356001600160a01b038116811461154457600080fd5b919050565b6000806040838503121561155c57600080fd5b6115658361152d565b946020939093013593505050565b634e487b7160e01b600052604160045260246000fd5b600067ffffffffffffffff808411156115a4576115a4611573565b604051601f8501601f19908116603f011681019082821181831017156115cc576115cc611573565b816040528093508581528686860111156115e557600080fd5b858560208301376000602087830101525050509392505050565b600082601f83011261161057600080fd5b610ef083833560208501611589565b6000806040838503121561163257600080fd5b82359150602083013567ffffffffffffffff81111561165057600080fd5b61165c858286016115ff565b9150509250929050565b60008060006060848603121561167b57600080fd5b6116848461152d565b92506116926020850161152d565b9150604084013590509250925092565b6000602082840312156116b457600080fd5b610ef08261152d565b600080604083850312156116d057600080fd5b6116d98361152d565b9150602083013580151581146116ee57600080fd5b809150509250929050565b6000806000806080858703121561170f57600080fd5b6117188561152d565b93506117266020860161152d565b925060408501359150606085013567ffffffffffffffff81111561174957600080fd5b8501601f8101871361175a57600080fd5b61176987823560208401611589565b91505092959194509250565b60008060006060848603121561178a57600080fd5b6117938461152d565b925060208401359150604084013567ffffffffffffffff8111156117b657600080fd5b6117c2868287016115ff565b9150509250925092565b600080604083850312156117df57600080fd5b6117e88361152d565b91506117f66020840161152d565b90509250929050565b600181811c9082168061181357607f821691505b60208210810361183357634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052603260045260246000fd5b601f8211156105e6576000816000526020600020601f850160051c810160208610156118785750805b601f850160051c820191505b8181101561189757828155600101611884565b505050505050565b815167ffffffffffffffff8111156118b9576118b9611573565b6118cd816118c784546117ff565b8461184f565b602080601f83116001811461190257600084156118ea5750858301515b600019600386901b1c1916600185901b178555611897565b600085815260208120601f198616915b8281101561193157888601518255948401946001909101908401611912565b508582101561194f5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6001600160a01b0385811682528416602082015260408101839052608060608201819052600090611992908301846114d5565b9695505050505050565b6000602082840312156119ae57600080fd5b8151610ef08161147e565b600083516119cb8184602088016114b1565b8351908301906119df8183602088016114b1565b01949350505050565b818103818111156103f457634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052603160045260246000fdfea26469706673582212206ff38700c73b602455dbb7964f2d3281f62efc77263f0f3bdb67f5e4ee5d4f3f64736f6c63430008170033a2646970667358221220d058cf8dfb17169ff3320b4ba2cb9665d5f875cda19c5c22351f341d783cad4064736f6c63430008170033" access(all) let compiledERC721Bytecode = "60806040523480156200001157600080fd5b5033604051806040016040528060048152602001634e414d4560e01b8152506040518060400160405280600681526020016514d6535093d360d21b8152508160009081620000609190620001ac565b5060016200006f8282620001ac565b5050506001600160a01b038116620000a157604051631e4fbdf760e01b81526000600482015260240160405180910390fd5b620000ac81620000b3565b5062000278565b600780546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b634e487b7160e01b600052604160045260246000fd5b600181811c908216806200013057607f821691505b6020821081036200015157634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115620001a7576000816000526020600020601f850160051c81016020861015620001825750805b601f850160051c820191505b81811015620001a3578281556001016200018e565b5050505b505050565b81516001600160401b03811115620001c857620001c862000105565b620001e081620001d984546200011b565b8462000157565b602080601f831160018114620002185760008415620001ff5750858301515b600019600386901b1c1916600185901b178555620001a3565b600085815260208120601f198616915b82811015620002495788860151825594840194600190910190840162000228565b5085821015620002685787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b61143080620002886000396000f3fe608060405234801561001057600080fd5b50600436106101165760003560e01c8063715018a6116100a2578063b88d4fde11610071578063b88d4fde14610239578063c87b56dd1461024c578063cd279c7c1461025f578063e985e9c514610272578063f2fde38b1461028557600080fd5b8063715018a6146102055780638da5cb5b1461020d57806395d89b411461021e578063a22cb4651461022657600080fd5b806323b872dd116100e957806323b872dd1461019857806342842e0e146101ab57806342966c68146101be5780636352211e146101d157806370a08231146101e457600080fd5b806301ffc9a71461011b57806306fdde0314610143578063081812fc14610158578063095ea7b314610183575b600080fd5b61012e610129366004610f0f565b610298565b60405190151581526020015b60405180910390f35b61014b6102a9565b60405161013a9190610f7c565b61016b610166366004610f8f565b61033b565b6040516001600160a01b03909116815260200161013a565b610196610191366004610fc4565b610364565b005b6101966101a6366004610fee565b610373565b6101966101b9366004610fee565b610403565b6101966101cc366004610f8f565b610423565b61016b6101df366004610f8f565b61042f565b6101f76101f236600461102a565b61043a565b60405190815260200161013a565b610196610482565b6007546001600160a01b031661016b565b61014b610496565b610196610234366004611045565b6104a5565b61019661024736600461110d565b6104b0565b61014b61025a366004610f8f565b6104c7565b61019661026d366004611189565b6104d2565b61012e6102803660046111f4565b6104ee565b61019661029336600461102a565b61051c565b60006102a38261055a565b92915050565b6060600080546102b890611227565b80601f01602080910402602001604051908101604052809291908181526020018280546102e490611227565b80156103315780601f1061030657610100808354040283529160200191610331565b820191906000526020600020905b81548152906001019060200180831161031457829003601f168201915b5050505050905090565b60006103468261057f565b506000828152600460205260409020546001600160a01b03166102a3565b61036f8282336105b8565b5050565b6001600160a01b0382166103a257604051633250574960e11b8152600060048201526024015b60405180910390fd5b60006103af8383336105c5565b9050836001600160a01b0316816001600160a01b0316146103fd576040516364283d7b60e01b81526001600160a01b0380861660048301526024820184905282166044820152606401610399565b50505050565b61041e838383604051806020016040528060008152506104b0565b505050565b61036f600082336105c5565b60006102a38261057f565b60006001600160a01b038216610466576040516322718ad960e21b815260006004820152602401610399565b506001600160a01b031660009081526003602052604090205490565b61048a6106be565b61049460006106eb565b565b6060600180546102b890611227565b61036f33838361073d565b6104bb848484610373565b6103fd848484846107dc565b60606102a382610905565b6104da6106be565b6104e48383610a16565b61041e8282610a30565b6001600160a01b03918216600090815260056020908152604080832093909416825291909152205460ff1690565b6105246106be565b6001600160a01b03811661054e57604051631e4fbdf760e01b815260006004820152602401610399565b610557816106eb565b50565b60006001600160e01b03198216632483248360e11b14806102a357506102a382610a80565b6000818152600260205260408120546001600160a01b0316806102a357604051637e27328960e01b815260048101849052602401610399565b61041e8383836001610ad0565b6000828152600260205260408120546001600160a01b03908116908316156105f2576105f2818486610bd6565b6001600160a01b038116156106305761060f600085600080610ad0565b6001600160a01b038116600090815260036020526040902080546000190190555b6001600160a01b0385161561065f576001600160a01b0385166000908152600360205260409020805460010190555b60008481526002602052604080822080546001600160a01b0319166001600160a01b0389811691821790925591518793918516917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4949350505050565b6007546001600160a01b031633146104945760405163118cdaa760e01b8152336004820152602401610399565b600780546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6001600160a01b03821661076f57604051630b61174360e31b81526001600160a01b0383166004820152602401610399565b6001600160a01b03838116600081815260056020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b6001600160a01b0383163b156103fd57604051630a85bd0160e11b81526001600160a01b0384169063150b7a029061081e903390889087908790600401611261565b6020604051808303816000875af1925050508015610859575060408051601f3d908101601f191682019092526108569181019061129e565b60015b6108c2573d808015610887576040519150601f19603f3d011682016040523d82523d6000602084013e61088c565b606091505b5080516000036108ba57604051633250574960e11b81526001600160a01b0385166004820152602401610399565b805181602001fd5b6001600160e01b03198116630a85bd0160e11b146108fe57604051633250574960e11b81526001600160a01b0385166004820152602401610399565b5050505050565b60606109108261057f565b506000828152600660205260408120805461092a90611227565b80601f016020809104026020016040519081016040528092919081815260200182805461095690611227565b80156109a35780601f10610978576101008083540402835291602001916109a3565b820191906000526020600020905b81548152906001019060200180831161098657829003601f168201915b5050505050905060006109c160408051602081019091526000815290565b905080516000036109d3575092915050565b815115610a055780826040516020016109ed9291906112bb565b60405160208183030381529060405292505050919050565b610a0e84610c3a565b949350505050565b61036f828260405180602001604052806000815250610caf565b6000828152600660205260409020610a48828261133a565b506040518281527ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79060200160405180910390a15050565b60006001600160e01b031982166380ac58cd60e01b1480610ab157506001600160e01b03198216635b5e139f60e01b145b806102a357506301ffc9a760e01b6001600160e01b03198316146102a3565b8080610ae457506001600160a01b03821615155b15610ba6576000610af48461057f565b90506001600160a01b03831615801590610b205750826001600160a01b0316816001600160a01b031614155b8015610b335750610b3181846104ee565b155b15610b5c5760405163a9fbf51f60e01b81526001600160a01b0384166004820152602401610399565b8115610ba45783856001600160a01b0316826001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45b505b5050600090815260046020526040902080546001600160a01b0319166001600160a01b0392909216919091179055565b610be1838383610cc6565b61041e576001600160a01b038316610c0f57604051637e27328960e01b815260048101829052602401610399565b60405163177e802f60e01b81526001600160a01b038316600482015260248101829052604401610399565b6060610c458261057f565b506000610c5d60408051602081019091526000815290565b90506000815111610c7d5760405180602001604052806000815250610ca8565b80610c8784610d29565b604051602001610c989291906112bb565b6040516020818303038152906040525b9392505050565b610cb98383610dbc565b61041e60008484846107dc565b60006001600160a01b03831615801590610a0e5750826001600160a01b0316846001600160a01b03161480610d005750610d0084846104ee565b80610a0e5750506000908152600460205260409020546001600160a01b03908116911614919050565b60606000610d3683610e21565b600101905060008167ffffffffffffffff811115610d5657610d56611081565b6040519080825280601f01601f191660200182016040528015610d80576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a8504945084610d8a57509392505050565b6001600160a01b038216610de657604051633250574960e11b815260006004820152602401610399565b6000610df4838360006105c5565b90506001600160a01b0381161561041e576040516339e3563760e11b815260006004820152602401610399565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b8310610e605772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef81000000008310610e8c576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc100008310610eaa57662386f26fc10000830492506010015b6305f5e1008310610ec2576305f5e100830492506008015b6127108310610ed657612710830492506004015b60648310610ee8576064830492506002015b600a83106102a35760010192915050565b6001600160e01b03198116811461055757600080fd5b600060208284031215610f2157600080fd5b8135610ca881610ef9565b60005b83811015610f47578181015183820152602001610f2f565b50506000910152565b60008151808452610f68816020860160208601610f2c565b601f01601f19169290920160200192915050565b602081526000610ca86020830184610f50565b600060208284031215610fa157600080fd5b5035919050565b80356001600160a01b0381168114610fbf57600080fd5b919050565b60008060408385031215610fd757600080fd5b610fe083610fa8565b946020939093013593505050565b60008060006060848603121561100357600080fd5b61100c84610fa8565b925061101a60208501610fa8565b9150604084013590509250925092565b60006020828403121561103c57600080fd5b610ca882610fa8565b6000806040838503121561105857600080fd5b61106183610fa8565b91506020830135801515811461107657600080fd5b809150509250929050565b634e487b7160e01b600052604160045260246000fd5b600067ffffffffffffffff808411156110b2576110b2611081565b604051601f8501601f19908116603f011681019082821181831017156110da576110da611081565b816040528093508581528686860111156110f357600080fd5b858560208301376000602087830101525050509392505050565b6000806000806080858703121561112357600080fd5b61112c85610fa8565b935061113a60208601610fa8565b925060408501359150606085013567ffffffffffffffff81111561115d57600080fd5b8501601f8101871361116e57600080fd5b61117d87823560208401611097565b91505092959194509250565b60008060006060848603121561119e57600080fd5b6111a784610fa8565b925060208401359150604084013567ffffffffffffffff8111156111ca57600080fd5b8401601f810186136111db57600080fd5b6111ea86823560208401611097565b9150509250925092565b6000806040838503121561120757600080fd5b61121083610fa8565b915061121e60208401610fa8565b90509250929050565b600181811c9082168061123b57607f821691505b60208210810361125b57634e487b7160e01b600052602260045260246000fd5b50919050565b6001600160a01b038581168252841660208201526040810183905260806060820181905260009061129490830184610f50565b9695505050505050565b6000602082840312156112b057600080fd5b8151610ca881610ef9565b600083516112cd818460208801610f2c565b8351908301906112e1818360208801610f2c565b01949350505050565b601f82111561041e576000816000526020600020601f850160051c810160208610156113135750805b601f850160051c820191505b818110156113325782815560010161131f565b505050505050565b815167ffffffffffffffff81111561135457611354611081565b611368816113628454611227565b846112ea565b602080601f83116001811461139d57600084156113855750858301515b600019600386901b1c1916600185901b178555611332565b600085815260208120601f198616915b828110156113cc578886015182559484019460019091019084016113ad565b50858210156113ea5787850151600019600388901b60f8161c191681555b5050505050600190811b0190555056fea264697066735822122046da1d9cfc7c225e4655204f464e2ecbb316a6284c51c9c338433a1abb5919f864736f6c63430008170033" -access(all) let evmBridgeRouterCode = "696d706f7274204e6f6e46756e6769626c65546f6b656e2066726f6d203078303030303030303030303030303030310a696d706f72742046756e6769626c65546f6b656e2066726f6d203078303030303030303030303030303030320a696d706f727420466c6f77546f6b656e2066726f6d203078303030303030303030303030303030330a0a696d706f72742045564d2066726f6d203078303030303030303030303030303030310a0a696d706f72742049466c6f7745564d4e46544272696467652066726f6d203078303030303030303030303030303030370a0a2f2f2f205468697320636f6e747261637420646566696e65732061206d656368616e69736d20666f7220726f7574696e67206272696467652072657175657374732066726f6d207468652045564d20636f6e747261637420746f2074686520466c6f772d45564d206272696467652061732077656c6c0a2f2f2f206173207570646174696e67207468652064657369676e617465642062726964676520616464726573730a2f2f2f0a61636365737328616c6c290a636f6e74726163742045564d427269646765526f75746572207b0a0a202020202f2f2f20456e7469746c656d656e7420616c6c6f77696e6720666f72207570646174657320746f2074686520526f757465720a2020202061636365737328616c6c2920656e7469746c656d656e7420526f7574657241646d696e0a0a202020202f2f2f20456d69747465642069662f7768656e207468652062726964676520636f6e74726163742074686520726f75746572206469726563747320746f20697320757064617465640a2020202061636365737328616c6c29206576656e7420427269646765436f6e74726163745570646174656428616464726573733a20416464726573732c206e616d653a20537472696e67290a202020200a202020202f2f2f204272696467654163636573736f7220696d706c656d656e746174696f6e2075736564206279207468652045564d20636f6e747261637420746f20726f757465206272696467652063616c6c73206265747765656e20564d730a202020202f2f2f0a2020202061636365737328616c6c290a202020207265736f7572636520526f75746572203a2045564d2e4272696467654163636573736f72207b0a20202020202020202f2f2f2041646472657373206f66207468652062726964676520636f6e74726163740a202020202020202061636365737328616c6c292076617220627269646765416464726573733a20416464726573730a20202020202020202f2f2f204e616d65206f66207468652062726964676520636f6e74726163740a202020202020202061636365737328616c6c292076617220627269646765436f6e74726163744e616d653a20537472696e670a0a2020202020202020696e697428616464726573733a20416464726573732c206e616d653a20537472696e6729207b0a20202020202020202020202073656c662e62726964676541646472657373203d20616464726573730a20202020202020202020202073656c662e627269646765436f6e74726163744e616d65203d206e616d650a20202020202020207d0a0a20202020202020202f2f2f2050617373657320616c6f6e672074686520627269646765207265717565737420746f206465646963617465642062726964676520636f6e74726163740a20202020202020202f2f2f0a20202020202020202f2f2f2040706172616d206e66743a20546865204e465420746f206265206272696467656420746f2045564d0a20202020202020202f2f2f2040706172616d20746f3a205468652061646472657373206f66207468652045564d206163636f756e7420746f2072656365697665207468652062726964676564204e46540a20202020202020202f2f2f2040706172616d2066656550726f76696465723a2041207265666572656e636520746f20612046756e6769626c65546f6b656e2050726f76696465722066726f6d20776869636820746865206272696467696e67206665652069732077697468647261776e20696e2024464c4f570a20202020202020202f2f2f0a20202020202020206163636573732845564d2e427269646765290a202020202020202066756e206465706f7369744e4654280a2020202020202020202020206e66743a20407b4e6f6e46756e6769626c65546f6b656e2e4e46547d2c0a202020202020202020202020746f3a2045564d2e45564d416464726573732c0a20202020202020202020202066656550726f76696465723a20617574682846756e6769626c65546f6b656e2e57697468647261772920267b46756e6769626c65546f6b656e2e50726f76696465727d0a202020202020202029207b0a20202020202020202020202073656c662e626f72726f7742726964676528292e6272696467654e4654546f45564d28746f6b656e3a203c2d6e66742c20746f3a20746f2c2066656550726f76696465723a2066656550726f7669646572290a20202020202020207d0a0a20202020202020202f2f2f2050617373657320616c6f6e672074686520627269646765207265717565737420746f20746865206465646963617465642062726964676520636f6e74726163742c2072657475726e696e67207468652062726964676564204e46540a20202020202020202f2f2f0a20202020202020202f2f2f2040706172616d2063616c6c65723a2041207265666572656e636520746f2074686520434f412077686963682063757272656e746c79206f776e7320746865204e465420696e2045564d0a20202020202020202f2f2f2040706172616d20747970653a2054686520436164656e63652074797065206f6620746865204e465420746f20626520627269646765642066726f6d2045564d0a20202020202020202f2f2f2040706172616d2069643a20546865204944206f6620746865204e465420746f20626520627269646765642066726f6d2045564d0a20202020202020202f2f2f2040706172616d2066656550726f76696465723a2041207265666572656e636520746f20612046756e6769626c65546f6b656e2050726f76696465722066726f6d20776869636820746865206272696467696e67206665652069732077697468647261776e20696e2024464c4f570a20202020202020202f2f2f0a20202020202020202f2f2f204072657475726e205468652062726964676564204e46540a20202020202020202f2f2f0a20202020202020206163636573732845564d2e427269646765290a202020202020202066756e2077697468647261774e4654280a20202020202020202020202063616c6c65723a20617574682845564d2e43616c6c29202645564d2e436164656e63654f776e65644163636f756e742c0a202020202020202020202020747970653a20547970652c0a20202020202020202020202069643a2055496e743235362c0a20202020202020202020202066656550726f76696465723a20617574682846756e6769626c65546f6b656e2e57697468647261772920267b46756e6769626c65546f6b656e2e50726f76696465727d0a2020202020202020293a20407b4e6f6e46756e6769626c65546f6b656e2e4e46547d207b0a2020202020202020202020206c657420627269646765203d2073656c662e626f72726f7742726964676528290a2020202020202020202020202f2f20446566696e6520612063616c6c6261636b2066756e6374696f6e2c20656e61626c696e67207468652062726964676520746f20616374206f6e2074686520657068656d6572616c20434f41207265666572656e636520696e2073636f70650a202020202020202020202020766172206578656375746564203d2066616c73650a20202020202020202020202066756e2063616c6c6261636b28293a2045564d2e526573756c74207b0a20202020202020202020202020202020707265207b0a20202020202020202020202020202020202020202165786563757465643a202243616c6c6261636b2063616e206f6e6c79206265206578656375746564206f6e6365220a202020202020202020202020202020207d0a20202020202020202020202020202020706f7374207b0a202020202020202020202020202020202020202065786563757465643a202243616c6c6261636b206d757374206265206578656375746564220a202020202020202020202020202020207d0a202020202020202020202020202020206578656375746564203d20747275650a2020202020202020202020202020202072657475726e2063616c6c65722e63616c6c280a2020202020202020202020202020202020202020746f3a206272696467652e6765744173736f63696174656445564d4164647265737328776974683a2074797065290a2020202020202020202020202020202020202020202020203f3f2070616e696328224e6f2045564d2061646472657373206173736f6369617465642077697468207479706522292c0a2020202020202020202020202020202020202020646174613a2045564d2e656e636f6465414249576974685369676e6174757265280a20202020202020202020202020202020202020202020202022736166655472616e7366657246726f6d28616464726573732c616464726573732c75696e7432353629222c0a2020202020202020202020202020202020202020202020205b63616c6c65722e6164647265737328292c206272696467652e676574427269646765434f4145564d4164647265737328292c2069645d0a2020202020202020202020202020202020202020292c0a20202020202020202020202020202020202020206761734c696d69743a2031353030303030302c0a202020202020202020202020202020202020202076616c75653a2045564d2e42616c616e6365286174746f666c6f773a2030290a20202020202020202020202020202020290a2020202020202020202020207d0a2020202020202020202020202f2f2045786563757465207468652062726964676520726571756573740a20202020202020202020202072657475726e203c2d206272696467652e6272696467654e465446726f6d45564d280a202020202020202020202020202020206f776e65723a2063616c6c65722e6164647265737328292c0a20202020202020202020202020202020747970653a20747970652c0a2020202020202020202020202020202069643a2069642c0a2020202020202020202020202020202066656550726f76696465723a2066656550726f76696465722c0a2020202020202020202020202020202070726f7465637465645472616e7366657243616c6c3a2063616c6c6261636b0a202020202020202020202020290a20202020202020207d0a0a20202020202020202f2f2f2053657473207468652062726964676520636f6e74726163742074686520726f75746572206469726563747320627269646765207265717565737473207468726f7567680a20202020202020202f2f2f0a202020202020202061636365737328526f7574657241646d696e292066756e20736574427269646765436f6e747261637428616464726573733a20416464726573732c206e616d653a20537472696e6729207b0a20202020202020202020202073656c662e62726964676541646472657373203d20616464726573730a20202020202020202020202073656c662e627269646765436f6e74726163744e616d65203d206e616d650a202020202020202020202020656d697420427269646765436f6e74726163745570646174656428616464726573733a20616464726573732c206e616d653a206e616d65290a20202020202020207d0a0a20202020202020202f2f2f2052657475726e732061207265666572656e636520746f207468652062726964676520636f6e74726163740a20202020202020202f2f2f0a20202020202020206163636573732873656c66292066756e20626f72726f7742726964676528293a20267b49466c6f7745564d4e46544272696467657d207b0a20202020202020202020202072657475726e206765744163636f756e742873656c662e62726964676541646472657373292e636f6e7472616374732e626f72726f773c267b49466c6f7745564d4e46544272696467657d3e286e616d653a2073656c662e627269646765436f6e74726163744e616d65290a202020202020202020202020202020203f3f2070616e6963282242726964676520636f6e7472616374206e6f7420666f756e6422290a20202020202020207d0a202020207d0a0a20202020696e697428627269646765416464726573733a20416464726573732c20627269646765436f6e74726163744e616d653a20537472696e6729207b0a202020202020202073656c662e6163636f756e742e73746f726167652e73617665280a2020202020202020202020203c2d63726561746520526f7574657228616464726573733a20627269646765416464726573732c206e616d653a20627269646765436f6e74726163744e616d65292c0a202020202020202020202020746f3a202f73746f726167652f65766d427269646765526f757465720a2020202020202020290a202020207d0a7d0a" +access(all) let compiledERC20Bytecode = "6101606040523480156200001257600080fd5b50604051806040016040528060048152602001634e414d4560e01b81525080604051806040016040528060018152602001603160f81b81525033604051806040016040528060048152602001634e414d4560e01b8152506040518060400160405280600681526020016514d6535093d360d21b815250816003908162000099919062000318565b506004620000a8828262000318565b5050506001600160a01b038116620000db57604051631e4fbdf760e01b8152600060048201526024015b60405180910390fd5b620000e681620001a3565b50620000f4826006620001f5565b6101205262000105816007620001f5565b61014052815160208084019190912060e052815190820120610100524660a0526200019360e05161010051604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201529081019290925260608201524660808201523060a082015260009060c00160405160208183030381529060405280519060200120905090565b60805250503060c052506200045a565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600060208351101562000215576200020d836200022e565b905062000228565b8162000222848262000318565b5060ff90505b92915050565b600080829050601f815111156200025c578260405163305a27a960e01b8152600401620000d29190620003e4565b8051620002698262000435565b179392505050565b634e487b7160e01b600052604160045260246000fd5b600181811c908216806200029c57607f821691505b602082108103620002bd57634e487b7160e01b600052602260045260246000fd5b50919050565b601f82111562000313576000816000526020600020601f850160051c81016020861015620002ee5750805b601f850160051c820191505b818110156200030f57828155600101620002fa565b5050505b505050565b81516001600160401b0381111562000334576200033462000271565b6200034c8162000345845462000287565b84620002c3565b602080601f8311600181146200038457600084156200036b5750858301515b600019600386901b1c1916600185901b1785556200030f565b600085815260208120601f198616915b82811015620003b55788860151825594840194600190910190840162000394565b5085821015620003d45787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60006020808352835180602085015260005b818110156200041457858101830151858201604001528201620003f6565b506000604082860101526040601f19601f8301168501019250505092915050565b80516020808301519190811015620002bd5760001960209190910360031b1b16919050565b60805160a05160c05160e051610100516101205161014051611147620004b5600039600061093101526000610904015260006107c101526000610799015260006106f40152600061071e0152600061074801526111476000f3fe608060405234801561001057600080fd5b50600436106101215760003560e01c8063715018a6116100ad57806395d89b411161007157806395d89b4114610258578063a9059cbb14610260578063d505accf14610273578063dd62ed3e14610286578063f2fde38b146102bf57600080fd5b8063715018a6146101f457806379cc6790146101fc5780637ecebe001461020f57806384b0196e146102225780638da5cb5b1461023d57600080fd5b8063313ce567116100f4578063313ce5671461018c5780633644e5151461019b57806340c10f19146101a357806342966c68146101b857806370a08231146101cb57600080fd5b806306fdde0314610126578063095ea7b31461014457806318160ddd1461016757806323b872dd14610179575b600080fd5b61012e6102d2565b60405161013b9190610e91565b60405180910390f35b610157610152366004610ec7565b610364565b604051901515815260200161013b565b6002545b60405190815260200161013b565b610157610187366004610ef1565b61037e565b6040516012815260200161013b565b61016b6103a2565b6101b66101b1366004610ec7565b6103b1565b005b6101b66101c6366004610f2d565b6103c7565b61016b6101d9366004610f46565b6001600160a01b031660009081526020819052604090205490565b6101b66103d4565b6101b661020a366004610ec7565b6103e8565b61016b61021d366004610f46565b6103fd565b61022a61041b565b60405161013b9796959493929190610f61565b6005546040516001600160a01b03909116815260200161013b565b61012e610461565b61015761026e366004610ec7565b610470565b6101b6610281366004610ffa565b61047e565b61016b61029436600461106d565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b6101b66102cd366004610f46565b6105bd565b6060600380546102e1906110a0565b80601f016020809104026020016040519081016040528092919081815260200182805461030d906110a0565b801561035a5780601f1061032f5761010080835404028352916020019161035a565b820191906000526020600020905b81548152906001019060200180831161033d57829003601f168201915b5050505050905090565b6000336103728185856105f8565b60019150505b92915050565b60003361038c85828561060a565b610397858585610688565b506001949350505050565b60006103ac6106e7565b905090565b6103b9610812565b6103c3828261083f565b5050565b6103d13382610875565b50565b6103dc610812565b6103e660006108ab565b565b6103f382338361060a565b6103c38282610875565b6001600160a01b038116600090815260086020526040812054610378565b60006060806000806000606061042f6108fd565b61043761092a565b60408051600080825260208201909252600f60f81b9b939a50919850469750309650945092509050565b6060600480546102e1906110a0565b600033610372818585610688565b834211156104a75760405163313c898160e11b8152600481018590526024015b60405180910390fd5b60007f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98888886104f48c6001600160a01b0316600090815260086020526040902080546001810190915590565b6040805160208101969096526001600160a01b0394851690860152929091166060840152608083015260a082015260c0810186905260e001604051602081830303815290604052805190602001209050600061054f82610957565b9050600061055f82878787610984565b9050896001600160a01b0316816001600160a01b0316146105a6576040516325c0072360e11b81526001600160a01b0380831660048301528b16602482015260440161049e565b6105b18a8a8a6105f8565b50505050505050505050565b6105c5610812565b6001600160a01b0381166105ef57604051631e4fbdf760e01b81526000600482015260240161049e565b6103d1816108ab565b61060583838360016109b2565b505050565b6001600160a01b038381166000908152600160209081526040808320938616835292905220546000198114610682578181101561067357604051637dc7a0d960e11b81526001600160a01b0384166004820152602481018290526044810183905260640161049e565b610682848484840360006109b2565b50505050565b6001600160a01b0383166106b257604051634b637e8f60e11b81526000600482015260240161049e565b6001600160a01b0382166106dc5760405163ec442f0560e01b81526000600482015260240161049e565b610605838383610a87565b6000306001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614801561074057507f000000000000000000000000000000000000000000000000000000000000000046145b1561076a57507f000000000000000000000000000000000000000000000000000000000000000090565b6103ac604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201527f0000000000000000000000000000000000000000000000000000000000000000918101919091527f000000000000000000000000000000000000000000000000000000000000000060608201524660808201523060a082015260009060c00160405160208183030381529060405280519060200120905090565b6005546001600160a01b031633146103e65760405163118cdaa760e01b815233600482015260240161049e565b6001600160a01b0382166108695760405163ec442f0560e01b81526000600482015260240161049e565b6103c360008383610a87565b6001600160a01b03821661089f57604051634b637e8f60e11b81526000600482015260240161049e565b6103c382600083610a87565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b60606103ac7f00000000000000000000000000000000000000000000000000000000000000006006610bb1565b60606103ac7f00000000000000000000000000000000000000000000000000000000000000006007610bb1565b60006103786109646106e7565b8360405161190160f01b8152600281019290925260228201526042902090565b60008060008061099688888888610c5c565b9250925092506109a68282610d2b565b50909695505050505050565b6001600160a01b0384166109dc5760405163e602df0560e01b81526000600482015260240161049e565b6001600160a01b038316610a0657604051634a1406b160e11b81526000600482015260240161049e565b6001600160a01b038085166000908152600160209081526040808320938716835292905220829055801561068257826001600160a01b0316846001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92584604051610a7991815260200190565b60405180910390a350505050565b6001600160a01b038316610ab2578060026000828254610aa791906110da565b90915550610b249050565b6001600160a01b03831660009081526020819052604090205481811015610b055760405163391434e360e21b81526001600160a01b0385166004820152602481018290526044810183905260640161049e565b6001600160a01b03841660009081526020819052604090209082900390555b6001600160a01b038216610b4057600280548290039055610b5f565b6001600160a01b03821660009081526020819052604090208054820190555b816001600160a01b0316836001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef83604051610ba491815260200190565b60405180910390a3505050565b606060ff8314610bcb57610bc483610de4565b9050610378565b818054610bd7906110a0565b80601f0160208091040260200160405190810160405280929190818152602001828054610c03906110a0565b8015610c505780601f10610c2557610100808354040283529160200191610c50565b820191906000526020600020905b815481529060010190602001808311610c3357829003601f168201915b50505050509050610378565b600080807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0841115610c975750600091506003905082610d21565b604080516000808252602082018084528a905260ff891692820192909252606081018790526080810186905260019060a0016020604051602081039080840390855afa158015610ceb573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116610d1757506000925060019150829050610d21565b9250600091508190505b9450945094915050565b6000826003811115610d3f57610d3f6110fb565b03610d48575050565b6001826003811115610d5c57610d5c6110fb565b03610d7a5760405163f645eedf60e01b815260040160405180910390fd5b6002826003811115610d8e57610d8e6110fb565b03610daf5760405163fce698f760e01b81526004810182905260240161049e565b6003826003811115610dc357610dc36110fb565b036103c3576040516335e2f38360e21b81526004810182905260240161049e565b60606000610df183610e23565b604080516020808252818301909252919250600091906020820181803683375050509182525060208101929092525090565b600060ff8216601f81111561037857604051632cd44ac360e21b815260040160405180910390fd5b6000815180845260005b81811015610e7157602081850181015186830182015201610e55565b506000602082860101526020601f19601f83011685010191505092915050565b602081526000610ea46020830184610e4b565b9392505050565b80356001600160a01b0381168114610ec257600080fd5b919050565b60008060408385031215610eda57600080fd5b610ee383610eab565b946020939093013593505050565b600080600060608486031215610f0657600080fd5b610f0f84610eab565b9250610f1d60208501610eab565b9150604084013590509250925092565b600060208284031215610f3f57600080fd5b5035919050565b600060208284031215610f5857600080fd5b610ea482610eab565b60ff60f81b881681526000602060e06020840152610f8260e084018a610e4b565b8381036040850152610f94818a610e4b565b606085018990526001600160a01b038816608086015260a0850187905284810360c08601528551808252602080880193509091019060005b81811015610fe857835183529284019291840191600101610fcc565b50909c9b505050505050505050505050565b600080600080600080600060e0888a03121561101557600080fd5b61101e88610eab565b965061102c60208901610eab565b95506040880135945060608801359350608088013560ff8116811461105057600080fd5b9699959850939692959460a0840135945060c09093013592915050565b6000806040838503121561108057600080fd5b61108983610eab565b915061109760208401610eab565b90509250929050565b600181811c908216806110b457607f821691505b6020821081036110d457634e487b7160e01b600052602260045260246000fd5b50919050565b8082018082111561037857634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052602160045260246000fdfea2646970667358221220f1e9d08ff3a77a5dedf27b973e8f3f8da74683e415389a21794cdc5ebb196f9164736f6c63430008170033" + +access(all) let evmBridgeRouterCode = "696d706f727420224e6f6e46756e6769626c65546f6b656e220a696d706f7274202246756e6769626c65546f6b656e220a696d706f72742022466c6f77546f6b656e220a0a696d706f7274202245564d220a0a696d706f7274202249466c6f7745564d4e4654427269646765220a696d706f7274202249466c6f7745564d546f6b656e427269646765220a0a2f2f2f205468697320636f6e747261637420646566696e65732061206d656368616e69736d20666f7220726f7574696e67206272696467652072657175657374732066726f6d207468652045564d20636f6e747261637420746f2074686520466c6f772d45564d206272696467652061732077656c6c0a2f2f2f206173207570646174696e67207468652064657369676e617465642062726964676520616464726573730a2f2f2f0a61636365737328616c6c290a636f6e74726163742045564d427269646765526f75746572207b0a0a202020202f2f2f20456e7469746c656d656e7420616c6c6f77696e6720666f72207570646174657320746f2074686520526f757465720a2020202061636365737328616c6c2920656e7469746c656d656e7420526f7574657241646d696e0a0a202020202f2f2f20456d69747465642069662f7768656e207468652062726964676520636f6e74726163742074686520726f75746572206469726563747320746f20697320757064617465640a2020202061636365737328616c6c29206576656e7420427269646765436f6e74726163745570646174656428616464726573733a20416464726573732c206e616d653a20537472696e67290a202020200a202020202f2f2f204272696467654163636573736f7220696d706c656d656e746174696f6e2075736564206279207468652045564d20636f6e747261637420746f20726f757465206272696467652063616c6c73206265747765656e20564d730a202020202f2f2f0a2020202061636365737328616c6c290a202020207265736f7572636520526f75746572203a2045564d2e4272696467654163636573736f72207b0a20202020202020202f2f2f2041646472657373206f66207468652062726964676520636f6e74726163740a202020202020202061636365737328616c6c292076617220627269646765416464726573733a20416464726573730a20202020202020202f2f2f204e616d65206f66207468652062726964676520636f6e74726163740a202020202020202061636365737328616c6c292076617220627269646765436f6e74726163744e616d653a20537472696e670a0a2020202020202020696e697428616464726573733a20416464726573732c206e616d653a20537472696e6729207b0a20202020202020202020202073656c662e62726964676541646472657373203d20616464726573730a20202020202020202020202073656c662e627269646765436f6e74726163744e616d65203d206e616d650a20202020202020207d0a0a20202020202020202f2f2f2050617373657320616c6f6e672074686520627269646765207265717565737420746f206465646963617465642062726964676520636f6e74726163740a20202020202020202f2f2f0a20202020202020202f2f2f2040706172616d206e66743a20546865204e465420746f206265206272696467656420746f2045564d0a20202020202020202f2f2f2040706172616d20746f3a205468652061646472657373206f66207468652045564d206163636f756e7420746f2072656365697665207468652062726964676564204e46540a20202020202020202f2f2f2040706172616d2066656550726f76696465723a2041207265666572656e636520746f20612046756e6769626c65546f6b656e2050726f76696465722066726f6d20776869636820746865206272696467696e67206665652069732077697468647261776e20696e2024464c4f570a20202020202020202f2f2f0a20202020202020206163636573732845564d2e427269646765290a202020202020202066756e206465706f7369744e4654280a2020202020202020202020206e66743a20407b4e6f6e46756e6769626c65546f6b656e2e4e46547d2c0a202020202020202020202020746f3a2045564d2e45564d416464726573732c0a20202020202020202020202066656550726f76696465723a20617574682846756e6769626c65546f6b656e2e57697468647261772920267b46756e6769626c65546f6b656e2e50726f76696465727d0a202020202020202029207b0a20202020202020202020202073656c662e626f72726f7742726964676528292e6272696467654e4654546f45564d28746f6b656e3a203c2d6e66742c20746f3a20746f2c2066656550726f76696465723a2066656550726f7669646572290a20202020202020207d0a0a20202020202020202f2f2f2050617373657320616c6f6e672074686520627269646765207265717565737420746f20746865206465646963617465642062726964676520636f6e74726163742c2072657475726e696e67207468652062726964676564204e46540a20202020202020202f2f2f0a20202020202020202f2f2f2040706172616d2063616c6c65723a2041207265666572656e636520746f2074686520434f412077686963682063757272656e746c79206f776e7320746865204e465420696e2045564d0a20202020202020202f2f2f2040706172616d20747970653a2054686520436164656e63652074797065206f6620746865204e465420746f20626520627269646765642066726f6d2045564d0a20202020202020202f2f2f2040706172616d2069643a20546865204944206f6620746865204e465420746f20626520627269646765642066726f6d2045564d0a20202020202020202f2f2f2040706172616d2066656550726f76696465723a2041207265666572656e636520746f20612046756e6769626c65546f6b656e2050726f76696465722066726f6d20776869636820746865206272696467696e67206665652069732077697468647261776e20696e2024464c4f570a20202020202020202f2f2f0a20202020202020202f2f2f204072657475726e205468652062726964676564204e46540a20202020202020202f2f2f0a20202020202020206163636573732845564d2e427269646765290a202020202020202066756e2077697468647261774e4654280a20202020202020202020202063616c6c65723a20617574682845564d2e43616c6c29202645564d2e436164656e63654f776e65644163636f756e742c0a202020202020202020202020747970653a20547970652c0a20202020202020202020202069643a2055496e743235362c0a20202020202020202020202066656550726f76696465723a20617574682846756e6769626c65546f6b656e2e57697468647261772920267b46756e6769626c65546f6b656e2e50726f76696465727d0a2020202020202020293a20407b4e6f6e46756e6769626c65546f6b656e2e4e46547d207b0a2020202020202020202020206c657420627269646765203d2073656c662e626f72726f7742726964676528290a2020202020202020202020202f2f20446566696e6520612063616c6c6261636b2066756e6374696f6e2c20656e61626c696e67207468652062726964676520746f20616374206f6e2074686520657068656d6572616c20434f41207265666572656e636520696e2073636f70650a202020202020202020202020766172206578656375746564203d2066616c73650a20202020202020202020202066756e2063616c6c6261636b28293a2045564d2e526573756c74207b0a20202020202020202020202020202020707265207b0a20202020202020202020202020202020202020202165786563757465643a202243616c6c6261636b2063616e206f6e6c79206265206578656375746564206f6e6365220a202020202020202020202020202020207d0a20202020202020202020202020202020706f7374207b0a202020202020202020202020202020202020202065786563757465643a202243616c6c6261636b206d757374206265206578656375746564220a202020202020202020202020202020207d0a202020202020202020202020202020206578656375746564203d20747275650a2020202020202020202020202020202072657475726e2063616c6c65722e63616c6c280a2020202020202020202020202020202020202020746f3a206272696467652e6765744173736f63696174656445564d4164647265737328776974683a2074797065290a2020202020202020202020202020202020202020202020203f3f2070616e696328224e6f2045564d2061646472657373206173736f6369617465642077697468207479706522292c0a2020202020202020202020202020202020202020646174613a2045564d2e656e636f6465414249576974685369676e6174757265280a20202020202020202020202020202020202020202020202022736166655472616e7366657246726f6d28616464726573732c616464726573732c75696e7432353629222c0a2020202020202020202020202020202020202020202020205b63616c6c65722e6164647265737328292c206272696467652e676574427269646765434f4145564d4164647265737328292c2069645d0a2020202020202020202020202020202020202020292c0a20202020202020202020202020202020202020206761734c696d69743a2031353030303030302c0a202020202020202020202020202020202020202076616c75653a2045564d2e42616c616e6365286174746f666c6f773a2030290a20202020202020202020202020202020290a2020202020202020202020207d0a2020202020202020202020202f2f2045786563757465207468652062726964676520726571756573740a20202020202020202020202072657475726e203c2d206272696467652e6272696467654e465446726f6d45564d280a202020202020202020202020202020206f776e65723a2063616c6c65722e6164647265737328292c0a20202020202020202020202020202020747970653a20747970652c0a2020202020202020202020202020202069643a2069642c0a2020202020202020202020202020202066656550726f76696465723a2066656550726f76696465722c0a2020202020202020202020202020202070726f7465637465645472616e7366657243616c6c3a2063616c6c6261636b0a202020202020202020202020290a20202020202020207d0a0a20202020202020202f2f2f2050617373657320616c6f6e672074686520627269646765207265717565737420746f206465646963617465642062726964676520636f6e74726163740a20202020202020202f2f2f0a20202020202020202f2f2f2040706172616d207661756c743a205468652066756e6769626c6520746f6b656e207661756c7420746f206265206272696467656420746f2045564d0a20202020202020202f2f2f2040706172616d20746f3a205468652061646472657373206f66207468652045564d206163636f756e7420746f207265636569766520746865206272696467656420746f6b656e730a20202020202020202f2f2f2040706172616d2066656550726f76696465723a2041207265666572656e636520746f20612046756e6769626c65546f6b656e2050726f76696465722066726f6d20776869636820746865206272696467696e67206665652069732077697468647261776e20696e2024464c4f570a20202020202020202f2f2f0a20202020202020206163636573732845564d2e427269646765290a202020202020202066756e206465706f736974546f6b656e73280a2020202020202020202020207661756c743a20407b46756e6769626c65546f6b656e2e5661756c747d2c0a202020202020202020202020746f3a2045564d2e45564d416464726573732c0a20202020202020202020202066656550726f76696465723a20617574682846756e6769626c65546f6b656e2e57697468647261772920267b46756e6769626c65546f6b656e2e50726f76696465727d0a202020202020202029207b0a20202020202020202020202073656c662e626f72726f7742726964676528292e627269646765546f6b656e73546f45564d287661756c743a203c2d7661756c742c20746f3a20746f2c2066656550726f76696465723a2066656550726f7669646572290a20202020202020207d0a0a20202020202020202f2f2f2050617373657320616c6f6e672074686520627269646765207265717565737420746f20746865206465646963617465642062726964676520636f6e74726163742c2072657475726e696e67207468652062726964676564204e46540a20202020202020202f2f2f0a20202020202020202f2f2f2040706172616d2063616c6c65723a2041207265666572656e636520746f2074686520434f412077686963682063757272656e746c79206f776e732074686520746f6b656e7320696e2045564d0a20202020202020202f2f2f2040706172616d20747970653a2054686520436164656e63652074797065206f66207468652066756e6769626c6520746f6b656e207661756c7420746f20626520627269646765642066726f6d2045564d0a20202020202020202f2f2f2040706172616d20616d6f756e743a2054686520616d6f756e74206f6620746f6b656e7320746f20626520627269646765640a20202020202020202f2f2f2040706172616d2066656550726f76696465723a2041207265666572656e636520746f20612046756e6769626c65546f6b656e2050726f76696465722066726f6d20776869636820746865206272696467696e67206665652069732077697468647261776e20696e2024464c4f570a20202020202020202f2f2f0a20202020202020202f2f2f204072657475726e205468652062726964676564204e46540a20202020202020202f2f2f0a20202020202020206163636573732845564d2e427269646765290a202020202020202066756e207769746864726177546f6b656e73280a20202020202020202020202063616c6c65723a20617574682845564d2e43616c6c29202645564d2e436164656e63654f776e65644163636f756e742c0a202020202020202020202020747970653a20547970652c0a202020202020202020202020616d6f756e743a2055496e743235362c0a20202020202020202020202066656550726f76696465723a20617574682846756e6769626c65546f6b656e2e57697468647261772920267b46756e6769626c65546f6b656e2e50726f76696465727d0a2020202020202020293a20407b46756e6769626c65546f6b656e2e5661756c747d207b0a2020202020202020202020206c657420627269646765203d2073656c662e626f72726f7742726964676528290a2020202020202020202020202f2f20446566696e6520612063616c6c6261636b2066756e6374696f6e2c20656e61626c696e67207468652062726964676520746f20616374206f6e2074686520657068656d6572616c20434f41207265666572656e636520696e2073636f70650a202020202020202020202020766172206578656375746564203d2066616c73650a20202020202020202020202066756e2063616c6c6261636b28293a2045564d2e526573756c74207b0a20202020202020202020202020202020707265207b0a20202020202020202020202020202020202020202165786563757465643a202243616c6c6261636b2063616e206f6e6c79206265206578656375746564206f6e6365220a202020202020202020202020202020207d0a20202020202020202020202020202020706f7374207b0a202020202020202020202020202020202020202065786563757465643a202243616c6c6261636b206d757374206265206578656375746564220a202020202020202020202020202020207d0a202020202020202020202020202020206578656375746564203d20747275650a2020202020202020202020202020202072657475726e2063616c6c65722e63616c6c280a2020202020202020202020202020202020202020746f3a206272696467652e6765744173736f63696174656445564d4164647265737328776974683a2074797065290a2020202020202020202020202020202020202020202020203f3f2070616e696328224e6f2045564d2061646472657373206173736f6369617465642077697468207479706522292c0a2020202020202020202020202020202020202020646174613a2045564d2e656e636f6465414249576974685369676e6174757265280a202020202020202020202020202020202020202020202020227472616e7366657228616464726573732c75696e7432353629222c0a2020202020202020202020202020202020202020202020205b6272696467652e676574427269646765434f4145564d4164647265737328292c20616d6f756e745d0a2020202020202020202020202020202020202020292c0a20202020202020202020202020202020202020206761734c696d69743a2031353030303030302c0a202020202020202020202020202020202020202076616c75653a2045564d2e42616c616e6365286174746f666c6f773a2030290a20202020202020202020202020202020290a2020202020202020202020207d0a2020202020202020202020202f2f2045786563757465207468652062726964676520726571756573740a20202020202020202020202072657475726e203c2d206272696467652e627269646765546f6b656e7346726f6d45564d280a202020202020202020202020202020206f776e65723a2063616c6c65722e6164647265737328292c0a20202020202020202020202020202020747970653a20747970652c0a20202020202020202020202020202020616d6f756e743a20616d6f756e742c0a2020202020202020202020202020202066656550726f76696465723a2066656550726f76696465722c0a2020202020202020202020202020202070726f7465637465645472616e7366657243616c6c3a2063616c6c6261636b0a202020202020202020202020290a20202020202020207d0a0a20202020202020202f2f2f2053657473207468652062726964676520636f6e74726163742074686520726f75746572206469726563747320627269646765207265717565737473207468726f7567680a20202020202020202f2f2f0a202020202020202061636365737328526f7574657241646d696e292066756e20736574427269646765436f6e747261637428616464726573733a20416464726573732c206e616d653a20537472696e6729207b0a20202020202020202020202073656c662e62726964676541646472657373203d20616464726573730a20202020202020202020202073656c662e627269646765436f6e74726163744e616d65203d206e616d650a202020202020202020202020656d697420427269646765436f6e74726163745570646174656428616464726573733a20616464726573732c206e616d653a206e616d65290a20202020202020207d0a0a20202020202020202f2f2f2052657475726e732061207265666572656e636520746f207468652062726964676520636f6e74726163740a20202020202020202f2f2f0a20202020202020206163636573732873656c66292066756e20626f72726f7742726964676528293a20267b49466c6f7745564d4e46544272696467652c2049466c6f7745564d546f6b656e4272696467657d207b0a20202020202020202020202072657475726e206765744163636f756e742873656c662e62726964676541646472657373292e636f6e7472616374732e626f72726f773c267b49466c6f7745564d4e46544272696467652c2049466c6f7745564d546f6b656e4272696467657d3e280a20202020202020202020202020202020202020206e616d653a2073656c662e627269646765436f6e74726163744e616d650a2020202020202020202020202020202029203f3f2070616e6963282242726964676520636f6e7472616374206e6f7420666f756e6422290a20202020202020207d0a202020207d0a0a20202020696e697428627269646765416464726573733a20416464726573732c20627269646765436f6e74726163744e616d653a20537472696e6729207b0a202020202020202073656c662e6163636f756e742e73746f726167652e73617665280a2020202020202020202020203c2d63726561746520526f7574657228616464726573733a20627269646765416464726573732c206e616d653a20627269646765436f6e74726163744e616d65292c0a202020202020202020202020746f3a202f73746f726167652f65766d427269646765526f757465720a2020202020202020290a202020207d0a7d0a" access(all) let bridgedNFTCodeChunks = [ - "696d706f7274204e6f6e46756e6769626c65546f6b656e2066726f6d203078303030303030303030303030303030310a696d706f7274204d6574616461746156696577732066726f6d203078303030303030303030303030303030310a696d706f727420566965775265736f6c7665722066726f6d203078303030303030303030303030303030310a696d706f72742046756e6769626c65546f6b656e2066726f6d203078303030303030303030303030303030320a696d706f727420466c6f77546f6b656e2066726f6d203078303030303030303030303030303030330a0a696d706f72742045564d2066726f6d203078303030303030303030303030303030310a0a696d706f7274204943726f7373564d2066726f6d203078303030303030303030303030303030370a696d706f7274204945564d4272696467654e46544d696e7465722066726f6d203078303030303030303030303030303030370a696d706f727420466c6f7745564d4272696467654e4654457363726f772066726f6d203078303030303030303030303030303030370a696d706f727420466c6f7745564d427269646765436f6e6669672066726f6d203078303030303030303030303030303030370a696d706f727420466c6f7745564d4272696467655574696c732066726f6d203078303030303030303030303030303030370a696d706f727420466c6f7745564d4272696467652066726f6d203078303030303030303030303030303030370a696d706f72742043726f7373564d4e46542066726f6d203078303030303030303030303030303030370a0a2f2f2f205468697320636f6e747261637420697320612074656d706c617465207573656420627920466c6f7745564d42726964676520746f20646566696e652045564d2d6e6174697665204e46547320627269646765642066726f6d20466c6f772045564d20746f20466c6f772e0a2f2f2f2055706f6e206465706c6f796d656e74206f66207468697320636f6e74726163742c2074686520636f6e7472616374206e616d65206973206465726976656420617320612066756e6374696f6e206f6620746865206173736574207479706520286865726520616e2045524337323120616b610a2f2f2f20616e204e46542920616e642074686520636f6e747261637427732045564d20616464726573732e20546865206465726976656420636f6e7472616374206e616d65206973207468656e206a6f696e65642077697468207468697320636f6e7472616374277320636f64652c0a2f2f2f207072657061726564206173206368756e6b7320696e20466c6f7745564d42726964676554656d706c61746573206265666f7265206265696e67206465706c6f79656420746f2074686520466c6f772045564d20427269646765206163636f756e742e0a2f2f2f0a2f2f2f204f6e206272696467696e672c2074686520455243373231206973207472616e7366657272656420746f2074686520627269646765277320436164656e63654f776e65644163636f756e742045564d206164647265737320616e642061206e6577204e4654206973206d696e7465642066726f6d0a2f2f2f207468697320636f6e747261637420746f20746865206272696467696e672063616c6c65722e204f6e2072657475726e20746f20466c6f772045564d2c2074686520726576657273652070726f6365737320697320666f6c6c6f776564202d2074686520746f6b656e206973206275726e65640a2f2f2f20696e207468697320636f6e747261637420616e642074686520455243373231206973207472616e7366657272656420746f2074686520646566696e656420726563697069656e742e20496e2074686973207761792c2074686520436164656e636520746f6b656e206163747320617320610a2f2f2f20726570726573656e746174696f6e206f6620626f7468207468652045564d204e465420616e642074687573206f776e6572736869702072696768747320746f2069742075706f6e206272696467696e67206261636b20746f20466c6f772045564d2e0a2f2f2f0a2f2f2f20546f20627269646765206265747765656e20564d732c20612063616c6c65722063616e20656974686572207573652074686520636f6e7472616374206d6574686f647320646566696e65642062656c6f772c206f72207573652074686520466c6f7745564d42726964676527730a2f2f2f206272696467696e67206d6574686f64732077686963682077696c6c2070726f6772616d61746963616c6c7920726f757465206272696467696e672063616c6c7320746f207468697320636f6e74726163742e0a2f2f2f0a2f2f20544f444f3a20496d706c656d656e74204e465420636f6e747261637420696e74657266616365206f6e636520763220617661696c61626c65206c6f63616c6c790a61636365737328616c6c2920636f6e747261637420", - "203a204943726f7373564d2c204945564d4272696467654e46544d696e7465722c204e6f6e46756e6769626c65546f6b656e207b0a0a202020202f2f2f20506f696e74657220746f2074686520466163746f7279206465706c6f79656420536f6c696469747920636f6e7472616374206164647265737320646566696e696e672074686520627269646765642061737365740a2020202061636365737328616c6c29206c65742065766d4e4654436f6e7472616374416464726573733a2045564d2e45564d416464726573730a202020202f2f2f204e616d65206f6620746865204e465420636f6c6c656374696f6e20646566696e656420696e2074686520636f72726573706f6e64696e672045524337323120636f6e74726163740a2020202061636365737328616c6c29206c6574206e616d653a20537472696e670a202020202f2f2f2053796d626f6c206f6620746865204e465420636f6c6c656374696f6e20646566696e656420696e2074686520636f72726573706f6e64696e672045524337323120636f6e74726163740a2020202061636365737328616c6c29206c65742073796d626f6c3a20537472696e670a202020202f2f2f20555249206f662074686520636f6e74726163742c20696620617661696c61626c6520617320612076617220696e2063617365207468652062726964676520656e61626c65732063726f73732d564d204d657461646174612073796e63696e6720696e20746865206675747572650a2020202061636365737328616c6c292076617220636f6e74726163745552493a20537472696e673f0a202020202f2f2f2052657461696e206120436f6c6c656374696f6e20746f207265666572656e6365207768656e207265736f6c76696e6720436f6c6c656374696f6e204d657461646174610a202020206163636573732873656c6629206c657420636f6c6c656374696f6e3a2040436f6c6c656374696f6e0a202020202f2f2f204d617070696e67206f6620746f6b656e205552497320696e6465786564206f6e207468656972204552433732312049442e205468697320776f756c64206e6f74206e6f726d616c6c792062652072657461696e65642077697468696e206120436164656e6365204e46540a202020202f2f2f20636f6e74726163742c206275742073696e6365204e4654206d65746164617461206d6179206265207570646174656420696e2045564d2c20697427732072657461696e6564206865726520736f207468617420746865206272696467652063616e207570646174650a202020202f2f2f20697420616761696e73742074686520736f757263652045524337323120636f6e7472616374207768696368206973207472656174656420617320746865204e4654277320736f75726365206f662074727574682e0a2020202061636365737328616c6c29206c657420746f6b656e555249733a207b55496e743235363a20537472696e677d0a0a202020202f2f2f20546865204e4654207265736f7572636520726570726573656e74696e672074686520627269646765642045524337323120746f6b656e0a202020202f2f2f0a2020202061636365737328616c6c29207265736f75726365204e46543a2043726f7373564d4e46542e45564d4e4654207b0a20202020202020202f2f2f2054686520436164656e6365204944206f6620746865204e46540a202020202020202061636365737328616c6c29206c65742069643a2055496e7436340a20202020202020202f2f2f2054686520455243373231204944206f6620746865204e46540a202020202020202061636365737328616c6c29206c65742065766d49443a2055496e743235360a20202020202020202f2f2f20546865206e616d65206f6620746865204e465420617320646566696e656420696e207468652045524337323120636f6e74726163740a202020202020202061636365737328616c6c29206c6574206e616d653a20537472696e670a20202020202020202f2f2f205468652073796d626f6c206f6620746865204e465420617320646566696e656420696e207468652045524337323120636f6e74726163740a202020202020202061636365737328616c6c29206c65742073796d626f6c3a20537472696e670a20202020202020202f2f2f204164646974696f6e616c206f6e636861696e206d657461646174610a202020202020202061636365737328616c6c29206c6574206d657461646174613a207b537472696e673a20416e795374727563747d0a0a2020202020202020696e6974280a2020202020202020202020206e616d653a20537472696e672c0a20202020202020202020202073796d626f6c3a20537472696e672c0a20202020202020202020202065766d49443a2055496e743235362c0a2020202020202020202020206d657461646174613a207b537472696e673a20416e795374727563747d0a202020202020202029207b0a20202020202020202020202073656c662e6e616d65203d206e616d650a20202020202020202020202073656c662e73796d626f6c203d2073796d626f6c0a20202020202020202020202073656c662e6964203d2073656c662e757569640a20202020202020202020202073656c662e65766d4944203d2065766d49440a20202020202020202020202073656c662e6d65746164617461203d206d657461646174610a20202020202020207d0a0a20202020202020202f2f2f2052657475726e7320746865206d65746164617461207669657720747970657320737570706f727465642062792074686973204e46540a202020202020202061636365737328616c6c2920766965772066756e20676574566965777328293a205b547970655d207b0a20202020202020202020202072657475726e205b0a20202020202020202020202020202020547970653c43726f7373564d4e46542e45564d427269646765644d657461646174613e28292c0a20202020202020202020202020202020547970653c4d6574616461746156696577732e53657269616c3e28292c0a20202020202020202020202020202020547970653c4d6574616461746156696577732e4e4654436f6c6c656374696f6e446174613e28292c0a20202020202020202020202020202020547970653c4d6574616461746156696577732e4e4654436f6c6c656374696f6e446973706c61793e28290a2020202020202020202020205d0a20202020202020207d0a0a20202020202020202f2f2f205265736f6c7665732061206d65746164617461207669657720666f722074686973204e46540a202020202020202061636365737328616c6c292066756e207265736f6c766556696577285f20766965773a2054797065293a20416e795374727563743f207b0a2020202020202020202020207377697463682076696577207b0a202020202020202020202020202020202f2f20576520646f6e2774206b6e6f772077686174206b696e64206f662066696c65207468652055524920726570726573656e747320284950465320762048545450292c20736f2077652063616e2774207265736f6c766520446973706c617920766965770a202020202020202020202020202020202f2f20776974682074686520555249206173207468756d626e61696c202d207765206d61792061206e6577207374616e64617264207669657720666f722045564d204e465473202d207468697320697320696e746572696d0a202020202020202020202020202020206361736520547970653c43726f7373564d4e46542e45564d427269646765644d657461646174613e28293a0a202020202020202020202020202020202020202072657475726e2043726f7373564d4e46542e45564d427269646765644d65746164617461280a2020202020202020202020202020202020202020202020206e616d653a2073656c662e6e616d652c0a20202020202020202020202020202020202020202020202073796d626f6c3a2073656c662e73796d626f6c2c0a2020202020202020202020202020202020202020202020207572693a2043726f7373564d4e46542e55524928626173655552493a206e696c2c2076616c75653a2073656c662e746f6b656e5552492829290a2020202020202020202020202020202020202020290a202020202020202020202020202020206361736520547970653c4d6574616461746156696577732e53657269616c3e28293a0a202020202020202020202020202020202020202072657475726e204d6574616461746156696577732e53657269616c280a20202020202020202020202020202020202020202020202073656c662e69640a2020202020202020202020202020202020202020290a202020202020202020202020202020206361736520547970653c4d6574616461746156696577732e4e4654436f6c6c656374696f6e446174613e28293a0a202020202020202020202020202020202020202072657475726e20", + "696d706f7274204e6f6e46756e6769626c65546f6b656e2066726f6d203078303030303030303030303030303030310a696d706f7274204d6574616461746156696577732066726f6d203078303030303030303030303030303030310a696d706f727420566965775265736f6c7665722066726f6d203078303030303030303030303030303030310a696d706f72742046756e6769626c65546f6b656e2066726f6d203078303030303030303030303030303030320a696d706f727420466c6f77546f6b656e2066726f6d203078303030303030303030303030303030330a0a696d706f72742045564d2066726f6d203078303030303030303030303030303030310a0a696d706f7274204943726f7373564d2066726f6d203078303030303030303030303030303030370a696d706f7274204945564d4272696467654e46544d696e7465722066726f6d203078303030303030303030303030303030370a696d706f727420466c6f7745564d4272696467654e4654457363726f772066726f6d203078303030303030303030303030303030370a696d706f727420466c6f7745564d427269646765436f6e6669672066726f6d203078303030303030303030303030303030370a696d706f727420466c6f7745564d4272696467655574696c732066726f6d203078303030303030303030303030303030370a696d706f727420466c6f7745564d4272696467652066726f6d203078303030303030303030303030303030370a696d706f72742043726f7373564d4e46542066726f6d203078303030303030303030303030303030370a0a2f2f2f205468697320636f6e747261637420697320612074656d706c617465207573656420627920466c6f7745564d42726964676520746f20646566696e652045564d2d6e6174697665204e46547320627269646765642066726f6d20466c6f772045564d20746f20466c6f772e0a2f2f2f2055706f6e206465706c6f796d656e74206f66207468697320636f6e74726163742c2074686520636f6e7472616374206e616d65206973206465726976656420617320612066756e6374696f6e206f6620746865206173736574207479706520286865726520616e2045524337323120616b610a2f2f2f20616e204e46542920616e642074686520636f6e747261637427732045564d20616464726573732e20546865206465726976656420636f6e7472616374206e616d65206973207468656e206a6f696e65642077697468207468697320636f6e7472616374277320636f64652c0a2f2f2f207072657061726564206173206368756e6b7320696e20466c6f7745564d42726964676554656d706c61746573206265666f7265206265696e67206465706c6f79656420746f2074686520466c6f772045564d20427269646765206163636f756e742e0a2f2f2f0a2f2f2f204f6e206272696467696e672c2074686520455243373231206973207472616e7366657272656420746f2074686520627269646765277320436164656e63654f776e65644163636f756e742045564d206164647265737320616e642061206e6577204e4654206973206d696e7465642066726f6d0a2f2f2f207468697320636f6e747261637420746f20746865206272696467696e672063616c6c65722e204f6e2072657475726e20746f20466c6f772045564d2c2074686520726576657273652070726f6365737320697320666f6c6c6f776564202d2074686520746f6b656e206973206275726e65640a2f2f2f20696e207468697320636f6e747261637420616e642074686520455243373231206973207472616e7366657272656420746f2074686520646566696e656420726563697069656e742e20496e2074686973207761792c2074686520436164656e636520746f6b656e206163747320617320610a2f2f2f20726570726573656e746174696f6e206f6620626f7468207468652045564d204e465420616e642074687573206f776e6572736869702072696768747320746f2069742075706f6e206272696467696e67206261636b20746f20466c6f772045564d2e0a2f2f2f0a2f2f2f20546f20627269646765206265747765656e20564d732c20612063616c6c65722063616e20656974686572207573652074686520636f6e7472616374206d6574686f647320646566696e65642062656c6f772c206f72207573652074686520466c6f7745564d42726964676527730a2f2f2f206272696467696e67206d6574686f64732077686963682077696c6c2070726f6772616d61746963616c6c7920726f757465206272696467696e672063616c6c7320746f207468697320636f6e74726163742e0a2f2f2f0a61636365737328616c6c2920636f6e747261637420", + "203a204943726f7373564d2c204945564d4272696467654e46544d696e7465722c204e6f6e46756e6769626c65546f6b656e207b0a0a202020202f2f2f20506f696e74657220746f2074686520466163746f7279206465706c6f79656420536f6c696469747920636f6e7472616374206164647265737320646566696e696e672074686520627269646765642061737365740a2020202061636365737328616c6c29206c65742065766d4e4654436f6e7472616374416464726573733a2045564d2e45564d416464726573730a202020202f2f2f204e616d65206f6620746865204e465420636f6c6c656374696f6e20646566696e656420696e2074686520636f72726573706f6e64696e672045524337323120636f6e74726163740a2020202061636365737328616c6c29206c6574206e616d653a20537472696e670a202020202f2f2f2053796d626f6c206f6620746865204e465420636f6c6c656374696f6e20646566696e656420696e2074686520636f72726573706f6e64696e672045524337323120636f6e74726163740a2020202061636365737328616c6c29206c65742073796d626f6c3a20537472696e670a202020202f2f2f20555249206f662074686520636f6e74726163742c20696620617661696c61626c6520617320612076617220696e2063617365207468652062726964676520656e61626c65732063726f73732d564d204d657461646174612073796e63696e6720696e20746865206675747572650a2020202061636365737328616c6c292076617220636f6e74726163745552493a20537472696e673f0a202020202f2f2f2052657461696e206120436f6c6c656374696f6e20746f207265666572656e6365207768656e207265736f6c76696e6720436f6c6c656374696f6e204d657461646174610a202020206163636573732873656c6629206c657420636f6c6c656374696f6e3a2040436f6c6c656374696f6e0a202020202f2f2f204d617070696e67206f6620746f6b656e205552497320696e6465786564206f6e207468656972204552433732312049442e205468697320776f756c64206e6f74206e6f726d616c6c792062652072657461696e65642077697468696e206120436164656e6365204e46540a202020202f2f2f20636f6e74726163742c206275742073696e6365204e4654206d65746164617461206d6179206265207570646174656420696e2045564d2c20697427732072657461696e6564206865726520736f207468617420746865206272696467652063616e207570646174650a202020202f2f2f20697420616761696e73742074686520736f757263652045524337323120636f6e7472616374207768696368206973207472656174656420617320746865204e4654277320736f75726365206f662074727574682e0a2020202061636365737328616c6c29206c657420746f6b656e555249733a207b55496e743235363a20537472696e677d0a0a202020202f2f2f20546865204e4654207265736f7572636520726570726573656e74696e672074686520627269646765642045524337323120746f6b656e0a202020202f2f2f0a2020202061636365737328616c6c29207265736f75726365204e4654203a2043726f7373564d4e46542e45564d4e4654207b0a20202020202020202f2f2f2054686520436164656e6365204944206f6620746865204e46540a202020202020202061636365737328616c6c29206c65742069643a2055496e7436340a20202020202020202f2f2f2054686520455243373231204944206f6620746865204e46540a202020202020202061636365737328616c6c29206c65742065766d49443a2055496e743235360a20202020202020202f2f2f204164646974696f6e616c206f6e636861696e206d657461646174610a202020202020202061636365737328616c6c29206c6574206d657461646174613a207b537472696e673a20416e795374727563747d0a0a2020202020202020696e6974280a20202020202020202020202065766d49443a2055496e743235362c0a2020202020202020202020206d657461646174613a207b537472696e673a20416e795374727563747d0a202020202020202029207b0a20202020202020202020202073656c662e6964203d2073656c662e757569640a20202020202020202020202073656c662e65766d4944203d2065766d49440a20202020202020202020202073656c662e6d65746164617461203d206d657461646174610a20202020202020207d0a0a20202020202020202f2f2f2052657475726e7320746865206d65746164617461207669657720747970657320737570706f727465642062792074686973204e46540a202020202020202061636365737328616c6c2920766965772066756e20676574566965777328293a205b547970655d207b0a20202020202020202020202072657475726e205b0a20202020202020202020202020202020547970653c43726f7373564d4e46542e45564d427269646765644d657461646174613e28292c0a20202020202020202020202020202020547970653c4d6574616461746156696577732e53657269616c3e28292c0a20202020202020202020202020202020547970653c4d6574616461746156696577732e4e4654436f6c6c656374696f6e446174613e28292c0a20202020202020202020202020202020547970653c4d6574616461746156696577732e4e4654436f6c6c656374696f6e446973706c61793e28290a2020202020202020202020205d0a20202020202020207d0a0a202020202020202061636365737328616c6c2920766965772066756e206765744e616d6528293a20537472696e67207b0a20202020202020202020202072657475726e20", + "2e6e616d650a20202020202020207d0a0a202020202020202061636365737328616c6c2920766965772066756e2067657453796d626f6c28293a20537472696e67207b0a20202020202020202020202072657475726e20", + "2e73796d626f6c0a20202020202020207d0a0a202020202020202061636365737328616c6c2920766965772066756e20746f6b656e55524928293a20537472696e67207b0a20202020202020202020202072657475726e20", + "2e746f6b656e555249735b73656c662e65766d49445d203f3f2022220a20202020202020207d0a0a20202020202020202f2f2f205265736f6c7665732061206d65746164617461207669657720666f722074686973204e46540a202020202020202061636365737328616c6c292066756e207265736f6c766556696577285f20766965773a2054797065293a20416e795374727563743f207b0a2020202020202020202020207377697463682076696577207b0a202020202020202020202020202020202f2f20576520646f6e2774206b6e6f772077686174206b696e64206f662066696c65207468652055524920726570726573656e747320284950465320762048545450292c20736f2077652063616e2774207265736f6c766520446973706c617920766965770a202020202020202020202020202020202f2f20776974682074686520555249206173207468756d626e61696c202d207765206d61792061206e6577207374616e64617264207669657720666f722045564d204e465473202d207468697320697320696e746572696d0a202020202020202020202020202020206361736520547970653c43726f7373564d4e46542e45564d427269646765644d657461646174613e28293a0a202020202020202020202020202020202020202072657475726e2043726f7373564d4e46542e45564d427269646765644d65746164617461280a2020202020202020202020202020202020202020202020206e616d653a2073656c662e6765744e616d6528292c0a20202020202020202020202020202020202020202020202073796d626f6c3a2073656c662e67657453796d626f6c28292c0a2020202020202020202020202020202020202020202020207572693a2043726f7373564d4e46542e55524928626173655552493a206e696c2c2076616c75653a2073656c662e746f6b656e5552492829290a2020202020202020202020202020202020202020290a202020202020202020202020202020206361736520547970653c4d6574616461746156696577732e53657269616c3e28293a0a202020202020202020202020202020202020202072657475726e204d6574616461746156696577732e53657269616c280a20202020202020202020202020202020202020202020202073656c662e69640a2020202020202020202020202020202020202020290a202020202020202020202020202020206361736520547970653c4d6574616461746156696577732e4e4654436f6c6c656374696f6e446174613e28293a0a202020202020202020202020202020202020202072657475726e20", "2e7265736f6c7665436f6e747261637456696577280a2020202020202020202020202020202020202020202020207265736f75726365547970653a2073656c662e6765745479706528292c0a20202020202020202020202020202020202020202020202076696577547970653a20547970653c4d6574616461746156696577732e4e4654436f6c6c656374696f6e446174613e28290a2020202020202020202020202020202020202020290a202020202020202020202020202020206361736520547970653c4d6574616461746156696577732e4e4654436f6c6c656374696f6e446973706c61793e28293a0a202020202020202020202020202020202020202072657475726e20", "2e7265736f6c7665436f6e747261637456696577280a2020202020202020202020202020202020202020202020207265736f75726365547970653a2073656c662e6765745479706528292c0a20202020202020202020202020202020202020202020202076696577547970653a20547970653c4d6574616461746156696577732e4e4654436f6c6c656374696f6e446973706c61793e28290a2020202020202020202020202020202020202020290a2020202020202020202020207d0a20202020202020202020202072657475726e206e696c0a20202020202020207d0a0a20202020202020202f2f2f207075626c69632066756e6374696f6e207468617420616e796f6e652063616e2063616c6c20746f206372656174652061206e657720656d70747920636f6c6c656374696f6e0a202020202020202061636365737328616c6c292066756e20637265617465456d707479436f6c6c656374696f6e28293a20407b4e6f6e46756e6769626c65546f6b656e2e436f6c6c656374696f6e7d207b0a20202020202020202020202072657475726e203c2d20", "2e637265617465456d707479436f6c6c656374696f6e286e6674547970653a2073656c662e676574547970652829290a20202020202020207d0a0a20202020202020202f2a202d2d2d2043726f7373564d4e465420636f6e666f726d616e6365202d2d2d202a2f0a20202020202020202f2f0a20202020202020202f2f2f2052657475726e73207468652045564d20636f6e74726163742061646472657373206f6620746865204e46540a202020202020202061636365737328616c6c2920766965772066756e2067657445564d436f6e74726163744164647265737328293a2045564d2e45564d41646472657373207b0a20202020202020202020202072657475726e20", - "2e67657445564d436f6e74726163744164647265737328290a20202020202020207d0a0a20202020202020202f2f2f2053696d696c617220746f204552433732312e746f6b656e555249206d6574686f642c2072657475726e732074686520555249206f6620746865204e465420776974682073656c662e65766d49442061742074696d65206f66206272696467696e670a202020202020202061636365737328616c6c2920766965772066756e20746f6b656e55524928293a20537472696e67207b0a20202020202020202020202072657475726e20", - "2e746f6b656e555249735b73656c662e65766d49445d203f3f2022220a20202020202020207d0a202020207d0a0a202020202f2f2f2054686973207265736f7572636520686f6c6473206173736f636961746564204e4654732c20616e642073657276657320717565726965732061626f75742073746f726564204e4654730a2020202061636365737328616c6c29207265736f7572636520436f6c6c656374696f6e3a204e6f6e46756e6769626c65546f6b656e2e436f6c6c656374696f6e2c2043726f7373564d4e46542e45564d4e4654436f6c6c656374696f6e207b0a20202020202020202f2f2f2064696374696f6e617279206f66204e465420636f6e666f726d696e6720746f6b656e7320696e6465786564206f6e2074686569722049440a202020202020202061636365737328636f6e74726163742920766172206f776e65644e4654733a20407b55496e7436343a20", + "2e67657445564d436f6e74726163744164647265737328290a20202020202020207d0a202020207d0a0a202020202f2f2f2054686973207265736f7572636520686f6c6473206173736f636961746564204e4654732c20616e642073657276657320717565726965732061626f75742073746f726564204e4654730a2020202061636365737328616c6c29207265736f7572636520436f6c6c656374696f6e203a2043726f7373564d4e46542e45564d4e4654436f6c6c656374696f6e207b0a20202020202020202f2f2f2064696374696f6e617279206f66204e465420636f6e666f726d696e6720746f6b656e7320696e6465786564206f6e2074686569722049440a202020202020202061636365737328636f6e74726163742920766172206f776e65644e4654733a20407b55496e7436343a20", "2e4e46547d0a20202020202020202f2f2f204d617070696e67206f662045564d2049447320746f20466c6f77204e4654204944730a202020202020202061636365737328636f6e747261637429206c65742065766d4944546f466c6f7749443a207b55496e743235363a2055496e7436347d0a0a202020202020202061636365737328616c6c29207661722073746f72616765506174683a2053746f72616765506174680a202020202020202061636365737328616c6c2920766172207075626c6963506174683a205075626c6963506174680a0a2020202020202020696e6974202829207b0a20202020202020202020202073656c662e6f776e65644e465473203c2d207b7d0a20202020202020202020202073656c662e65766d4944546f466c6f774944203d207b7d0a2020202020202020202020206c657420636f6c6c656374696f6e44617461203d20", "2e7265736f6c7665436f6e747261637456696577280a20202020202020202020202020202020202020207265736f75726365547970653a20547970653c40", - "2e4e46543e28292c0a202020202020202020202020202020202020202076696577547970653a20547970653c4d6574616461746156696577732e4e4654436f6c6c656374696f6e446174613e28290a202020202020202020202020202020202920617321204d6574616461746156696577732e4e4654436f6c6c656374696f6e446174613f0a202020202020202020202020202020203f3f2070616e69632822436f756c64206e6f74207265736f6c76652074686520636f6c6c656374696f6e2064617461207669657720666f7220746865204e465420636f6c6c656374696f6e22290a20202020202020202020202073656c662e73746f7261676550617468203d20636f6c6c656374696f6e446174612e73746f72616765506174680a20202020202020202020202073656c662e7075626c696350617468203d20636f6c6c656374696f6e446174612e7075626c6963506174680a20202020202020207d0a0a20202020202020202f2f2f2052657475726e732061206c697374206f66204e46542074797065732074686174207468697320726563656976657220616363657074730a202020202020202061636365737328616c6c2920766965772066756e20676574537570706f727465644e4654547970657328293a207b547970653a20426f6f6c7d207b0a20202020202020202020202072657475726e207b20547970653c40", + "2e4e46543e28292c0a202020202020202020202020202020202020202076696577547970653a20547970653c4d6574616461746156696577732e4e4654436f6c6c656374696f6e446174613e28290a202020202020202020202020202020202920617321204d6574616461746156696577732e4e4654436f6c6c656374696f6e446174613f0a202020202020202020202020202020203f3f2070616e69632822436f756c64206e6f74207265736f6c76652074686520636f6c6c656374696f6e2064617461207669657720666f7220746865204e465420636f6c6c656374696f6e22290a20202020202020202020202073656c662e73746f7261676550617468203d20636f6c6c656374696f6e446174612e73746f72616765506174680a20202020202020202020202073656c662e7075626c696350617468203d20636f6c6c656374696f6e446174612e7075626c6963506174680a20202020202020207d0a0a202020202020202061636365737328616c6c2920766965772066756e206765744e616d6528293a20537472696e67207b0a20202020202020202020202072657475726e20", + "2e6e616d650a20202020202020207d0a0a202020202020202061636365737328616c6c2920766965772066756e2067657453796d626f6c28293a20537472696e67207b0a20202020202020202020202072657475726e20", + "2e73796d626f6c0a20202020202020207d0a0a20202020202020202f2f2f2052657475726e732061206c697374206f66204e46542074797065732074686174207468697320726563656976657220616363657074730a202020202020202061636365737328616c6c2920766965772066756e20676574537570706f727465644e4654547970657328293a207b547970653a20426f6f6c7d207b0a20202020202020202020202072657475726e207b20547970653c40", "2e4e46543e28293a2074727565207d0a20202020202020207d0a0a20202020202020202f2f2f2052657475726e732077686574686572206f72206e6f742074686520676976656e20747970652069732061636365707465642062792074686520636f6c6c656374696f6e0a20202020202020202f2f2f204120636f6c6c656374696f6e20746861742063616e2061636365707420616e7920747970652073686f756c64206a7573742072657475726e20747275652062792064656661756c740a202020202020202061636365737328616c6c2920766965772066756e206973537570706f727465644e46545479706528747970653a2054797065293a20426f6f6c207b0a202020202020202020202072657475726e2074797065203d3d20547970653c40", - "2e4e46543e28290a20202020202020207d0a0a20202020202020202f2f2f2052656d6f76657320616e204e46542066726f6d2074686520636f6c6c656374696f6e20616e64206d6f76657320697420746f207468652063616c6c65720a2020202020202020616363657373284e6f6e46756e6769626c65546f6b656e2e5769746864726177207c204e6f6e46756e6769626c65546f6b656e2e4f776e6572292066756e20776974686472617728776974686472617749443a2055496e743634293a20407b4e6f6e46756e6769626c65546f6b656e2e4e46547d207b0a2020202020202020202020206c657420746f6b656e203c2d2073656c662e6f776e65644e4654732e72656d6f7665286b65793a2077697468647261774944290a202020202020202020202020202020203f3f2070616e69632822436f756c64206e6f7420776974686472617720616e204e46542077697468207468652070726f76696465642049442066726f6d2074686520636f6c6c656374696f6e22290a0a20202020202020202020202072657475726e203c2d746f6b656e0a20202020202020207d0a0a20202020202020202f2f2f2057697468647261777320616e204e46542066726f6d2074686520636f6c6c656374696f6e206279206974732045564d2049440a2020202020202020616363657373284e6f6e46756e6769626c65546f6b656e2e5769746864726177207c204e6f6e46756e6769626c65546f6b656e2e4f776e6572292066756e207769746864726177427945564d4944285f2069643a2055496e743634293a20407b4e6f6e46756e6769626c65546f6b656e2e4e46547d207b0a2020202020202020202020206c657420746f6b656e203c2d2073656c662e6f776e65644e4654732e72656d6f7665286b65793a206964290a202020202020202020202020202020203f3f2070616e69632822436f756c64206e6f7420776974686472617720616e204e46542077697468207468652070726f76696465642049442066726f6d2074686520636f6c6c656374696f6e22290a0a20202020202020202020202072657475726e203c2d746f6b656e0a20202020202020207d0a0a20202020202020202f2f2f205474616b65732061204e465420616e64206164647320697420746f2074686520636f6c6c656374696f6e732064696374696f6e61727920616e6420616464732074686520494420746f207468652065766d4944546f466c6f774944206d617070696e670a202020202020202061636365737328616c6c292066756e206465706f73697428746f6b656e3a20407b4e6f6e46756e6769626c65546f6b656e2e4e46547d29207b0a2020202020202020202020206c657420746f6b656e203c2d20746f6b656e206173212040", + "2e4e46543e28290a20202020202020207d0a0a20202020202020202f2f2f2052656d6f76657320616e204e46542066726f6d2074686520636f6c6c656374696f6e20616e64206d6f76657320697420746f207468652063616c6c65720a2020202020202020616363657373284e6f6e46756e6769626c65546f6b656e2e5769746864726177207c204e6f6e46756e6769626c65546f6b656e2e4f776e6572292066756e20776974686472617728776974686472617749443a2055496e743634293a20407b4e6f6e46756e6769626c65546f6b656e2e4e46547d207b0a2020202020202020202020206c657420746f6b656e203c2d2073656c662e6f776e65644e4654732e72656d6f7665286b65793a2077697468647261774944290a202020202020202020202020202020203f3f2070616e69632822436f756c64206e6f7420776974686472617720616e204e46542077697468207468652070726f76696465642049442066726f6d2074686520636f6c6c656374696f6e22290a0a20202020202020202020202072657475726e203c2d746f6b656e0a20202020202020207d0a0a20202020202020202f2f2f2057697468647261777320616e204e46542066726f6d2074686520636f6c6c656374696f6e206279206974732045564d2049440a2020202020202020616363657373284e6f6e46756e6769626c65546f6b656e2e5769746864726177207c204e6f6e46756e6769626c65546f6b656e2e4f776e6572292066756e207769746864726177427945564d4944285f2069643a2055496e74323536293a20407b4e6f6e46756e6769626c65546f6b656e2e4e46547d207b0a20202020202020202020202072657475726e203c2d2073656c662e776974686472617728776974686472617749443a200a2020202020202020202020202020202073656c662e676574436164656e636549442866726f6d3a20696429203f3f2070616e69632822436f756c64206e6f7420776974686472617720616e204e46542077697468207468652070726f76696465642045564d2049442066726f6d2074686520636f6c6c656374696f6e22290a202020202020202020202020290a20202020202020207d0a0a20202020202020202f2f2f205474616b65732061204e465420616e64206164647320697420746f2074686520636f6c6c656374696f6e732064696374696f6e61727920616e6420616464732074686520494420746f207468652065766d4944546f466c6f774944206d617070696e670a202020202020202061636365737328616c6c292066756e206465706f73697428746f6b656e3a20407b4e6f6e46756e6769626c65546f6b656e2e4e46547d29207b0a2020202020202020202020206c657420746f6b656e203c2d20746f6b656e206173212040", "2e4e46540a0a2020202020202020202020202f2f2061646420746865206e657720746f6b656e20746f207468652064696374696f6e6172792077686963682072656d6f76657320746865206f6c64206f6e650a20202020202020202020202073656c662e65766d4944546f466c6f7749445b746f6b656e2e65766d49445d203d20746f6b656e2e69640a2020202020202020202020206c6574206f6c64546f6b656e203c2d2073656c662e6f776e65644e4654735b746f6b656e2e69645d203c2d20746f6b656e0a0a20202020202020202020202064657374726f79206f6c64546f6b656e0a20202020202020207d0a0a20202020202020202f2f2f2052657475726e7320616e206172726179206f66207468652049447320746861742061726520696e2074686520636f6c6c656374696f6e0a202020202020202061636365737328616c6c2920766965772066756e2067657449447328293a205b55496e7436345d207b0a20202020202020202020202072657475726e2073656c662e6f776e65644e4654732e6b6579730a20202020202020207d0a0a20202020202020202f2f2f2052657475726e7320616e206172726179206f66207468652045564d2049447320746861742061726520696e2074686520636f6c6c656374696f6e0a202020202020202061636365737328616c6c2920766965772066756e2067657445564d49447328293a205b55496e743235365d207b0a20202020202020202020202072657475726e2073656c662e65766d4944546f466c6f7749442e6b6579730a20202020202020207d0a0a20202020202020202f2f2f2052657475726e732074686520436164656e6365204e46542e696420666f722074686520676976656e2045564d204e46542049442069660a202020202020202061636365737328616c6c2920766965772066756e20676574436164656e636549442866726f6d2065766d49443a2055496e74323536293a2055496e7436343f207b0a20202020202020202020202072657475726e2073656c662e65766d4944546f466c6f7749445b65766d49445d203f3f2055496e7436342865766d4944290a20202020202020207d0a0a20202020202020202f2f2f2052657475726e73207468652045564d204e4654204944206173736f63696174656420776974682074686520436164656e6365204e46542049442e2054686520676f616c20697320746f20726574726965766520746865204552433732312049442076616c75652e0a20202020202020202f2f2f20417320666172206173207468652062726964676520697320636f6e6365726e65642c20616e2045524337323120646566696e6564206279207468652062726964676520697320746865204e46542773204944206174207468652074696d65206f66206272696467696e670a20202020202020202f2f2f206f72207468652076616c7565206f6620746865204e46542e65766d494420696620697420696d706c656d656e7473207468652043726f7373564d4e46542e45564d4e465420696e74657266616365207768656e20627269646765642e0a20202020202020202f2f2f20466f6c6c6f77696e672074686973207061747465726e2c206966206c6f636b65642c20746865204e465420697320636865636b656420666f722045564d4e465420636f6e666f726d616e63652072657475726e696e67202e65766d494420696620736f2c0a20202020202020202f2f2f206f746865727769736520746865204e465427732049442069732072657475726e656420617320612055496e743235362073696e63652074686174277320686f77207468652062726964676520776f756c642068616e646c65206d696e74696e6720696e207468650a20202020202020202f2f2f20636f72726573706f6e64696e672045524337323120636f6e74726163742e0a20202020202020202f2f2f0a202020202020202061636365737328616c6c2920766965772066756e2067657445564d49442866726f6d20636164656e636549443a2055496e743634293a2055496e743235363f207b0a2020202020202020202020206966206c6574206e6674203d2073656c662e626f72726f774e465428636164656e6365494429207b0a202020202020202020202020202020206966206c65742065766d4e4654203d2043726f7373564d4e46542e67657445564d49442866726f6d3a206e667429207b0a202020202020202020202020202020202020202072657475726e2065766d4e46540a202020202020202020202020202020207d0a2020202020202020202020202020202072657475726e2055496e74323536286e66742e6964290a2020202020202020202020207d0a20202020202020202020202072657475726e206e696c0a20202020202020207d0a0a20202020202020202f2f2f2052657475726e732074686520636f6e747261637455524920666f7220746865204e465420636f6c6c656374696f6e20617320646566696e656420696e2074686520736f757263652045524337323120636f6e74726163742e204966206e6f6e65207761730a20202020202020202f2f2f20646566696e6564206174207468652074696d65206f66206272696467696e672c20616e20656d70747920737472696e672069732072657475726e65642e0a202020202020202061636365737328616c6c2920766965772066756e20636f6e747261637455524928293a20537472696e673f207b0a20202020202020202020202072657475726e20", "2e636f6e74726163745552490a20202020202020207d0a0a20202020202020202f2f2f20476574732074686520616d6f756e74206f66204e4654732073746f72656420696e2074686520636f6c6c656374696f6e0a202020202020202061636365737328616c6c2920766965772066756e206765744c656e67746828293a20496e74207b0a20202020202020202020202072657475726e2073656c662e6f776e65644e4654732e6b6579732e6c656e6774680a20202020202020207d0a0a20202020202020202f2f2f205265747269657665732061207265666572656e636520746f20746865204e46542073746f72656420696e2074686520636f6c6c656374696f6e206279206974732049440a202020202020202061636365737328616c6c2920766965772066756e20626f72726f774e4654285f2069643a2055496e743634293a20267b4e6f6e46756e6769626c65546f6b656e2e4e46547d3f207b0a20202020202020202020202072657475726e202673656c662e6f776e65644e4654735b69645d0a20202020202020207d0a0a20202020202020202f2f2f20426f72726f77207468652076696577207265736f6c76657220666f722074686520737065636966696564204e46542049440a202020202020202061636365737328616c6c2920766965772066756e20626f72726f77566965775265736f6c7665722869643a2055496e743634293a20267b566965775265736f6c7665722e5265736f6c7665727d3f207b0a2020202020202020202020206966206c6574206e6674203d202673656c662e6f776e65644e4654735b69645d2061732026", "2e4e46543f207b0a2020202020202020202020202020202072657475726e206e667420617320267b566965775265736f6c7665722e5265736f6c7665727d0a2020202020202020202020207d0a20202020202020202020202072657475726e206e696c0a20202020202020207d0a0a20202020202020202f2f2f204372656174657320616e20656d70747920636f6c6c656374696f6e0a202020202020202061636365737328616c6c292066756e20637265617465456d707479436f6c6c656374696f6e28293a20407b4e6f6e46756e6769626c65546f6b656e2e436f6c6c656374696f6e7d20207b0a20202020202020202020202072657475726e203c2d", @@ -32,9 +38,30 @@ access(all) let bridgedNFTCodeChunks = [ "2e436f6c6c656374696f6e3e28292c0a20202020202020202020202020202020202020207075626c69634c696e6b6564547970653a20547970653c26", "2e436f6c6c656374696f6e3e28292c0a2020202020202020202020202020202020202020637265617465456d707479436f6c6c656374696f6e46756e6374696f6e3a202866756e28293a20407b4e6f6e46756e6769626c65546f6b656e2e436f6c6c656374696f6e7d207b0a20202020202020202020202020202020202020202020202072657475726e203c2d", "2e637265617465456d707479436f6c6c656374696f6e286e6674547970653a20547970653c40", - "2e4e46543e2829290a20202020202020202020202020202020202020207d290a20202020202020202020202020202020290a2020202020202020202020202020202072657475726e20636f6c6c656374696f6e446174610a2020202020202020202020206361736520547970653c4d6574616461746156696577732e4e4654436f6c6c656374696f6e446973706c61793e28293a0a202020202020202020202020202020206c6574206d65646961203d204d6574616461746156696577732e4d65646961280a202020202020202020202020202020202020202066696c653a204d6574616461746156696577732e4854545046696c65280a20202020202020202020202020202020202020202020202075726c3a202268747470733a2f2f6173736574732e776562736974652d66696c65732e636f6d2f3566363239346330633761386364643634336231633832302f3566363239346330633761386364613535636231633933365f466c6f775f576f72646d61726b2e737667220a2020202020202020202020202020202020202020292c0a20202020202020202020202020202020202020206d65646961547970653a2022696d6167652f7376672b786d6c220a20202020202020202020202020202020290a2020202020202020202020202020202072657475726e204d6574616461746156696577732e4e4654436f6c6c656374696f6e446973706c6179280a20202020202020202020202020202020202020206e616d653a202254686520466c6f77564d2042726964676564204e465420436f6c6c656374696f6e222c0a20202020202020202020202020202020202020206465736372697074696f6e3a20225468697320636f6c6c656374696f6e2077617320627269646765642066726f6d20466c6f772045564d2e222c0a202020202020202020202020202020202020202065787465726e616c55524c3a204d6574616461746156696577732e45787465726e616c55524c282268747470733a2f2f6272696467652e666c6f772e636f6d2f6e667422292c0a2020202020202020202020202020202020202020737175617265496d6167653a206d656469612c0a202020202020202020202020202020202020202062616e6e6572496d6167653a206d656469612c0a2020202020202020202020202020202020202020736f6369616c733a207b7d0a20202020202020202020202020202020290a2020202020202020202020206361736520547970653c43726f7373564d4e46542e45564d427269646765644d657461646174613e28293a0a2020202020202020202020202020202072657475726e2043726f7373564d4e46542e45564d427269646765644d65746164617461280a20202020202020202020202020202020202020206e616d653a2073656c662e6e616d652c0a202020202020202020202020202020202020202073796d626f6c3a2073656c662e73796d626f6c2c0a20202020202020202020202020202020202020207572693a2073656c662e636f6e747261637455524920213d206e696c203f2043726f7373564d4e46542e55524928626173655552493a206e696c2c2076616c75653a2073656c662e636f6e74726163745552492129203a2043726f7373564d4e46542e55524928626173655552493a206e696c2c2076616c75653a202222290a20202020202020202020202020202020290a20202020202020207d0a202020202020202072657475726e206e696c0a202020207d0a0a202020202f2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a0a2020202020202020496e7465726e616c204d6574686f64730a202020202a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2f0a0a202020202f2f2f20416c6c6f7773207468652062726964676520746f206d696e74204e4654732066726f6d206272696467652d646566696e6564204e465420636f6e7472616374730a202020202f2f2f0a20202020616363657373286163636f756e74290a2020202066756e206d696e744e46542869643a2055496e743235362c20746f6b656e5552493a20537472696e67293a20404e4654207b0a2020202020202020707265207b0a20202020202020202020202073656c662e746f6b656e555249735b69645d203d3d206e696c3a20224120746f6b656e20776974682074686520676976656e2045524337323120494420616c726561647920657869737473220a20202020202020207d0a202020202020202073656c662e746f6b656e555249735b69645d203d20746f6b656e5552490a202020202020202072657475726e203c2d637265617465204e4654280a2020202020202020202020206e616d653a2073656c662e6e616d652c0a20202020202020202020202073796d626f6c3a2073656c662e73796d626f6c2c0a20202020202020202020202065766d49443a2069642c0a2020202020202020202020206d657461646174613a207b0a20202020202020202020202020202020224272696467656420426c6f636b223a2067657443757272656e74426c6f636b28292e6865696768742c0a2020202020202020202020202020202022427269646765642054696d657374616d70223a2067657443757272656e74426c6f636b28292e74696d657374616d700a2020202020202020202020207d0a2020202020202020290a202020207d0a0a202020202f2f2f20416c6c6f7773207468652062726964676520746f207570646174652074686520555249206f662062726964676564204e4654732e205468697320617373756d65732074686174207468652045564d2d646566696e696e672070726f6a656374206d617920636f6e7461696e0a202020202f2f2f206c6f67696320286f6e636861696e206f72206f6666636861696e292077686963682075706461746573204e4654206d6574616461746120696e2074686520736f757263652045524337323120636f6e74726163742e204f6e206272696467696e672c20746865205552492063616e0a202020202f2f2f207468656e206265207570646174656420696e207468697320636f6e747261637420746f207265666c6563742074686520736f757263652045524337323120636f6e74726163742773206d657461646174612e0a202020202f2f2f0a20202020616363657373286163636f756e74290a2020202066756e20757064617465546f6b656e5552492865766d49443a2055496e743235362c206e65775552493a20537472696e6729207b0a2020202020202020707265207b0a20202020202020202020202073656c662e746f6b656e555249735b65766d49445d20213d206e696c3a20224e6f20746f6b656e20776974682074686520676976656e2045524337323120494420657869737473220a20202020202020207d0a202020202020202069662073656c662e746f6b656e555249735b65766d49445d20213d206e6577555249207b0a20202020202020202020202073656c662e746f6b656e555249735b65766d49445d203d206e65775552490a20202020202020207d0a202020207d0a0a20202020696e6974286e616d653a20537472696e672c2073796d626f6c3a20537472696e672c2065766d436f6e7472616374416464726573733a2045564d2e45564d416464726573732c20636f6e74726163745552493a20537472696e673f29207b0a202020202020202073656c662e65766d4e4654436f6e747261637441646472657373203d2065766d436f6e7472616374416464726573730a202020202020202073656c662e6e616d65203d206e616d650a202020202020202073656c662e73796d626f6c203d2073796d626f6c0a202020202020202073656c662e636f6e7472616374555249203d20636f6e74726163745552490a202020202020202073656c662e746f6b656e55524973203d207b7d0a202020202020202073656c662e636f6c6c656374696f6e203c2d2063726561746520436f6c6c656374696f6e28290a0a2020202020202020466c6f7745564d427269646765436f6e6669672e6173736f63696174655479706528547970653c40", + "2e4e46543e2829290a20202020202020202020202020202020202020207d290a20202020202020202020202020202020290a2020202020202020202020202020202072657475726e20636f6c6c656374696f6e446174610a2020202020202020202020206361736520547970653c4d6574616461746156696577732e4e4654436f6c6c656374696f6e446973706c61793e28293a0a202020202020202020202020202020206c6574206d65646961203d204d6574616461746156696577732e4d65646961280a202020202020202020202020202020202020202066696c653a204d6574616461746156696577732e4854545046696c65280a20202020202020202020202020202020202020202020202075726c3a202268747470733a2f2f6173736574732e776562736974652d66696c65732e636f6d2f3566363239346330633761386364643634336231633832302f3566363239346330633761386364613535636231633933365f466c6f775f576f72646d61726b2e737667220a2020202020202020202020202020202020202020292c0a20202020202020202020202020202020202020206d65646961547970653a2022696d6167652f7376672b786d6c220a20202020202020202020202020202020290a2020202020202020202020202020202072657475726e204d6574616461746156696577732e4e4654436f6c6c656374696f6e446973706c6179280a20202020202020202020202020202020202020206e616d653a202254686520466c6f77564d2042726964676564204e465420436f6c6c656374696f6e222c0a20202020202020202020202020202020202020206465736372697074696f6e3a20225468697320636f6c6c656374696f6e2077617320627269646765642066726f6d20466c6f772045564d2e222c0a202020202020202020202020202020202020202065787465726e616c55524c3a204d6574616461746156696577732e45787465726e616c55524c282268747470733a2f2f6272696467652e666c6f772e636f6d2f6e667422292c0a2020202020202020202020202020202020202020737175617265496d6167653a206d656469612c0a202020202020202020202020202020202020202062616e6e6572496d6167653a206d656469612c0a2020202020202020202020202020202020202020736f6369616c733a207b7d0a20202020202020202020202020202020290a2020202020202020202020206361736520547970653c43726f7373564d4e46542e45564d427269646765644d657461646174613e28293a0a2020202020202020202020202020202072657475726e2043726f7373564d4e46542e45564d427269646765644d65746164617461280a20202020202020202020202020202020202020206e616d653a2073656c662e6e616d652c0a202020202020202020202020202020202020202073796d626f6c3a2073656c662e73796d626f6c2c0a20202020202020202020202020202020202020207572693a2073656c662e636f6e747261637455524920213d206e696c203f2043726f7373564d4e46542e55524928626173655552493a206e696c2c2076616c75653a2073656c662e636f6e74726163745552492129203a2043726f7373564d4e46542e55524928626173655552493a206e696c2c2076616c75653a202222290a20202020202020202020202020202020290a20202020202020207d0a202020202020202072657475726e206e696c0a202020207d0a0a202020202f2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a0a2020202020202020496e7465726e616c204d6574686f64730a202020202a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2f0a0a202020202f2f2f20416c6c6f7773207468652062726964676520746f206d696e74204e4654732066726f6d206272696467652d646566696e6564204e465420636f6e7472616374730a202020202f2f2f0a20202020616363657373286163636f756e74290a2020202066756e206d696e744e46542869643a2055496e743235362c20746f6b656e5552493a20537472696e67293a20404e4654207b0a2020202020202020707265207b0a20202020202020202020202073656c662e746f6b656e555249735b69645d203d3d206e696c3a20224120746f6b656e20776974682074686520676976656e2045524337323120494420616c726561647920657869737473220a20202020202020207d0a202020202020202073656c662e746f6b656e555249735b69645d203d20746f6b656e5552490a202020202020202072657475726e203c2d637265617465204e4654280a20202020202020202020202065766d49443a2069642c0a2020202020202020202020206d657461646174613a207b0a20202020202020202020202020202020224272696467656420426c6f636b223a2067657443757272656e74426c6f636b28292e6865696768742c0a2020202020202020202020202020202022427269646765642054696d657374616d70223a2067657443757272656e74426c6f636b28292e74696d657374616d700a2020202020202020202020207d0a2020202020202020290a202020207d0a0a202020202f2f2f20416c6c6f7773207468652062726964676520746f207570646174652074686520555249206f662062726964676564204e4654732e205468697320617373756d65732074686174207468652045564d2d646566696e696e672070726f6a656374206d617920636f6e7461696e0a202020202f2f2f206c6f67696320286f6e636861696e206f72206f6666636861696e292077686963682075706461746573204e4654206d6574616461746120696e2074686520736f757263652045524337323120636f6e74726163742e204f6e206272696467696e672c20746865205552492063616e0a202020202f2f2f207468656e206265207570646174656420696e207468697320636f6e747261637420746f207265666c6563742074686520736f757263652045524337323120636f6e74726163742773206d657461646174612e0a202020202f2f2f0a20202020616363657373286163636f756e74290a2020202066756e20757064617465546f6b656e5552492865766d49443a2055496e743235362c206e65775552493a20537472696e6729207b0a2020202020202020707265207b0a20202020202020202020202073656c662e746f6b656e555249735b65766d49445d20213d206e696c3a20224e6f20746f6b656e20776974682074686520676976656e2045524337323120494420657869737473220a20202020202020207d0a202020202020202069662073656c662e746f6b656e555249735b65766d49445d20213d206e6577555249207b0a20202020202020202020202073656c662e746f6b656e555249735b65766d49445d203d206e65775552490a20202020202020207d0a202020207d0a0a20202020696e6974286e616d653a20537472696e672c2073796d626f6c3a20537472696e672c2065766d436f6e7472616374416464726573733a2045564d2e45564d416464726573732c20636f6e74726163745552493a20537472696e673f29207b0a202020202020202073656c662e65766d4e4654436f6e747261637441646472657373203d2065766d436f6e7472616374416464726573730a202020202020202073656c662e6e616d65203d206e616d650a202020202020202073656c662e73796d626f6c203d2073796d626f6c0a202020202020202073656c662e636f6e7472616374555249203d20636f6e74726163745552490a202020202020202073656c662e746f6b656e55524973203d207b7d0a202020202020202073656c662e636f6c6c656374696f6e203c2d2063726561746520436f6c6c656374696f6e28290a0a2020202020202020466c6f7745564d427269646765436f6e6669672e6173736f63696174655479706528547970653c40", "2e4e46543e28292c20776974683a2073656c662e65766d4e4654436f6e747261637441646472657373290a2020202020202020466c6f7745564d4272696467654e4654457363726f772e696e697469616c697a65457363726f77280a202020202020202020202020666f72547970653a20547970653c40", - "2e4e46543e28292c0a202020202020202020202020657263373231416464726573733a2073656c662e65766d4e4654436f6e7472616374416464726573730a2020202020202020290a202020207d0a7d0a" + "2e4e46543e28292c0a2020202020202020202020206e616d653a206e616d652c0a20202020202020202020202073796d626f6c3a2073796d626f6c2c0a202020202020202020202020657263373231416464726573733a2073656c662e65766d4e4654436f6e7472616374416464726573730a2020202020202020290a202020207d0a7d0a" +] + +access(all) let bridgedTokenCodeChunks = [ + "696d706f7274204e6f6e46756e6769626c65546f6b656e2066726f6d203078303030303030303030303030303030310a696d706f7274204d6574616461746156696577732066726f6d203078303030303030303030303030303030310a696d706f72742046756e6769626c65546f6b656e4d6574616461746156696577732066726f6d203078303030303030303030303030303030320a696d706f727420566965775265736f6c7665722066726f6d203078303030303030303030303030303030310a696d706f72742046756e6769626c65546f6b656e2066726f6d203078303030303030303030303030303030320a696d706f727420466c6f77546f6b656e2066726f6d203078303030303030303030303030303030330a0a696d706f72742045564d2066726f6d203078303030303030303030303030303030310a0a696d706f7274204943726f7373564d2066726f6d203078303030303030303030303030303030370a696d706f7274204945564d427269646765546f6b656e4d696e7465722066726f6d203078303030303030303030303030303030370a696d706f727420466c6f7745564d427269646765546f6b656e457363726f772066726f6d203078303030303030303030303030303030370a696d706f727420466c6f7745564d427269646765436f6e6669672066726f6d203078303030303030303030303030303030370a696d706f727420466c6f7745564d4272696467655574696c732066726f6d203078303030303030303030303030303030370a696d706f727420466c6f7745564d4272696467652066726f6d203078303030303030303030303030303030370a696d706f72742043726f7373564d4e46542066726f6d203078303030303030303030303030303030370a696d706f72742043726f7373564d546f6b656e2066726f6d203078303030303030303030303030303030370a0a2f2f2f205468697320636f6e747261637420697320612074656d706c617465207573656420627920466c6f7745564d42726964676520746f20646566696e652045564d2d6e61746976652066756e6769626c6520746f6b656e7320627269646765642066726f6d20466c6f772045564d20746f200a2f2f2f20436164656e63652e2055706f6e206465706c6f796d656e74206f66207468697320636f6e74726163742c2074686520636f6e7472616374206e616d65206973206465726976656420617320612066756e6374696f6e206f6620746865206173736574207479706520286865726520616e200a2f2f2f2045524332302920616e642074686520636f6e747261637427732045564d20616464726573732e20546865206465726976656420636f6e7472616374206e616d65206973207468656e206a6f696e65642077697468207468697320636f6e7472616374277320636f64652c0a2f2f2f207072657061726564206173206368756e6b7320696e20466c6f7745564d42726964676554656d706c61746573206265666f7265206265696e67206465706c6f79656420746f2074686520466c6f772045564d20427269646765206163636f756e742e0a2f2f2f0a2f2f2f204f6e206272696467696e672c20746865204552433230206973207472616e7366657272656420746f2074686520627269646765277320436164656e63654f776e65644163636f756e742045564d206164647265737320616e6420746f6b656e7320617265206d696e7465642066726f6d0a2f2f2f207468697320636f6e747261637420746f20746865206272696467696e672063616c6c65722e204f6e2072657475726e20746f20466c6f772045564d2c2074686520726576657273652070726f6365737320697320666f6c6c6f776564202d2074686520746f6b656e206973206275726e65640a2f2f2f20696e207468697320636f6e747261637420616e6420746865204552433230206973207472616e7366657272656420746f2074686520646566696e656420726563697069656e742e20496e2074686973207761792c2074686520436164656e6365205661756c74206163747320617320610a2f2f2f20726570726573656e746174696f6e206f6620626f7468207468652045564d20746f6b656e7320616e642074687573206f776e6572736869702072696768747320746f2069742075706f6e206272696467696e67206261636b20746f20466c6f772045564d2e0a2f2f2f0a2f2f2f20546f20627269646765206265747765656e20564d732c20612063616c6c65722063616e20656974686572207573652074686520696e74657266616365206578706f736564206f6e20436164656e63654f776e65644163636f756e74206f722075736520466c6f7745564d4272696467650a2f2f2f207075626c696320636f6e7472616374206d6574686f64732e0a2f2f2f0a61636365737328616c6c2920636f6e747261637420", + "203a204943726f7373564d2c204945564d427269646765546f6b656e4d696e7465722c2046756e6769626c65546f6b656e207b0a0a202020202f2f2f20506f696e74657220746f2074686520466163746f7279206465706c6f79656420536f6c696469747920636f6e7472616374206164647265737320646566696e696e672074686520627269646765642061737365740a2020202061636365737328616c6c29206c65742065766d546f6b656e436f6e7472616374416464726573733a2045564d2e45564d416464726573730a202020202f2f2f204e616d65206f66207468652066756e6769626c6520746f6b656e20646566696e656420696e2074686520636f72726573706f6e64696e6720455243323020636f6e74726163740a2020202061636365737328616c6c29206c6574206e616d653a20537472696e670a202020202f2f2f2053796d626f6c206f66207468652066756e6769626c6520746f6b656e20646566696e656420696e2074686520636f72726573706f6e64696e6720455243323020636f6e74726163740a2020202061636365737328616c6c29206c65742073796d626f6c3a20537472696e670a202020202f2f2f20446563696d616c20706c6163652076616c756520646566696e656420696e2074686520736f7572636520455243323020636f6e74726163740a2020202061636365737328616c6c29206c657420646563696d616c733a2055496e74380a202020202f2f2f20555249206f662074686520636f6e74726163742c20696620617661696c61626c6520617320612076617220696e2063617365207468652062726964676520656e61626c65732063726f73732d564d204d657461646174612073796e63696e6720696e20746865206675747572650a2020202061636365737328616c6c292076617220636f6e74726163745552493a20537472696e673f0a202020202f2f2f20546f74616c20737570706c79206f66207468697320436164656e636520746f6b656e20696e2063697263756c6174696f6e0a202020202f2f2f204e4f54453a205468697320646f6573206e6f74207265666c6563742074686520746f74616c20737570706c79206f662074686520736f7572636520455243323020696e2063697263756c6174696f6e2077697468696e2045564d0a2020202061636365737328616c6c292076617220746f74616c537570706c793a205546697836340a202020202f2f2f2052657461696e2061205661756c7420746f207265666572656e6365207768656e207265736f6c76696e67205661756c74204d657461646174610a202020206163636573732873656c6629206c6574207661756c743a20405661756c740a0a202020202f2f2f20546865205661756c74207265736f7572636520726570726573656e74696e6720746865206272696467656420455243323020746f6b656e0a202020202f2f2f0a2020202061636365737328616c6c29207265736f75726365205661756c74203a2043726f7373564d546f6b656e2e45564d546f6b656e496e666f2c2046756e6769626c65546f6b656e2e5661756c74207b0a20202020202020202f2f2f2042616c616e6365206f662074686520746f6b656e7320696e206120676976656e205661756c740a202020202020202061636365737328616c6c29207661722062616c616e63653a205546697836340a0a2020202020202020696e69742862616c616e63653a2055466978363429207b0a20202020202020202020202073656c662e62616c616e6365203d2062616c616e63650a20202020202020207d0a0a20202020202020202f2a202d2d2d2043726f7373564d546f6b656e2e45564d46545661756c7420636f6e666f726d616e6365202d2d2d202a2f0a20202020202020202f2f0a20202020202020202f2f2f204765747320746865204552433230206e616d652076616c75650a202020202020202061636365737328616c6c2920766965772066756e206765744e616d6528293a20537472696e67207b0a20202020202020202020202072657475726e20", + "2e6e616d650a20202020202020207d0a20202020202020202f2f2f2047657473207468652045524332302073796d626f6c2076616c75650a202020202020202061636365737328616c6c2920766965772066756e2067657453796d626f6c28293a20537472696e67207b0a20202020202020202020202072657475726e20", + "2e73796d626f6c0a20202020202020207d0a20202020202020202f2f2f20476574732074686520455243323020646563696d616c732076616c75650a202020202020202061636365737328616c6c2920766965772066756e20676574446563696d616c7328293a2055496e7438207b0a20202020202020202020202072657475726e20", + "2e646563696d616c730a20202020202020207d0a20202020202020202f2f2f2052657475726e73207468652045564d20636f6e74726163742061646472657373206f66207468652066756e6769626c6520746f6b656e0a202020202020202061636365737328616c6c2920766965772066756e2067657445564d436f6e74726163744164647265737328293a2045564d2e45564d41646472657373207b0a20202020202020202020202072657475726e20", + "2e67657445564d436f6e74726163744164647265737328290a20202020202020207d0a0a202020202020202061636365737328616c6c2920766965772066756e20676574566965777328293a205b547970655d207b0a20202020202020202020202072657475726e20", + "2e676574436f6e74726163745669657773287265736f75726365547970653a206e696c290a20202020202020207d0a0a202020202020202061636365737328616c6c292066756e207265736f6c766556696577285f20766965773a2054797065293a20416e795374727563743f207b0a20202020202020202020202072657475726e20", + "2e7265736f6c7665436f6e747261637456696577287265736f75726365547970653a206e696c2c2076696577547970653a2076696577290a20202020202020207d0a0a20202020202020202f2f2f20676574537570706f727465645661756c745479706573206f7074696f6e616c6c792072657475726e732061206c697374206f66207661756c742074797065732074686174207468697320726563656976657220616363657074730a202020202020202061636365737328616c6c2920766965772066756e20676574537570706f727465645661756c74547970657328293a207b547970653a20426f6f6c7d207b0a20202020202020202020202072657475726e207b2073656c662e6765745479706528293a2074727565207d0a20202020202020207d0a0a202020202020202061636365737328616c6c2920766965772066756e206973537570706f727465645661756c745479706528747970653a2054797065293a20426f6f6c207b0a20202020202020202020202072657475726e2073656c662e676574537570706f727465645661756c74547970657328295b747970655d203f3f2066616c73650a20202020202020207d0a0a20202020202020202f2f2f2041736b732069662074686520616d6f756e742063616e2062652077697468647261776e2066726f6d2074686973207661756c740a202020202020202061636365737328616c6c2920766965772066756e206973417661696c61626c65546f576974686472617728616d6f756e743a20554669783634293a20426f6f6c207b0a20202020202020202020202072657475726e20616d6f756e74203c3d2073656c662e62616c616e63650a20202020202020207d0a0a20202020202020202f2f2f206465706f7369740a20202020202020202f2f2f0a20202020202020202f2f2f2046756e6374696f6e20746861742074616b65732061205661756c74206f626a65637420617320616e20617267756d656e7420616e6420616464730a20202020202020202f2f2f206974732062616c616e636520746f207468652062616c616e6365206f6620746865206f776e657273205661756c742e0a20202020202020202f2f2f0a20202020202020202f2f2f20497420697320616c6c6f77656420746f2064657374726f79207468652073656e74205661756c74206265636175736520746865205661756c740a20202020202020202f2f2f2077617320612074656d706f7261727920686f6c646572206f662074686520746f6b656e732e20546865205661756c7427732062616c616e6365206861730a20202020202020202f2f2f206265656e20636f6e73756d656420616e64207468657265666f72652063616e2062652064657374726f7965642e0a20202020202020202f2f2f0a202020202020202061636365737328616c6c292066756e206465706f7369742866726f6d3a20407b46756e6769626c65546f6b656e2e5661756c747d29207b0a2020202020202020202020206c6574207661756c74203c2d2066726f6d2061732120405661756c740a20202020202020202020202073656c662e62616c616e6365203d2073656c662e62616c616e6365202b207661756c742e62616c616e63650a2020202020202020202020207661756c742e62616c616e6365203d20302e300a20202020202020202020202064657374726f79207661756c740a20202020202020207d0a0a20202020202020202f2f2f20637265617465456d7074795661756c740a20202020202020202f2f2f0a20202020202020202f2f2f2046756e6374696f6e207468617420637265617465732061206e6577205661756c74207769746820612062616c616e6365206f66207a65726f0a20202020202020202f2f2f20616e642072657475726e7320697420746f207468652063616c6c696e6720636f6e746578742e20412075736572206d7573742063616c6c20746869732066756e6374696f6e0a20202020202020202f2f2f20616e642073746f7265207468652072657475726e6564205661756c7420696e2074686569722073746f7261676520696e206f7264657220746f20616c6c6f772074686569720a20202020202020202f2f2f206163636f756e7420746f2062652061626c6520746f2072656365697665206465706f73697473206f66207468697320746f6b656e20747970652e0a20202020202020202f2f2f0a202020202020202061636365737328616c6c292066756e20637265617465456d7074795661756c7428293a20405661756c74207b0a20202020202020202020202072657475726e203c2d637265617465205661756c742862616c616e63653a20302e30290a20202020202020207d0a0a20202020202020202f2f2f2077697468647261770a20202020202020202f2f2f0a20202020202020202f2f2f2046756e6374696f6e20746861742074616b657320616e20616d6f756e7420617320616e20617267756d656e740a20202020202020202f2f2f20616e6420776974686472617773207468617420616d6f756e742066726f6d20746865205661756c742e0a20202020202020202f2f2f0a20202020202020202f2f2f20497420637265617465732061206e65772074656d706f72617279205661756c742074686174206973207573656420746f20686f6c640a20202020202020202f2f2f2074686520746f6b656e73207468617420617265206265696e67207472616e736665727265642e2049742072657475726e7320746865206e65776c790a20202020202020202f2f2f2063726561746564205661756c7420746f2074686520636f6e7465787420746861742063616c6c656420736f2069742063616e206265206465706f73697465640a20202020202020202f2f2f20656c736577686572652e0a20202020202020202f2f2f0a20202020202020206163636573732846756e6769626c65546f6b656e2e5769746864726177292066756e20776974686472617728616d6f756e743a20554669783634293a20405661756c74207b0a20202020202020202020202073656c662e62616c616e6365203d2073656c662e62616c616e6365202d20616d6f756e740a20202020202020202020202072657475726e203c2d637265617465205661756c742862616c616e63653a20616d6f756e74290a20202020202020207d0a0a20202020202020202f2f2f2043616c6c6564207768656e20612066756e6769626c6520746f6b656e206973206275726e6564207669612074686520604275726e65722e6275726e282960206d6574686f640a202020202020202061636365737328636f6e7472616374292066756e206275726e43616c6c6261636b2829207b0a20202020202020202020202069662073656c662e62616c616e6365203e20302e30207b0a20202020202020202020202020202020", + "2e746f74616c537570706c79203d20", + "2e746f74616c537570706c79202d2073656c662e62616c616e63650a2020202020202020202020207d0a20202020202020202020202073656c662e62616c616e6365203d20302e300a20202020202020207d0a202020207d0a0a202020202f2f2f20637265617465456d7074795661756c740a202020202f2f2f0a202020202f2f2f2046756e6374696f6e207468617420637265617465732061206e6577205661756c74207769746820612062616c616e6365206f66207a65726f20616e642072657475726e7320697420746f207468652063616c6c696e6720636f6e746578742e20412075736572206d7573742063616c6c0a202020202f2f2f20746869732066756e6374696f6e20616e642073746f7265207468652072657475726e6564205661756c7420696e2074686569722073746f7261676520696e206f7264657220746f20616c6c6f77207468656972206163636f756e7420746f2062652061626c6520746f0a202020202f2f2f2072656365697665206465706f73697473206f66207468697320746f6b656e20747970652e0a202020202f2f2f0a2020202061636365737328616c6c292066756e20637265617465456d7074795661756c74287661756c74547970653a2054797065293a2040", + "2e5661756c74207b0a202020202020202072657475726e203c2d20637265617465205661756c742862616c616e63653a20302e30290a202020207d0a0a202020202f2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a0a202020202020202020202020476574746572730a202020202a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2f0a0a202020202f2f2f2052657475726e73207468652045564d20636f6e74726163742061646472657373206f66207468652066756e6769626c6520746f6b656e207468697320636f6e747261637420726570726573656e74730a202020202f2f2f0a2020202061636365737328616c6c2920766965772066756e2067657445564d436f6e74726163744164647265737328293a2045564d2e45564d41646472657373207b0a202020202020202072657475726e2073656c662e65766d546f6b656e436f6e7472616374416464726573730a202020207d0a0a202020202f2f2f2046756e6374696f6e20746861742072657475726e7320616c6c20746865204d6574616461746120566965777320696d706c656d656e74656420627920746869732066756e6769626c6520746f6b656e20636f6e74726163742e0a202020202f2f2f0a202020202f2f2f204072657475726e20416e206172726179206f6620547970657320646566696e696e672074686520696d706c656d656e7465642076696577732e20546869732076616c75652077696c6c20626520757365642062790a202020202f2f2f202020202020202020646576656c6f7065727320746f206b6e6f7720776869636820706172616d6574657220746f207061737320746f20746865207265736f6c7665566965772829206d6574686f642e0a202020202f2f2f0a2020202061636365737328616c6c2920766965772066756e20676574436f6e74726163745669657773287265736f75726365547970653a20547970653f293a205b547970655d207b0a202020202020202072657475726e205b0a202020202020202020202020547970653c46756e6769626c65546f6b656e4d6574616461746156696577732e4654566965773e28292c0a202020202020202020202020547970653c46756e6769626c65546f6b656e4d6574616461746156696577732e4654446973706c61793e28292c0a202020202020202020202020547970653c46756e6769626c65546f6b656e4d6574616461746156696577732e46545661756c74446174613e28292c0a202020202020202020202020547970653c46756e6769626c65546f6b656e4d6574616461746156696577732e546f74616c537570706c793e28292c0a202020202020202020202020547970653c43726f7373564d4e46542e45564d427269646765644d657461646174613e28290a20202020202020205d0a202020207d0a0a202020202f2f2f2046756e6374696f6e2074686174207265736f6c7665732061206d65746164617461207669657720666f72207468697320636f6e74726163742e0a202020202f2f2f0a202020202f2f2f2040706172616d20766965773a205468652054797065206f6620746865206465736972656420766965772e0a202020202f2f2f0a202020202f2f2f204072657475726e20412073747275637475726520726570726573656e74696e67207468652072657175657374656420766965772e0a202020202f2f2f0a2020202061636365737328616c6c292066756e207265736f6c7665436f6e747261637456696577287265736f75726365547970653a20547970653f2c2076696577547970653a2054797065293a20416e795374727563743f207b0a2020202020202020737769746368207669657754797065207b0a2020202020202020202020206361736520547970653c46756e6769626c65546f6b656e4d6574616461746156696577732e4654566965773e28293a0a2020202020202020202020202020202072657475726e2046756e6769626c65546f6b656e4d6574616461746156696577732e465456696577280a20202020202020202020202020202020202020206674446973706c61793a2073656c662e7265736f6c7665436f6e747261637456696577287265736f75726365547970653a206e696c2c2076696577547970653a20547970653c46756e6769626c65546f6b656e4d6574616461746156696577732e4654446973706c61793e282929206173212046756e6769626c65546f6b656e4d6574616461746156696577732e4654446973706c61793f2c0a202020202020202020202020202020202020202066745661756c74446174613a2073656c662e7265736f6c7665436f6e747261637456696577287265736f75726365547970653a206e696c2c2076696577547970653a20547970653c46756e6769626c65546f6b656e4d6574616461746156696577732e46545661756c74446174613e282929206173212046756e6769626c65546f6b656e4d6574616461746156696577732e46545661756c74446174613f0a20202020202020202020202020202020290a2020202020202020202020206361736520547970653c46756e6769626c65546f6b656e4d6574616461746156696577732e4654446973706c61793e28293a0a202020202020202020202020202020206c6574206d65646961203d204d6574616461746156696577732e4d65646961280a20202020202020202020202020202020202020202020202066696c653a204d6574616461746156696577732e4854545046696c65280a20202020202020202020202020202020202020202020202075726c3a202268747470733a2f2f6173736574732e776562736974652d66696c65732e636f6d2f3566363239346330633761386364643634336231633832302f3566363239346330633761386364613535636231633933365f466c6f775f576f72646d61726b2e737667220a2020202020202020202020202020202020202020292c0a20202020202020202020202020202020202020206d65646961547970653a2022696d6167652f7376672b786d6c220a20202020202020202020202020202020290a202020202020202020202020202020206c6574206d6564696173203d204d6574616461746156696577732e4d6564696173285b6d656469615d290a2020202020202020202020202020202072657475726e2046756e6769626c65546f6b656e4d6574616461746156696577732e4654446973706c6179280a20202020202020202020202020202020202020202f2f20544f444f3a20446563696465206f6e20686f772077652077616e7420746f20726570726573656e74206272696467656420746f6b656e206d656469610a20202020202020202020202020202020202020206e616d653a2073656c662e6e616d652c0a202020202020202020202020202020202020202073796d626f6c3a2073656c662e73796d626f6c2c0a20202020202020202020202020202020202020206465736372697074696f6e3a2022546869732066756e6769626c6520746f6b656e2077617320627269646765642066726f6d20466c6f772045564d2e222c0a202020202020202020202020202020202020202065787465726e616c55524c3a204d6574616461746156696577732e45787465726e616c55524c282268747470733a2f2f6272696467652e666c6f772e636f6d2f66756e6769626c652d746f6b656e22292c0a20202020202020202020202020202020202020206c6f676f733a206d65646961732c0a2020202020202020202020202020202020202020736f6369616c733a207b7d0a20202020202020202020202020202020290a2020202020202020202020206361736520547970653c46756e6769626c65546f6b656e4d6574616461746156696577732e46545661756c74446174613e28293a0a2020202020202020202020202020202072657475726e2046756e6769626c65546f6b656e4d6574616461746156696577732e46545661756c7444617461280a202020202020202020202020202020202020202073746f72616765506174683a202f73746f726167652f", + "5661756c742c0a20202020202020202020202020202020202020207265636569766572506174683a202f7075626c69632f", + "52656365697665722c0a20202020202020202020202020202020202020206d65746164617461506174683a202f7075626c69632f", + "5661756c742c0a202020202020202020202020202020202020202072656365697665724c696e6b6564547970653a20547970653c26", + "2e5661756c743e28292c0a20202020202020202020202020202020202020206d657461646174614c696e6b6564547970653a20547970653c26", + "2e5661756c743e28292c0a2020202020202020202020202020202020202020637265617465456d7074795661756c7446756e6374696f6e3a202866756e28293a20407b46756e6769626c65546f6b656e2e5661756c747d207b0a20202020202020202020202020202020202020202020202072657475726e203c2d73656c662e637265617465456d7074795661756c74287661756c74547970653a20547970653c40", + "2e5661756c743e2829290a20202020202020202020202020202020202020207d290a20202020202020202020202020202020290a2020202020202020202020206361736520547970653c46756e6769626c65546f6b656e4d6574616461746156696577732e546f74616c537570706c793e28293a0a2020202020202020202020202020202072657475726e2046756e6769626c65546f6b656e4d6574616461746156696577732e546f74616c537570706c79280a2020202020202020202020202020202020202020746f74616c537570706c793a2073656c662e746f74616c537570706c790a20202020202020202020202020202020290a2020202020202020202020206361736520547970653c43726f7373564d4e46542e45564d427269646765644d657461646174613e28293a0a2020202020202020202020202020202072657475726e2043726f7373564d4e46542e45564d427269646765644d65746164617461280a20202020202020202020202020202020202020206e616d653a2073656c662e6e616d652c0a202020202020202020202020202020202020202073796d626f6c3a2073656c662e73796d626f6c2c0a20202020202020202020202020202020202020207572693a2073656c662e636f6e747261637455524920213d206e696c203f2043726f7373564d4e46542e55524928626173655552493a206e696c2c2076616c75653a2073656c662e636f6e74726163745552492129203a2043726f7373564d4e46542e55524928626173655552493a206e696c2c2076616c75653a202222290a20202020202020202020202020202020290a20202020202020207d0a202020202020202072657475726e206e696c0a202020207d0a0a202020202f2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a0a2020202020202020496e7465726e616c204d6574686f64730a202020202a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2f0a0a202020202f2f2f20416c6c6f7773207468652062726964676520746f206d696e7420746f6b656e732066726f6d206272696467652d646566696e65642066756e6769626c6520746f6b656e20636f6e7472616374730a202020202f2f2f0a20202020616363657373286163636f756e74292066756e206d696e74546f6b656e7328616d6f756e743a20554669783634293a20407b46756e6769626c65546f6b656e2e5661756c747d207b0a202020202020202073656c662e746f74616c537570706c79203d2073656c662e746f74616c537570706c79202b20616d6f756e740a202020202020202072657475726e203c2d20637265617465205661756c742862616c616e63653a20616d6f756e74290a202020207d0a0a20202020696e6974286e616d653a20537472696e672c2073796d626f6c3a20537472696e672c20646563696d616c733a2055496e74382c2065766d436f6e7472616374416464726573733a2045564d2e45564d416464726573732c20636f6e74726163745552493a20537472696e673f29207b0a202020202020202073656c662e65766d546f6b656e436f6e747261637441646472657373203d2065766d436f6e7472616374416464726573730a202020202020202073656c662e6e616d65203d206e616d650a202020202020202073656c662e73796d626f6c203d2073796d626f6c0a202020202020202073656c662e646563696d616c73203d20646563696d616c730a202020202020202073656c662e636f6e7472616374555249203d20636f6e74726163745552490a202020202020202073656c662e746f74616c537570706c79203d20302e300a202020202020202073656c662e7661756c74203c2d20637265617465205661756c742862616c616e63653a20302e30290a0a2020202020202020466c6f7745564d427269646765436f6e6669672e6173736f63696174655479706528547970653c40", + "2e5661756c743e28292c20776974683a2073656c662e65766d546f6b656e436f6e747261637441646472657373290a2020202020202020466c6f7745564d427269646765546f6b656e457363726f772e696e697469616c697a65457363726f77280a202020202020202020202020776974683a203c2d637265617465205661756c742862616c616e63653a20302e30292c0a2020202020202020202020206e616d653a206e616d652c0a20202020202020202020202073796d626f6c3a2073796d626f6c2c0a202020202020202020202020646563696d616c733a20646563696d616c732c0a20202020202020202020202065766d546f6b656e416464726573733a2073656c662e65766d546f6b656e436f6e7472616374416464726573730a2020202020202020290a202020207d0a7d0a" ] access(all) @@ -52,6 +79,11 @@ fun getCompiledERC721Bytecode(): String { return compiledERC721Bytecode } +access(all) +fun getCompiledERC20Bytecode(): String { + return compiledERC20Bytecode +} + access(all) fun getEVMBridgeRouterCode(): String { return evmBridgeRouterCode @@ -61,3 +93,8 @@ access(all) fun getBridgedNFTCodeChunks(): [String] { return bridgedNFTCodeChunks } + +access(all) +fun getBridgedTokenCodeChunks(): [String] { + return bridgedTokenCodeChunks +} diff --git a/cadence/transactions/bridge/admin/claim_accessor_capability_and_save_router.cdc b/cadence/transactions/bridge/admin/claim_accessor_capability_and_save_router.cdc new file mode 100644 index 00000000..7d2451e0 --- /dev/null +++ b/cadence/transactions/bridge/admin/claim_accessor_capability_and_save_router.cdc @@ -0,0 +1,28 @@ +import "EVM" + +import "FlowEVMBridgeAccessor" + +/// This transaction is intended to be run once by the EVM contract account after FlowEVMBridgeAccessor.BridgeAccessor +/// has been configured in the bridge account and its Capability has been published to be claimed by the EVM account. +/// +/// @param name: The name of the BridgeAccessor Capability to claim +/// @param provider: The address of the account that published the BridgeAccessor Capability +/// +transaction(name: String, provider: Address) { + + prepare(signer: auth(Inbox, SaveValue) &Account) { + // Claim the BridgeAccessor Capability + let accessorCap = signer.inbox.claim(name, provider: provider) + ?? panic("BridgeAccessor Capability not found") + + // Ensure the Capability is valid + assert(accessorCap.check() == true, message: "Invalid BridgeAccessor Capability") + + // Create a Router to store the Capability and set the BridgeAccessor Capability in the Router + let router <- accessorCap.borrow()!.createBridgeRouter() + router.setBridgeAccessorCap(accessorCap) + + // Save the Router in storage + signer.storage.save(<-router, to: /storage/evmBridgeRouter) + } +} diff --git a/cadence/transactions/bridge/bridge_nft_from_evm.cdc b/cadence/transactions/bridge/nft/bridge_nft_from_evm.cdc similarity index 100% rename from cadence/transactions/bridge/bridge_nft_from_evm.cdc rename to cadence/transactions/bridge/nft/bridge_nft_from_evm.cdc diff --git a/cadence/transactions/bridge/bridge_nft_to_evm.cdc b/cadence/transactions/bridge/nft/bridge_nft_to_evm.cdc similarity index 100% rename from cadence/transactions/bridge/bridge_nft_to_evm.cdc rename to cadence/transactions/bridge/nft/bridge_nft_to_evm.cdc diff --git a/cadence/transactions/bridge/onboard_by_evm_address.cdc b/cadence/transactions/bridge/onboarding/onboard_by_evm_address.cdc similarity index 100% rename from cadence/transactions/bridge/onboard_by_evm_address.cdc rename to cadence/transactions/bridge/onboarding/onboard_by_evm_address.cdc diff --git a/cadence/transactions/bridge/onboard_by_type.cdc b/cadence/transactions/bridge/onboarding/onboard_by_type.cdc similarity index 100% rename from cadence/transactions/bridge/onboard_by_type.cdc rename to cadence/transactions/bridge/onboarding/onboard_by_type.cdc diff --git a/cadence/transactions/bridge/tokens/bridge_tokens_from_evm.cdc b/cadence/transactions/bridge/tokens/bridge_tokens_from_evm.cdc new file mode 100644 index 00000000..0c63368d --- /dev/null +++ b/cadence/transactions/bridge/tokens/bridge_tokens_from_evm.cdc @@ -0,0 +1,106 @@ +import "FungibleToken" +import "FungibleTokenMetadataViews" +import "ViewResolver" +import "MetadataViews" +import "FlowToken" + +import "ScopedFTProviders" + +import "EVM" + +import "FlowEVMBridge" +import "FlowEVMBridgeConfig" +import "FlowEVMBridgeUtils" + +/// This transaction bridges fungible tokens from EVM to Cadence assuming it has already been onboarded to the +/// FlowEVMBridge. +/// +/// NOTE: The ERC721 must have first been onboarded to the bridge. This can be checked via the method +/// FlowEVMBridge.evmAddressRequiresOnboarding(address: self.evmContractAddress) +/// +/// @param tokenContractAddress: The Flow account address hosting the FT-defining Cadence contract +/// @param tokenContractName: The name of the Vault-defining Cadence contract +/// @param amount: The amount of tokens to bridge from EVM +/// +transaction(tokenContractAddress: Address, tokenContractName: String, amount: UInt256) { + + let vaultType: Type + let receiver: &{FungibleToken.Vault} + let scopedProvider: @ScopedFTProviders.ScopedFTProvider + let coa: auth(EVM.Bridge) &EVM.CadenceOwnedAccount + + prepare(signer: auth(BorrowValue, CopyValue, IssueStorageCapabilityController, PublishCapability, SaveValue, UnpublishCapability) &Account) { + /* --- Reference the signer's CadenceOwnedAccount --- */ + // + // Borrow a reference to the signer's COA + self.coa = signer.storage.borrow(from: /storage/evm) + ?? panic("Could not borrow COA from provided gateway address") + + // Get the ERC20 contract address for the given FungibleToken Vault type + self.vaultType = FlowEVMBridgeUtils.buildCompositeType( + address: tokenContractAddress, + contractName: tokenContractName, + resourceName: "Vault" + ) ?? panic("Could not construct Vault type of: " .concat(tokenContractAddress.toString()).concat(".").concat(tokenContractName).concat(".Vault")) + + /* --- Reference the signer's Vault --- */ + // + // Borrow a reference to the FungibleToken Vault, configuring if necessary + let viewResolver = getAccount(tokenContractAddress).contracts.borrow<&{ViewResolver}>(name: tokenContractName) + ?? panic("Could not borrow ViewResolver from FungibleToken contract") + let vaultData = viewResolver.resolveContractView( + resourceType: self.vaultType, + viewType: Type() + ) as! FungibleTokenMetadataViews.FTVaultData? ?? panic("Could not resolve FTVaultData view") + // If the vault does not exist, create it and publish according to the contract's defined configuration + if signer.storage.borrow<&{FungibleToken.Vault}>(from: vaultData.storagePath) == nil { + signer.storage.save(<-vaultData.createEmptyVault(), to: vaultData.storagePath) + + signer.capabilities.unpublish(vaultData.receiverPath) + signer.capabilities.unpublish(vaultData.metadataPath) + + let receiverCap = signer.capabilities.storage.issue<&{FungibleToken.Vault}>(vaultData.storagePath) + let metadataCap = signer.capabilities.storage.issue<&{FungibleToken.Vault}>(vaultData.storagePath) + + signer.capabilities.publish(receiverCap, at: vaultData.receiverPath) + signer.capabilities.publish(metadataCap, at: vaultData.metadataPath) + } + self.receiver = signer.storage.borrow<&{FungibleToken.Vault}>(from: vaultData.storagePath) + ?? panic("Could not borrow Vault from storage path") + + /* --- Configure a ScopedFTProvider --- */ + // + // Calculate the bridge fee - bridging from EVM consumes no storage, so flat fee + let approxFee = FlowEVMBridgeUtils.calculateBridgeFee(used: 0, includeBase: true) + // Issue and store bridge-dedicated Provider Capability in storage if necessary + if signer.storage.type(at: FlowEVMBridgeConfig.providerCapabilityStoragePath) == nil { + let providerCap = signer.capabilities.storage.issue( + /storage/flowTokenVault + ) + signer.storage.save(providerCap, to: FlowEVMBridgeConfig.providerCapabilityStoragePath) + } + // Copy the stored Provider capability and create a ScopedFTProvider + let providerCapCopy = signer.storage.copy>( + from: FlowEVMBridgeConfig.providerCapabilityStoragePath + ) ?? panic("Invalid Provider Capability found in storage.") + let providerFilter = ScopedFTProviders.AllowanceFilter(approxFee) + self.scopedProvider <- ScopedFTProviders.createScopedFTProvider( + provider: providerCapCopy, + filters: [ providerFilter ], + expiration: getCurrentBlock().timestamp + 1.0 + ) + } + + execute { + // Execute the bridge request + let vault: @{FungibleToken.Vault} <- self.coa.withdrawTokens( + type: self.vaultType, + amount: amount, + feeProvider: &self.scopedProvider as auth(FungibleToken.Withdraw) &{FungibleToken.Provider} + ) + // Deposit the bridged token into the signer's vault + self.receiver.deposit(from: <-vault) + // Destroy the ScopedFTProvider + destroy self.scopedProvider + } +} diff --git a/cadence/transactions/bridge/tokens/bridge_tokens_to_evm.cdc b/cadence/transactions/bridge/tokens/bridge_tokens_to_evm.cdc new file mode 100644 index 00000000..8f75b2f5 --- /dev/null +++ b/cadence/transactions/bridge/tokens/bridge_tokens_to_evm.cdc @@ -0,0 +1,89 @@ +import "FungibleToken" +import "ViewResolver" +import "FungibleTokenMetadataViews" +import "FlowToken" + +import "ScopedFTProviders" + +import "EVM" + +import "FlowEVMBridge" +import "FlowEVMBridgeConfig" +import "FlowEVMBridgeUtils" + +/// Bridges a Vault from the signer's storage to the signer's COA in EVM.Account. +/// +/// NOTE: The Vault being bridged must have first been onboarded to the bridge. This can be checked for with the method +/// FlowEVMBridge.typeRequiresOnboarding(type): Bool? +/// +/// @param tokenContractAddress: The Flow account address hosting the FT-defining Cadence contract +/// @param tokenContractName: The name of the Vault-defining Cadence contract +/// @param amount: The amount of tokens to bridge from EVM +/// +transaction(tokenContractAddress: Address, tokenContractName: String, amount: UFix64) { + + let sentVault: @{FungibleToken.Vault} + let coa: auth(EVM.Bridge) &EVM.CadenceOwnedAccount + let scopedProvider: @ScopedFTProviders.ScopedFTProvider + + prepare(signer: auth(CopyValue, BorrowValue, IssueStorageCapabilityController, PublishCapability, SaveValue) &Account) { + /* --- Reference the signer's CadenceOwnedAccount --- */ + // + // Borrow a reference to the signer's COA + self.coa = signer.storage.borrow(from: /storage/evm) + ?? panic("Could not borrow COA from provided gateway address") + + /* --- Retrieve the funds --- */ + // + // Borrow a reference to the FungibleToken Vault + let viewResolver = getAccount(tokenContractAddress).contracts.borrow<&{ViewResolver}>(name: tokenContractName) + ?? panic("Could not borrow ViewResolver from FungibleToken contract") + let vaultData = viewResolver.resolveContractView( + resourceType: nil, + viewType: Type() + ) as! FungibleTokenMetadataViews.FTVaultData? ?? panic("Could not resolve FTVaultData view") + let vault = signer.storage.borrow( + from: vaultData.storagePath + ) ?? panic("Could not access signer's FungibleToken Vault") + + // Withdraw the requested balance & calculate the approximate bridge fee based on storage usage + let currentStorageUsage = signer.storage.used + self.sentVault <- vault.withdraw(amount: amount) + let withdrawnStorageUsage = signer.storage.used + // Approximate the bridge fee based on the difference in storage usage with some buffer + let approxFee = FlowEVMBridgeUtils.calculateBridgeFee( + used: currentStorageUsage - withdrawnStorageUsage, + includeBase: true + ) * 1.10 + + /* --- Configure a ScopedFTProvider --- */ + // + // Issue and store bridge-dedicated Provider Capability in storage if necessary + if signer.storage.type(at: FlowEVMBridgeConfig.providerCapabilityStoragePath) == nil { + let providerCap = signer.capabilities.storage.issue( + /storage/flowTokenVault + ) + signer.storage.save(providerCap, to: FlowEVMBridgeConfig.providerCapabilityStoragePath) + } + // Copy the stored Provider capability and create a ScopedFTProvider + let providerCapCopy = signer.storage.copy>( + from: FlowEVMBridgeConfig.providerCapabilityStoragePath + ) ?? panic("Invalid Provider Capability found in storage.") + let providerFilter = ScopedFTProviders.AllowanceFilter(approxFee) + self.scopedProvider <- ScopedFTProviders.createScopedFTProvider( + provider: providerCapCopy, + filters: [ providerFilter ], + expiration: getCurrentBlock().timestamp + 1.0 + ) + } + + execute { + // Execute the bridge + self.coa.depositTokens( + vault: <-self.sentVault, + feeProvider: &self.scopedProvider as auth(FungibleToken.Withdraw) &{FungibleToken.Provider} + ) + // Destroy the ScopedFTProvider + destroy self.scopedProvider + } +} diff --git a/cadence/transactions/example-assets/evm-assets/mint_erc20.cdc b/cadence/transactions/example-assets/evm-assets/mint_erc20.cdc new file mode 100644 index 00000000..311c80ff --- /dev/null +++ b/cadence/transactions/example-assets/evm-assets/mint_erc20.cdc @@ -0,0 +1,36 @@ +import "EVM" + +import "FlowEVMBridgeUtils" + +transaction( + recipientHexAddress: String, + amount: UInt256, + erc20HexAddress: String, + gasLimit: UInt64 +) { + + let coa: auth(EVM.Call) &EVM.CadenceOwnedAccount + + prepare(signer: auth(BorrowValue) &Account) { + self.coa = signer.storage.borrow(from: /storage/evm) + ?? panic("Signer does not have a COA in storage") + } + + execute { + let recipientAddress = FlowEVMBridgeUtils.getEVMAddressFromHexString(address: recipientHexAddress) + ?? panic("Invalid recipient address") + let erc20Address = FlowEVMBridgeUtils.getEVMAddressFromHexString(address: erc20HexAddress) + ?? panic("Invalid ERC20 address") + let calldata = EVM.encodeABIWithSignature( + "mint(address,uint256)", + [recipientAddress, amount] + ) + let callResult = self.coa.call( + to: erc20Address, + data: calldata, + gasLimit: gasLimit, + value: EVM.Balance(attoflow: 0) + ) + assert(callResult.status == EVM.Status.successful, message: "ERC20 mint failed with code: ".concat(callResult.errorCode.toString())) + } +} diff --git a/cadence/transactions/example-assets/safe_mint_erc721.cdc b/cadence/transactions/example-assets/evm-assets/safe_mint_erc721.cdc similarity index 100% rename from cadence/transactions/example-assets/safe_mint_erc721.cdc rename to cadence/transactions/example-assets/evm-assets/safe_mint_erc721.cdc diff --git a/cadence/transactions/example-assets/mint_nft.cdc b/cadence/transactions/example-assets/example-nft/mint_nft.cdc similarity index 100% rename from cadence/transactions/example-assets/mint_nft.cdc rename to cadence/transactions/example-assets/example-nft/mint_nft.cdc diff --git a/cadence/transactions/example-assets/setup_collection.cdc b/cadence/transactions/example-assets/example-nft/setup_collection.cdc similarity index 100% rename from cadence/transactions/example-assets/setup_collection.cdc rename to cadence/transactions/example-assets/example-nft/setup_collection.cdc diff --git a/cadence/transactions/example-assets/example-token/mint_tokens.cdc b/cadence/transactions/example-assets/example-token/mint_tokens.cdc new file mode 100644 index 00000000..a4e99fea --- /dev/null +++ b/cadence/transactions/example-assets/example-token/mint_tokens.cdc @@ -0,0 +1,49 @@ +import "FungibleToken" +import "ExampleToken" +import "FungibleTokenMetadataViews" + +/// This transaction is what the minter Account uses to mint new ExampleTokens +/// They provide the recipient address and amount to mint, and the tokens +/// are transferred to the address after minting + +transaction(recipient: Address, amount: UFix64) { + + /// Reference to the Example Token Minter Resource object + let tokenMinter: &ExampleToken.Minter + + /// Reference to the Fungible Token Receiver of the recipient + let tokenReceiver: &{FungibleToken.Receiver} + + /// The total supply of tokens before the burn + let supplyBefore: UFix64 + + prepare(signer: auth(BorrowValue) &Account) { + self.supplyBefore = ExampleToken.totalSupply + + // Borrow a reference to the admin object + self.tokenMinter = signer.storage.borrow<&ExampleToken.Minter>(from: ExampleToken.AdminStoragePath) + ?? panic("Signer is not the token admin") + + let vaultData = ExampleToken.resolveContractView( + resourceType: nil, + viewType: Type() + ) as! FungibleTokenMetadataViews.FTVaultData? + ?? panic("Could not get vault data view for the contract") + + self.tokenReceiver = getAccount(recipient).capabilities.borrow<&{FungibleToken.Receiver}>(vaultData.receiverPath) + ?? panic("Could not borrow receiver reference to the Vault") + } + + execute { + + // Create mint tokens + let mintedVault <- self.tokenMinter.mintTokens(amount: amount) + + // Deposit them to the receiever + self.tokenReceiver.deposit(from: <-mintedVault) + } + + post { + ExampleToken.totalSupply == self.supplyBefore + amount: "The total supply must be increased by the amount" + } +} \ No newline at end of file diff --git a/cadence/transactions/example-assets/example-token/setup_vault.cdc b/cadence/transactions/example-assets/example-token/setup_vault.cdc new file mode 100644 index 00000000..b7f5a7cc --- /dev/null +++ b/cadence/transactions/example-assets/example-token/setup_vault.cdc @@ -0,0 +1,42 @@ +// This transaction is a template for a transaction to allow +// anyone to add a Vault resource to their account so that +// they can use the exampleToken + +import "FungibleToken" +import "ExampleToken" +import "ViewResolver" +import "FungibleTokenMetadataViews" + +transaction () { + + prepare(signer: auth(BorrowValue, IssueStorageCapabilityController, PublishCapability, SaveValue) &Account) { + + let vaultData = ExampleToken.resolveContractView( + resourceType: nil, + viewType: Type() + ) as! FungibleTokenMetadataViews.FTVaultData? + ?? panic("ViewResolver does not resolve FTVaultData view") + + // Return early if the account already stores a ExampleToken Vault + if signer.storage.borrow<&ExampleToken.Vault>(from: vaultData.storagePath) != nil { + return + } + + let vault <- ExampleToken.createEmptyVault(vaultType: Type<@ExampleToken.Vault>()) + + // Create a new ExampleToken Vault and put it in storage + signer.storage.save(<-vault, to: vaultData.storagePath) + + // Create a public capability to the Vault that exposes the Vault interfaces + let vaultCap = signer.capabilities.storage.issue<&ExampleToken.Vault>( + vaultData.storagePath + ) + signer.capabilities.publish(vaultCap, at: vaultData.metadataPath) + + // Create a public Capability to the Vault's Receiver functionality + let receiverCap = signer.capabilities.storage.issue<&ExampleToken.Vault>( + vaultData.storagePath + ) + signer.capabilities.publish(receiverCap, at: vaultData.receiverPath) + } +} \ No newline at end of file diff --git a/cadence/transactions/example-assets/example-token/transfer_tokens.cdc b/cadence/transactions/example-assets/example-token/transfer_tokens.cdc new file mode 100644 index 00000000..213fe166 --- /dev/null +++ b/cadence/transactions/example-assets/example-token/transfer_tokens.cdc @@ -0,0 +1,48 @@ +// This transaction is a template for a transaction that +// could be used by anyone to send ExampleTokens to another +// account that has been set up to receive tokens. +// +// The withdraw amount and the account from getAccount +// would be the parameters to the transaction + +import "FungibleToken" +import "ExampleToken" +import "FungibleTokenMetadataViews" + +transaction(amount: UFix64, to: Address) { + + /// FTVaultData metadata view for the token being used + let vaultData: FungibleTokenMetadataViews.FTVaultData + + // The Vault resource that holds the tokens that are being transferred + let sentVault: @{FungibleToken.Vault} + + prepare(signer: auth(BorrowValue) &Account) { + + self.vaultData = ExampleToken.resolveContractView( + resourceType: nil, + viewType: Type() + ) as! FungibleTokenMetadataViews.FTVaultData? + ?? panic("ViewResolver does not resolve FTVaultData view") + + // Get a reference to the signer's stored vault + let vaultRef = signer.storage.borrow(from: self.vaultData.storagePath) + ?? panic("Could not borrow reference to the owner's Vault!") + + // Withdraw tokens from the signer's stored vault + self.sentVault <- vaultRef.withdraw(amount: amount) + } + + execute { + + // Get the recipient's public account object + let recipient = getAccount(to) + + // Get a reference to the recipient's Receiver + let receiverRef = recipient.capabilities.borrow<&{FungibleToken.Receiver}>(self.vaultData.receiverPath) + ?? panic("Could not borrow receiver reference to the recipient's Vault") + + // Deposit the withdrawn tokens in the recipient's receiver + receiverRef.deposit(from: <-self.sentVault) + } +} \ No newline at end of file diff --git a/cadence/transactions/test/deploy_using_evm_deployer.cdc b/cadence/transactions/test/deploy_using_evm_deployer.cdc new file mode 100644 index 00000000..4421e777 --- /dev/null +++ b/cadence/transactions/test/deploy_using_evm_deployer.cdc @@ -0,0 +1,9 @@ +import "EVMDeployer" + +transaction(name: String, bytecode: String, value: UInt) { + prepare(signer: &Account) {} + + execute { + EVMDeployer.deploy(name: name, bytecode: bytecode, value: value) + } +} diff --git a/flow.json b/flow.json index 3a4c2468..2bb21620 100644 --- a/flow.json +++ b/flow.json @@ -19,7 +19,7 @@ "aliases": { "emulator": "ee82856bf20e2aa6", "previewnet": "b6763b4399a888c8", - "testing": "0000000000000007" + "testing": "0000000000000001" } }, "CrossVMNFT": { @@ -29,6 +29,13 @@ "testing": "0000000000000007" } }, + "CrossVMToken": { + "source": "./cadence/contracts/bridge/CrossVMToken.cdc", + "aliases": { + "emulator": "f8d6e0586b0a20c7", + "testing": "0000000000000007" + } + }, "EVM": { "source": "./cadence/contracts/standards/EVM.cdc", "aliases": { @@ -36,11 +43,11 @@ "previewnet": "b6763b4399a888c8" } }, - "EVMBridgeRouter": { - "source": "./cadence/contracts/bridge/EVMBridgeRouter.cdc", + "FlowEVMBridgeAccessor": { + "source": "./cadence/contracts/bridge/FlowEVMBridgeAccessor.cdc", "aliases": { "emulator": "f8d6e0586b0a20c7", - "testing": "0000000000000001" + "testing": "0000000000000007" } }, "EVMDeployer": { @@ -57,6 +64,13 @@ "testing": "0000000000000008" } }, + "ExampleToken": { + "source": "./cadence/contracts/example-assets/ExampleToken.cdc", + "aliases": { + "emulator": "179b6b1cb6755e31", + "testing": "0000000000000010" + } + }, "FlowEVMBridge": { "source": "./cadence/contracts/bridge/FlowEVMBridge.cdc", "aliases": { @@ -85,6 +99,13 @@ "testing": "0000000000000007" } }, + "FlowEVMBridgeTokenEscrow": { + "source": "./cadence/contracts/bridge/FlowEVMBridgeTokenEscrow.cdc", + "aliases": { + "emulator": "f8d6e0586b0a20c7", + "testing": "0000000000000007" + } + }, "FlowEVMBridgeUtils": { "source": "./cadence/contracts/bridge/FlowEVMBridgeUtils.cdc", "aliases": { @@ -117,7 +138,7 @@ "emulator": "f8d6e0586b0a20c7", "mainnet": "f233dcee88fe0abe", "previewnet": "a0225e7000ac82a9", - "testing": "0000000000000007", + "testing": "0000000000000002", "testnet": "9a0766d93b6608b7" } }, @@ -135,6 +156,13 @@ "testing": "0000000000000007" } }, + "IEVMBridgeTokenMinter": { + "source": "./cadence/contracts/bridge/IEVMBridgeTokenMinter.cdc", + "aliases": { + "emulator": "f8d6e0586b0a20c7", + "testing": "0000000000000007" + } + }, "IFlowEVMNFTBridge": { "source": "./cadence/contracts/bridge/IFlowEVMNFTBridge.cdc", "aliases": { @@ -142,6 +170,13 @@ "testing": "0000000000000007" } }, + "IFlowEVMTokenBridge": { + "source": "./cadence/contracts/bridge/IFlowEVMTokenBridge.cdc", + "aliases": { + "emulator": "f8d6e0586b0a20c7", + "testing": "0000000000000007" + } + }, "MetadataViews": { "source": "./cadence/contracts/standards/MetadataViews.cdc", "aliases": { diff --git a/local/normalize_coverage_report.sh b/local/normalize_coverage_report.sh index 6d19dfb4..494d78a7 100644 --- a/local/normalize_coverage_report.sh +++ b/local/normalize_coverage_report.sh @@ -3,9 +3,15 @@ sed -i 's/A.0000000000000007.SerializeNFT/cadence\contracts\/SerializeNFT.cdc/' sed -i 's/A.0000000000000007.BridgePermissions/cadence\/contracts\/bridge\/BridgePermissions.cdc/' coverage.lcov sed -i 's/A.0000000000000007.ICrossVM/cadence\/contracts\/bridge\/ICrossVM.cdc/' coverage.lcov sed -i 's/A.0000000000000007.CrossVMNFT/cadence\/contracts\/bridge\/CrossVMNFT.cdc/' coverage.lcov +sed -i 's/A.0000000000000007.CrossVMToken/cadence\/contracts\/bridge\/CrossVMToken.cdc/' coverage.lcov sed -i 's/A.0000000000000007.FlowEVMBridgeConfig/cadence\/contracts\/bridge\/FlowEVMBridgeConfig.cdc/' coverage.lcov sed -i 's/A.0000000000000007.FlowEVMBridgeUtils/cadence\/contracts\/bridge\/FlowEVMBridgeUtils.cdc/' coverage.lcov +sed -i 's/A.0000000000000007.FlowEVMBridgeNFTEscrow/cadence\/contracts\/bridge\/FlowEVMBridgeNFTEscrow.cdc/' coverage.lcov +sed -i 's/A.0000000000000007.FlowEVMBridgeTokenEscrow/cadence\/contracts\/bridge\/FlowEVMBridgeTokenEscrow.cdc/' coverage.lcov sed -i 's/A.0000000000000007.FlowEVMBridgeTemplates/cadence\/contracts\/bridge\/FlowEVMBridgeTemplates.cdc/' coverage.lcov -sed -i 's/A.0000000000000007.IFlowEVMNFTBridge/cadence\/contracts\/bridge\/FlowEVMBridge.cdc/' coverage.lcov +sed -i 's/A.0000000000000007.IEVMBridgeNFTMinter/cadence\/contracts\/bridge\/IEVMBridgeNFTMinter.cdc/' coverage.lcov +sed -i 's/A.0000000000000007.IEVMBridgeTokenMinter/cadence\/contracts\/bridge\/IEVMBridgeTokenMinter.cdc/' coverage.lcov +sed -i 's/A.0000000000000007.IFlowEVMNFTBridge/cadence\/contracts\/bridge\/IFlowEVMNFTBridge.cdc/' coverage.lcov +sed -i 's/A.0000000000000007.IFlowEVMTokenBridge/cadence\/contracts\/bridge\/IFlowEVMTokenBridge.cdc/' coverage.lcov sed -i 's/A.0000000000000007.FlowEVMBridge/cadence\/contracts\/bridge\/FlowEVMBridge.cdc/' coverage.lcov sed -i 's/A.0000000000000007.EVMBridgeRouter/cadence\/contracts\/bridge\/EVMBridgeRouter.cdc/' coverage.lcov \ No newline at end of file diff --git a/local/setup_emulator.1.sh b/local/setup_emulator.1.sh index 33aea94f..58c1dfe8 100644 --- a/local/setup_emulator.1.sh +++ b/local/setup_emulator.1.sh @@ -1,36 +1,36 @@ #!/bin/bash # Create COA in emulator-account -flow transactions send ./cadence/transactions/evm/create_account.cdc 100.0 +flow-c1 transactions send ./cadence/transactions/evm/create_account.cdc 100.0 # Deploy supporting utils -flow accounts add-contract ./cadence/contracts/utils/ArrayUtils.cdc -flow accounts add-contract ./cadence/contracts/utils/StringUtils.cdc -flow accounts add-contract ./cadence/contracts/utils/ScopedFTProviders.cdc -flow accounts add-contract ./cadence/contracts/utils/Serialize.cdc -flow accounts add-contract ./cadence/contracts/utils/SerializeNFT.cdc +flow-c1 accounts add-contract ./cadence/contracts/utils/ArrayUtils.cdc +flow-c1 accounts add-contract ./cadence/contracts/utils/StringUtils.cdc +flow-c1 accounts add-contract ./cadence/contracts/utils/ScopedFTProviders.cdc +flow-c1 accounts add-contract ./cadence/contracts/utils/Serialize.cdc +flow-c1 accounts add-contract ./cadence/contracts/utils/SerializeNFT.cdc -flow accounts update-contract ./cadence/contracts/standards/EVM.cdc +flow-c1 accounts update-contract ./cadence/contracts/standards/EVM.cdc # Deploy initial bridge contracts -flow accounts add-contract ./cadence/contracts/bridge/BridgePermissions.cdc -flow accounts add-contract ./cadence/contracts/bridge/ICrossVM.cdc -flow accounts add-contract ./cadence/contracts/bridge/CrossVMNFT.cdc -flow accounts add-contract ./cadence/contracts/bridge/FlowEVMBridgeConfig.cdc +flow-c1 accounts add-contract ./cadence/contracts/bridge/BridgePermissions.cdc +flow-c1 accounts add-contract ./cadence/contracts/bridge/ICrossVM.cdc +flow-c1 accounts add-contract ./cadence/contracts/bridge/CrossVMNFT.cdc +flow-c1 accounts add-contract ./cadence/contracts/bridge/FlowEVMBridgeConfig.cdc # Deploy FlowEVMBridgeUtils also deploying FlowEVMBridgeFactory to EVM in init -flow accounts add-contract ./cadence/contracts/bridge/FlowEVMBridgeUtils.cdc \ +flow-c1 accounts add-contract ./cadence/contracts/bridge/FlowEVMBridgeUtils.cdc \ --args-json "$(cat ./cadence/args/deploy-factory-args.json)" -flow accounts add-contract ./cadence/contracts/bridge/FlowEVMBridgeNFTEscrow.cdc -flow accounts add-contract ./cadence/contracts/bridge/FlowEVMBridgeTemplates.cdc +flow-c1 accounts add-contract ./cadence/contracts/bridge/FlowEVMBridgeNFTEscrow.cdc +flow-c1 accounts add-contract ./cadence/contracts/bridge/FlowEVMBridgeTemplates.cdc # Add the templated contract code chunks for FlowEVMBridgedNFTTemplate.cdc contents -flow transactions send ./cadence/transactions/bridge/admin/upsert_contract_code_chunks.cdc \ +flow-c1 transactions send ./cadence/transactions/bridge/admin/upsert_contract_code_chunks.cdc \ --args-json "$(cat ./cadence/args/bridged-nft-code-chunks-args.json)" --gas-limit 1600 -flow accounts add-contract ./cadence/contracts/bridge/IEVMBridgeNFTMinter.cdc +flow-c1 accounts add-contract ./cadence/contracts/bridge/IEVMBridgeNFTMinter.cdc # Deploy main bridge interface & contract -flow accounts add-contract ./cadence/contracts/bridge/IFlowEVMNFTBridge.cdc -flow accounts add-contract ./cadence/contracts/bridge/FlowEVMBridge.cdc +flow-c1 accounts add-contract ./cadence/contracts/bridge/IFlowEVMNFTBridge.cdc +flow-c1 accounts add-contract ./cadence/contracts/bridge/FlowEVMBridge.cdc diff --git a/local/setup_emulator.2.sh b/local/setup_emulator.2.sh index 3d041cdd..91a6a674 100644 --- a/local/setup_emulator.2.sh +++ b/local/setup_emulator.2.sh @@ -1,39 +1,39 @@ # Deploy the bridge router directing calls from COAs to the dedicated bridge -flow accounts add-contract ./cadence/contracts/bridge/EVMBridgeRouter.cdc 0xf8d6e0586b0a20c7 FlowEVMBridge +flow-c1 accounts add-contract ./cadence/contracts/bridge/EVMBridgeRouter.cdc 0xf8d6e0586b0a20c7 FlowEVMBridge # Create `example-nft` account 179b6b1cb6755e31 with private key 96dfbadf086daa187100a24b1fd2b709b702954bbd030a394148e11bcbb799ef -flow accounts create --key "351e1310301a7374430f6077d7b1b679c9574f8e045234eac09568ceb15c4f5d937104b4c3180df1e416da20c9d58aac576ffc328a342198a5eae4a29a13c47a" +flow-c1 accounts create --key "351e1310301a7374430f6077d7b1b679c9574f8e045234eac09568ceb15c4f5d937104b4c3180df1e416da20c9d58aac576ffc328a342198a5eae4a29a13c47a" # Create `user` account 0xf3fcd2c1a78f5eee with private key bce84aae316aec618888e5bdd24a3c8b8af46896c1ebe457e2f202a4a9c43075 -flow accounts create --key "c695fa608bd40821552fae13bb710c917309690ed69c22866abad19d276c99296379358321d0123d7074c817dd646ae8f651734526179eaed9f33eba16601ff6" +flow-c1 accounts create --key "c695fa608bd40821552fae13bb710c917309690ed69c22866abad19d276c99296379358321d0123d7074c817dd646ae8f651734526179eaed9f33eba16601ff6" # Create `erc721` account 0xe03daebed8ca0615 with private key bf602a4cdffb5610a008622f6601ba7059f8a6f533d7489457deb3d45875acb0 -flow accounts create --key "9103fd9106a83a2ede667e2486848e13e5854ea512af9bbec9ad2aec155bd5b5c146b53a6c3fd619c591ae0cd730acb875e5b6e074047cf31d620b53c55a4fb4" +flow-c1 accounts create --key "9103fd9106a83a2ede667e2486848e13e5854ea512af9bbec9ad2aec155bd5b5c146b53a6c3fd619c591ae0cd730acb875e5b6e074047cf31d620b53c55a4fb4" # Give the user some FLOW -flow transactions send ./cadence/transactions/flow-token/transfer_flow.cdc 0xf3fcd2c1a78f5eee 100.0 +flow-c1 transactions send ./cadence/transactions/flow-token/transfer_flow.cdc 0xf3fcd2c1a78f5eee 100.0 # Give the erc721 some FLOW -flow transactions send ./cadence/transactions/flow-token/transfer_flow.cdc 0xe03daebed8ca0615 100.0 +flow-c1 transactions send ./cadence/transactions/flow-token/transfer_flow.cdc 0xe03daebed8ca0615 100.0 # Create a COA for the user -flow transactions send ./cadence/transactions/evm/create_account.cdc 10.0 --signer user +flow-c1 transactions send ./cadence/transactions/evm/create_account.cdc 10.0 --signer user # Create a COA for the erc721 -flow transactions send ./cadence/transactions/evm/create_account.cdc 10.0 --signer erc721 +flow-c1 transactions send ./cadence/transactions/evm/create_account.cdc 10.0 --signer erc721 -# user transfers Flow to the COA -flow transactions send ./cadence/transactions/evm/deposit.cdc 10.0 --signer user +# user transfers Flow-c1 to the COA +flow-c1 transactions send ./cadence/transactions/evm/deposit.cdc 10.0 --signer user -# erc721 transfers Flow to the COA -flow transactions send ./cadence/transactions/evm/deposit.cdc 10.0 --signer erc721 +# erc721 transfers Flow-c1 to the COA +flow-c1 transactions send ./cadence/transactions/evm/deposit.cdc 10.0 --signer erc721 # Setup User with Example NFT collection - Will break flow.json config due to bug in CLI - break here and update flow.json manually -flow accounts add-contract ./cadence/contracts/example-assets/ExampleNFT.cdc --signer example-nft +flow-c1 accounts add-contract ./cadence/contracts/example-assets/ExampleNFT.cdc --signer example-nft -flow transactions send ./cadence/transactions/example-assets/setup_collection.cdc --signer user -flow transactions send ./cadence/transactions/example-assets/mint_nft.cdc f3fcd2c1a78f5eee example description thumbnail '[]' '[]' '[]' --signer example-nft +flow-c1 transactions send ./cadence/transactions/example-assets/setup_collection.cdc --signer user +flow-c1 transactions send ./cadence/transactions/example-assets/mint_nft.cdc f3fcd2c1a78f5eee example description thumbnail '[]' '[]' '[]' --signer example-nft # Deploy ExampleERC721 contract with erc721's COA as owner - NOTE THE `deployedContractAddress` EMITTED IN THE RESULTING EVENT -flow transactions send ./cadence/transactions/evm/deploy.cdc \ +flow-c1 transactions send ./cadence/transactions/evm/deploy.cdc \ --args-json "$(cat ./cadence/args/deploy-erc721-args.json)" --signer erc721 \ No newline at end of file diff --git a/local/setup_emulator.3.sh b/local/setup_emulator.3.sh index 0b7f6054..6485be51 100644 --- a/local/setup_emulator.3.sh +++ b/local/setup_emulator.3.sh @@ -1,4 +1,4 @@ # Mint an ERC721 with ID 42 to the user's COA -flow transactions send ./cadence/transactions/example-assets/safe_mint_erc721.cdc \ +flow-c1 transactions send ./cadence/transactions/example-assets/safe_mint_erc721.cdc \ 42 "URI" 200000 \ --signer erc721 diff --git a/solidity/src/ExampleERC20.sol b/solidity/src/ExampleERC20.sol new file mode 100644 index 00000000..78fe9cc1 --- /dev/null +++ b/solidity/src/ExampleERC20.sol @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: MIT +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"; + +contract ExampleERC20 is ERC20, ERC20Burnable, Ownable, ERC20Permit { + constructor() ERC20("NAME", "SYMBOL") Ownable(msg.sender) ERC20Permit("NAME") {} + + function mint(address to, uint256 amount) public onlyOwner { + _mint(to, amount); + } +} diff --git a/solidity/src/FlowBridgeFactory.sol b/solidity/src/FlowBridgeFactory.sol index ebc3017d..dee9ee75 100644 --- a/solidity/src/FlowBridgeFactory.sol +++ b/solidity/src/FlowBridgeFactory.sol @@ -2,7 +2,10 @@ 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 "./FlowBridgedERC721.sol"; +import "./FlowBridgedERC20.sol"; import "./IBridgePermissions.sol"; contract FlowBridgeFactory is Ownable { @@ -11,10 +14,32 @@ contract FlowBridgeFactory is Ownable { 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); + + return address(newERC20); + } + // Function to deploy a new ERC721 contract function deployERC721( string memory name, @@ -46,7 +71,40 @@ contract FlowBridgeFactory is Ownable { return bytes(contractToflowIdentifier[contractAddr]).length != 0; } + function isERC20(address contractAddr) public view returns (bool) { + (bool success, bytes memory data) = contractAddr.staticcall(abi.encodeWithSignature("totalSupply()")); + if (!success || data.length == 0) { + return false; + } + (success, data) = contractAddr.staticcall(abi.encodeWithSignature("balanceOf(address)", address(0))); + if (!success || data.length == 0) { + return false; + } + (success, data) = + contractAddr.staticcall(abi.encodeWithSignature("allowance(address,address)", address(0), address(0))); + if (!success || data.length == 0) { + return false; + } + (success, data) = contractAddr.staticcall(abi.encodeWithSignature("name()")); + if (!success || data.length == 0) { + return false; + } + (success, data) = contractAddr.staticcall(abi.encodeWithSignature("symbol()")); + if (!success || data.length == 0) { + return false; + } + (success, data) = contractAddr.staticcall(abi.encodeWithSignature("decimals()")); + if (!success || data.length == 0) { + return false; + } + return true; + } + function isERC721(address contractAddr) public view returns (bool) { - return ERC165(contractAddr).supportsInterface(0x80ac58cd); + try ERC165(contractAddr).supportsInterface(0x80ac58cd) returns (bool support) { + return support; + } catch { + return false; + } } } diff --git a/solidity/src/FlowBridgedERC20.sol b/solidity/src/FlowBridgedERC20.sol new file mode 100644 index 00000000..a8deb0a2 --- /dev/null +++ b/solidity/src/FlowBridgedERC20.sol @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: MIT +// 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"; + +contract FlowBridgedERC20 is ERC20, ERC20Burnable, Ownable, ERC20Permit { + string public flowTokenAddress; + string public flowTokenIdentifier; + string public contractMetadata; + + constructor( + address owner, + string memory name, + string memory symbol, + string memory _flowTokenAddress, + string memory _flowTokenIdentifier, + string memory _contractMetadata + ) ERC20(name, symbol) Ownable(owner) ERC20Permit(name) { + flowTokenAddress = _flowTokenAddress; + flowTokenIdentifier = _flowTokenIdentifier; + contractMetadata = _contractMetadata; + } + + function mint(address to, uint256 amount) public onlyOwner { + _mint(to, amount); + } + + function getFlowTokenAddress() public view returns (string memory) { + return flowTokenAddress; + } + + function getFlowTokenIdentifier() public view returns (string memory) { + return flowTokenIdentifier; + } + + function contractURI() public view returns (string memory) { + return contractMetadata; + } +} diff --git a/solidity/test/FlowBridgeFactory.t.sol b/solidity/test/FlowBridgeFactory.t.sol index 05d6e73a..f826cc79 100644 --- a/solidity/test/FlowBridgeFactory.t.sol +++ b/solidity/test/FlowBridgeFactory.t.sol @@ -5,17 +5,22 @@ import {Test} from "forge-std/Test.sol"; import {FlowBridgeFactory} from "../src/FlowBridgeFactory.sol"; import {FlowBridgedERC721} from "../src/FlowBridgedERC721.sol"; +import {FlowBridgedERC20} from "../src/FlowBridgedERC20.sol"; contract FlowBridgeFactoryTest is Test { FlowBridgeFactory internal factory; FlowBridgedERC721 internal deployedERC721Contract; + FlowBridgedERC20 internal deployedERC20Contract; string name; string symbol; string flowNFTAddress; string flowNFTIdentifier; + string flowTokenAddress; + string flowTokenIdentifier; string contractURI; address deployedERC721Address; + address deployedERC20Address; function setUp() public virtual { factory = new FlowBridgeFactory(); @@ -23,10 +28,14 @@ contract FlowBridgeFactoryTest is Test { symbol = "symbol"; flowNFTAddress = "flowNFTAddress"; flowNFTIdentifier = "flowNFTIdentifier"; + flowTokenAddress = "flowTokenAddress"; + 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); } function test_DeployERC721() public { @@ -34,14 +43,39 @@ contract FlowBridgeFactoryTest is Test { assertEq(isFactoryDeployed, true); } + function test_IsERC721True() public { + bool isERC721 = factory.isERC721(deployedERC721Address); + assertEq(isERC721, true); + } + + function test_IsERC721False() public { + bool isERC721 = factory.isERC721(deployedERC20Address); + assertEq(isERC721, false); + } + + function test_DeployERC20() public { + bool isFactoryDeployed = factory.isFactoryDeployed(deployedERC20Address); + assertEq(isFactoryDeployed, true); + } + + function test_IsERC20True() public { + bool isERC20 = factory.isERC20(deployedERC20Address); + assertEq(isERC20, true); + } + + function test_IsERC20False() public { + bool isERC20 = factory.isERC20(deployedERC721Address); + assertEq(isERC20, false); + } + function test_ValidateDeployedERC721Address() public { - string memory actualName = deployedERC721Contract.name(); + string memory _name = deployedERC721Contract.name(); string memory _symbol = deployedERC721Contract.symbol(); string memory _flowNFTAddress = deployedERC721Contract.flowNFTAddress(); string memory _flowNFTIdentifier = deployedERC721Contract.flowNFTIdentifier(); string memory _contractURI = deployedERC721Contract.contractURI(); - assertEq(actualName, name); + assertEq(_name, name); assertEq(_symbol, symbol); assertEq(_flowNFTAddress, flowNFTAddress); assertEq(_flowNFTIdentifier, flowNFTIdentifier); @@ -52,6 +86,24 @@ contract FlowBridgeFactoryTest is Test { assertEq(factoryOwner, erc721Owner); } + function test_ValidateDeployedERC20Address() public { + string memory _name = deployedERC20Contract.name(); + string memory _symbol = deployedERC20Contract.symbol(); + string memory _flowTokenAddress = deployedERC20Contract.getFlowTokenAddress(); + string memory _flowTokenIdentifier = deployedERC20Contract.flowTokenIdentifier(); + string memory _contractURI = deployedERC20Contract.contractURI(); + + assertEq(_name, name); + assertEq(_symbol, symbol); + assertEq(_flowTokenAddress, flowTokenAddress); + assertEq(_flowTokenIdentifier, flowTokenIdentifier); + assertEq(_contractURI, contractURI); + + address factoryOwner = factory.owner(); + address erc20Owner = deployedERC20Contract.owner(); + assertEq(factoryOwner, erc20Owner); + } + function test_SuccessfulMint() public { address recipient = address(27); uint256 tokenId = 42;