From 9930536a20019041ded2f5e9c0a8c4c324f0601e Mon Sep 17 00:00:00 2001 From: Xiao Yi <369713644@qq.com> Date: Thu, 8 Jun 2023 15:45:17 +0800 Subject: [PATCH] . --- .DS_Store | Bin 0 -> 6148 bytes README.md | 82 + discord-export/.DS_Store | Bin 0 -> 8196 bytes ...1 - swivel-sep30 [892486622401159260].html | 1504 ++++++++++++ .../-MUa9tmyPufyVGMmAkKT-437CE.png | 0 .../1f389-28196.svg | 1 + .../1f44b-9E658.svg | 1 + .../1f44d-B3F5F.svg | 1 + .../1f604-6061B.svg | 1 + .../1f606-6F8AE.svg | 1 + .../1f60b-69108.svg | 1 + .../2-ADBB4.png | Bin 0 -> 1325 bytes ...3026b81d5ab56c4d2a773cb9b5dbd3a5-8CB58.png | Bin 0 -> 6783 bytes .../797886789380866079-D181A.png | Bin 0 -> 16796 bytes .../862404106545922051-D26C2.gif | Bin 0 -> 91182 bytes .../892635967494692896-61FB3.gif | Bin 0 -> 19019 bytes .../892635968027394048-5E523.gif | Bin 0 -> 22391 bytes ...en_Shot_2021-09-29_at_5.52.46_PM-DA8FF.png | Bin 0 -> 101230 bytes ...ae0c30c4cbe01bb2000b3d3094ea7e82-F120E.png | Bin 0 -> 42196 bytes ...cec17fe3825e83ddf170d7e8c98ece3e-B6D17.png | Bin 0 -> 27797 bytes ...df4391e9033659fcd5fd4c01aae14551-7F4A0.png | Bin 0 -> 9079 bytes ...fd27bbac738561bc2df301737c024c66-92730.png | Bin 0 -> 15561 bytes .../gost-0F62A | Bin 0 -> 56977 bytes .../unknown-D8713.png | Bin 0 -> 12082 bytes ...21 - swivel-sep30 [892486622401159260].txt | 154 ++ .../-MUa9tmyPufyVGMmAkKT-437CE.png | 0 ...en_Shot_2021-09-29_at_5.52.46_PM-DA8FF.png | Bin 0 -> 101230 bytes .../gost-0F62A | Bin 0 -> 56977 bytes .../unknown-D8713.png | Bin 0 -> 12082 bytes gost/.DS_Store | Bin 0 -> 6148 bytes gost/.travis.yml | 4 + gost/Makefile | 229 ++ gost/README.md | 83 + gost/build/.DS_Store | Bin 0 -> 6148 bytes gost/build/marketplace/Abstracts.sol | 17 + gost/build/marketplace/CErc20.abi | 1 + gost/build/marketplace/CErc20.bin | 0 gost/build/marketplace/Erc20.abi | 1 + gost/build/marketplace/Erc20.bin | 0 gost/build/marketplace/Erc2612.abi | 1 + gost/build/marketplace/Erc2612.bin | 1 + gost/build/marketplace/Erc2612.sol | 53 + gost/build/marketplace/Hash.abi | 1 + gost/build/marketplace/Hash.bin | 1 + gost/build/marketplace/Hash.sol | 80 + gost/build/marketplace/IErc2612.abi | 1 + gost/build/marketplace/IErc2612.bin | 0 gost/build/marketplace/IErc2612.sol | 56 + gost/build/marketplace/IPErc20.abi | 1 + gost/build/marketplace/IPErc20.bin | 0 gost/build/marketplace/IPErc20.sol | 80 + gost/build/marketplace/IZcToken.abi | 1 + gost/build/marketplace/IZcToken.bin | 0 gost/build/marketplace/IZcToken.sol | 21 + gost/build/marketplace/MarketPlace.abi | 1 + gost/build/marketplace/MarketPlace.bin | 1 + gost/build/marketplace/MarketPlace.sol | 259 ++ gost/build/marketplace/PErc20.abi | 1 + gost/build/marketplace/PErc20.bin | 1 + gost/build/marketplace/PErc20.sol | 278 +++ gost/build/marketplace/VaultTracker.abi | 1 + gost/build/marketplace/VaultTracker.bin | 1 + gost/build/marketplace/VaultTracker.sol | 251 ++ gost/build/marketplace/ZcToken.abi | 1 + gost/build/marketplace/ZcToken.bin | 1 + gost/build/marketplace/ZcToken.sol | 48 + gost/build/marketplace/marketplace.go | 2083 +++++++++++++++++ gost/build/swivel/Abstracts.sol | 40 + gost/build/swivel/CErc20.abi | 1 + gost/build/swivel/CErc20.bin | 0 gost/build/swivel/Erc20.abi | 1 + gost/build/swivel/Erc20.bin | 0 gost/build/swivel/Hash.abi | 1 + gost/build/swivel/Hash.bin | 1 + gost/build/swivel/Hash.sol | 107 + gost/build/swivel/MarketPlace.abi | 1 + gost/build/swivel/MarketPlace.bin | 0 gost/build/swivel/Sig.abi | 1 + gost/build/swivel/Sig.bin | 1 + gost/build/swivel/Sig.sol | 55 + gost/build/swivel/Swivel.abi | 1 + gost/build/swivel/Swivel.bin | 1 + gost/build/swivel/Swivel.sol | 490 ++++ gost/build/swivel/swivel.go | 1382 +++++++++++ gost/go.mod | 8 + gost/go.sum | 235 ++ gost/internal/helpers/helpers.go | 90 + gost/pkg/.DS_Store | Bin 0 -> 6148 bytes gost/pkg/marketplacetesting/constants.go | 15 + .../marketplacetesting/construction_test.go | 51 + .../marketplacetesting/create_market_test.go | 135 ++ .../marketplacetesting/custodial_exit_test.go | 290 +++ .../custodial_initiate_test.go | 288 +++ gost/pkg/marketplacetesting/dep.go | 63 + gost/pkg/marketplacetesting/env.go | 52 + .../get_ctoken_address_address_test.go | 72 + .../marketplacetesting/mature_market_test.go | 277 +++ .../p2p_vault_exchange_test.go | 187 ++ .../p2p_zc_token_exchange_test.go | 147 ++ .../redeem_vault_interest_test.go | 116 + .../redeem_zc_token_test.go | 453 ++++ .../set_swivel_address_test.go | 56 + .../transfer_vault_notional_fee_test.go | 106 + .../transfer_vault_notional_test.go | 107 + gost/pkg/swiveltesting/constants.go | 12 + gost/pkg/swiveltesting/dep.go | 99 + gost/pkg/swiveltesting/env.go | 52 + .../exit_vault_filling_vault_initiate_test.go | 194 ++ .../exit_vault_filling_zctoken_exit_test.go | 218 ++ .../exit_zctoken_filling_vault_exit_test.go | 218 ++ ...t_zctoken_filling_zctoken_initiate_test.go | 196 ++ .../initiate_vault_filling_vault_exit_test.go | 196 ++ ...ate_vault_filling_zctoken_initiate_test.go | 254 ++ ...ate_zctoken_filling_vault_initiate_test.go | 235 ++ ...tiate_zctoken_filling_zctoken_exit_test.go | 194 ++ .../redeem_vault_interest_test.go | 137 ++ gost/pkg/swiveltesting/redeem_zctoken_test.go | 141 ++ .../swiveltesting/split_and_combine_test.go | 156 ++ .../swiveltesting/swivel_construction_test.go | 65 + gost/pkg/swiveltesting/withdrawal_test.go | 166 ++ gost/pkg/testing/constants.go | 9 + gost/pkg/testing/dep.go | 85 + gost/pkg/testing/env.go | 52 + gost/pkg/testing/hash_test.go | 108 + gost/pkg/testing/sig_test.go | 74 + gost/pkg/testing/token_test.go | 186 ++ .../vaulttrackertesting/add_notional_test.go | 255 ++ .../vaulttrackertesting/balances_of_test.go | 90 + gost/pkg/vaulttrackertesting/constants.go | 13 + gost/pkg/vaulttrackertesting/dep.go | 59 + gost/pkg/vaulttrackertesting/env.go | 52 + .../vaulttrackertesting/mature_vault_test.go | 104 + .../redeem_interest_test.go | 257 ++ .../remove_notional_test.go | 217 ++ .../transfer_notional_fee_test.go | 93 + .../transfer_notional_from_test.go | 138 ++ .../transfer_notional_test.go | 521 +++++ .../vault_tracker_construction_test.go | 69 + gost/test/.DS_Store | Bin 0 -> 6148 bytes gost/test/fakes/Hash.abi | 1 + gost/test/fakes/Hash.bin | 1 + gost/test/fakes/Hash.sol | 107 + gost/test/fakes/HashFake.abi | 1 + gost/test/fakes/HashFake.bin | 1 + gost/test/fakes/HashFake.sol | 65 + gost/test/fakes/Sig.abi | 1 + gost/test/fakes/Sig.bin | 1 + gost/test/fakes/Sig.sol | 55 + gost/test/fakes/SigFake.abi | 1 + gost/test/fakes/SigFake.bin | 1 + gost/test/fakes/SigFake.sol | 19 + gost/test/fakes/hashfake.go | 388 +++ gost/test/fakes/sigfake.go | 277 +++ gost/test/marketplace/Abstracts.sol | 17 + gost/test/marketplace/CErc20.abi | 1 + gost/test/marketplace/CErc20.bin | 0 gost/test/marketplace/Erc20.abi | 1 + gost/test/marketplace/Erc20.bin | 0 gost/test/marketplace/MarketPlace.abi | 1 + gost/test/marketplace/MarketPlace.bin | 1 + gost/test/marketplace/MarketPlace.sol | 259 ++ gost/test/marketplace/VaultTracker.abi | 1 + gost/test/marketplace/VaultTracker.bin | 1 + gost/test/marketplace/VaultTracker.sol | 113 + gost/test/marketplace/ZcToken.abi | 1 + gost/test/marketplace/ZcToken.bin | 1 + gost/test/marketplace/ZcToken.sol | 98 + gost/test/marketplace/marketplace.go | 2083 +++++++++++++++++ gost/test/mocks/CErc20.abi | 1 + gost/test/mocks/CErc20.bin | 1 + gost/test/mocks/CErc20.sol | 64 + gost/test/mocks/Erc20.abi | 1 + gost/test/mocks/Erc20.bin | 1 + gost/test/mocks/Erc20.sol | 74 + gost/test/mocks/MarketPlace.abi | 1 + gost/test/mocks/MarketPlace.bin | 1 + gost/test/mocks/MarketPlace.sol | 183 ++ gost/test/mocks/cerc20.go | 460 ++++ gost/test/mocks/erc20.go | 495 ++++ gost/test/mocks/marketplace.go | 1135 +++++++++ gost/test/mocks/vaulttracker.go | 734 ++++++ gost/test/mocks/zctoken.go | 619 +++++ gost/test/swivel/Abstracts.sol | 40 + gost/test/swivel/CErc20.abi | 1 + gost/test/swivel/CErc20.bin | 0 gost/test/swivel/Erc20.abi | 1 + gost/test/swivel/Erc20.bin | 0 gost/test/swivel/Hash.abi | 1 + gost/test/swivel/Hash.bin | 1 + gost/test/swivel/Hash.sol | 107 + gost/test/swivel/MarketPlace.abi | 1 + gost/test/swivel/MarketPlace.bin | 0 gost/test/swivel/Sig.abi | 1 + gost/test/swivel/Sig.bin | 1 + gost/test/swivel/Sig.sol | 55 + gost/test/swivel/Swivel.abi | 1 + gost/test/swivel/Swivel.bin | 1 + gost/test/swivel/Swivel.sol | 490 ++++ gost/test/swivel/swivel.go | 1382 +++++++++++ gost/test/tokens/Erc2612.abi | 1 + gost/test/tokens/Erc2612.bin | 1 + gost/test/tokens/Erc2612.sol | 53 + gost/test/tokens/Hash.abi | 1 + gost/test/tokens/Hash.bin | 1 + gost/test/tokens/Hash.sol | 80 + gost/test/tokens/IErc2612.abi | 1 + gost/test/tokens/IErc2612.bin | 0 gost/test/tokens/IErc2612.sol | 56 + gost/test/tokens/IPErc20.abi | 1 + gost/test/tokens/IPErc20.bin | 0 gost/test/tokens/IPErc20.sol | 80 + gost/test/tokens/IZcToken.abi | 1 + gost/test/tokens/IZcToken.bin | 0 gost/test/tokens/IZcToken.sol | 21 + gost/test/tokens/PErc20.abi | 1 + gost/test/tokens/PErc20.bin | 1 + gost/test/tokens/PErc20.sol | 278 +++ gost/test/tokens/Underlying.abi | 1 + gost/test/tokens/Underlying.bin | 1 + gost/test/tokens/Underlying.sol | 22 + gost/test/tokens/ZcToken.abi | 1 + gost/test/tokens/ZcToken.bin | 1 + gost/test/tokens/ZcToken.sol | 48 + gost/test/tokens/underlying.go | 313 +++ gost/test/tokens/zctoken.go | 1006 ++++++++ gost/test/vaulttracker/Abstracts.sol | 17 + gost/test/vaulttracker/CErc20.abi | 1 + gost/test/vaulttracker/CErc20.bin | 0 gost/test/vaulttracker/Erc20.abi | 1 + gost/test/vaulttracker/Erc20.bin | 0 gost/test/vaulttracker/VaultTracker.abi | 1 + gost/test/vaulttracker/VaultTracker.bin | 1 + gost/test/vaulttracker/VaultTracker.sol | 251 ++ gost/test/vaulttracker/vaulttracker.go | 583 +++++ 234 files changed, 27226 insertions(+) create mode 100644 .DS_Store create mode 100644 README.md create mode 100644 discord-export/.DS_Store create mode 100644 discord-export/Code4rena - Archive-2021 - swivel-sep30 [892486622401159260].html create mode 100644 discord-export/Code4rena - Archive-2021 - swivel-sep30 [892486622401159260].html_Files/-MUa9tmyPufyVGMmAkKT-437CE.png create mode 100644 discord-export/Code4rena - Archive-2021 - swivel-sep30 [892486622401159260].html_Files/1f389-28196.svg create mode 100644 discord-export/Code4rena - Archive-2021 - swivel-sep30 [892486622401159260].html_Files/1f44b-9E658.svg create mode 100644 discord-export/Code4rena - Archive-2021 - swivel-sep30 [892486622401159260].html_Files/1f44d-B3F5F.svg create mode 100644 discord-export/Code4rena - Archive-2021 - swivel-sep30 [892486622401159260].html_Files/1f604-6061B.svg create mode 100644 discord-export/Code4rena - Archive-2021 - swivel-sep30 [892486622401159260].html_Files/1f606-6F8AE.svg create mode 100644 discord-export/Code4rena - Archive-2021 - swivel-sep30 [892486622401159260].html_Files/1f60b-69108.svg create mode 100644 discord-export/Code4rena - Archive-2021 - swivel-sep30 [892486622401159260].html_Files/2-ADBB4.png create mode 100644 discord-export/Code4rena - Archive-2021 - swivel-sep30 [892486622401159260].html_Files/3026b81d5ab56c4d2a773cb9b5dbd3a5-8CB58.png create mode 100644 discord-export/Code4rena - Archive-2021 - swivel-sep30 [892486622401159260].html_Files/797886789380866079-D181A.png create mode 100644 discord-export/Code4rena - Archive-2021 - swivel-sep30 [892486622401159260].html_Files/862404106545922051-D26C2.gif create mode 100644 discord-export/Code4rena - Archive-2021 - swivel-sep30 [892486622401159260].html_Files/892635967494692896-61FB3.gif create mode 100644 discord-export/Code4rena - Archive-2021 - swivel-sep30 [892486622401159260].html_Files/892635968027394048-5E523.gif create mode 100644 discord-export/Code4rena - Archive-2021 - swivel-sep30 [892486622401159260].html_Files/Screen_Shot_2021-09-29_at_5.52.46_PM-DA8FF.png create mode 100644 discord-export/Code4rena - Archive-2021 - swivel-sep30 [892486622401159260].html_Files/ae0c30c4cbe01bb2000b3d3094ea7e82-F120E.png create mode 100644 discord-export/Code4rena - Archive-2021 - swivel-sep30 [892486622401159260].html_Files/cec17fe3825e83ddf170d7e8c98ece3e-B6D17.png create mode 100644 discord-export/Code4rena - Archive-2021 - swivel-sep30 [892486622401159260].html_Files/df4391e9033659fcd5fd4c01aae14551-7F4A0.png create mode 100644 discord-export/Code4rena - Archive-2021 - swivel-sep30 [892486622401159260].html_Files/fd27bbac738561bc2df301737c024c66-92730.png create mode 100644 discord-export/Code4rena - Archive-2021 - swivel-sep30 [892486622401159260].html_Files/gost-0F62A create mode 100644 discord-export/Code4rena - Archive-2021 - swivel-sep30 [892486622401159260].html_Files/unknown-D8713.png create mode 100644 discord-export/Code4rena - Archive-2021 - swivel-sep30 [892486622401159260].txt create mode 100644 discord-export/Code4rena - Archive-2021 - swivel-sep30 [892486622401159260].txt_Files/-MUa9tmyPufyVGMmAkKT-437CE.png create mode 100644 discord-export/Code4rena - Archive-2021 - swivel-sep30 [892486622401159260].txt_Files/Screen_Shot_2021-09-29_at_5.52.46_PM-DA8FF.png create mode 100644 discord-export/Code4rena - Archive-2021 - swivel-sep30 [892486622401159260].txt_Files/gost-0F62A create mode 100644 discord-export/Code4rena - Archive-2021 - swivel-sep30 [892486622401159260].txt_Files/unknown-D8713.png create mode 100644 gost/.DS_Store create mode 100644 gost/.travis.yml create mode 100644 gost/Makefile create mode 100644 gost/README.md create mode 100644 gost/build/.DS_Store create mode 100644 gost/build/marketplace/Abstracts.sol create mode 100644 gost/build/marketplace/CErc20.abi create mode 100644 gost/build/marketplace/CErc20.bin create mode 100644 gost/build/marketplace/Erc20.abi create mode 100644 gost/build/marketplace/Erc20.bin create mode 100644 gost/build/marketplace/Erc2612.abi create mode 100644 gost/build/marketplace/Erc2612.bin create mode 100644 gost/build/marketplace/Erc2612.sol create mode 100644 gost/build/marketplace/Hash.abi create mode 100644 gost/build/marketplace/Hash.bin create mode 100644 gost/build/marketplace/Hash.sol create mode 100644 gost/build/marketplace/IErc2612.abi create mode 100644 gost/build/marketplace/IErc2612.bin create mode 100644 gost/build/marketplace/IErc2612.sol create mode 100644 gost/build/marketplace/IPErc20.abi create mode 100644 gost/build/marketplace/IPErc20.bin create mode 100644 gost/build/marketplace/IPErc20.sol create mode 100644 gost/build/marketplace/IZcToken.abi create mode 100644 gost/build/marketplace/IZcToken.bin create mode 100644 gost/build/marketplace/IZcToken.sol create mode 100644 gost/build/marketplace/MarketPlace.abi create mode 100644 gost/build/marketplace/MarketPlace.bin create mode 100644 gost/build/marketplace/MarketPlace.sol create mode 100644 gost/build/marketplace/PErc20.abi create mode 100644 gost/build/marketplace/PErc20.bin create mode 100644 gost/build/marketplace/PErc20.sol create mode 100644 gost/build/marketplace/VaultTracker.abi create mode 100644 gost/build/marketplace/VaultTracker.bin create mode 100644 gost/build/marketplace/VaultTracker.sol create mode 100644 gost/build/marketplace/ZcToken.abi create mode 100644 gost/build/marketplace/ZcToken.bin create mode 100644 gost/build/marketplace/ZcToken.sol create mode 100644 gost/build/marketplace/marketplace.go create mode 100644 gost/build/swivel/Abstracts.sol create mode 100644 gost/build/swivel/CErc20.abi create mode 100644 gost/build/swivel/CErc20.bin create mode 100644 gost/build/swivel/Erc20.abi create mode 100644 gost/build/swivel/Erc20.bin create mode 100644 gost/build/swivel/Hash.abi create mode 100644 gost/build/swivel/Hash.bin create mode 100644 gost/build/swivel/Hash.sol create mode 100644 gost/build/swivel/MarketPlace.abi create mode 100644 gost/build/swivel/MarketPlace.bin create mode 100644 gost/build/swivel/Sig.abi create mode 100644 gost/build/swivel/Sig.bin create mode 100644 gost/build/swivel/Sig.sol create mode 100644 gost/build/swivel/Swivel.abi create mode 100644 gost/build/swivel/Swivel.bin create mode 100644 gost/build/swivel/Swivel.sol create mode 100644 gost/build/swivel/swivel.go create mode 100644 gost/go.mod create mode 100644 gost/go.sum create mode 100644 gost/internal/helpers/helpers.go create mode 100644 gost/pkg/.DS_Store create mode 100644 gost/pkg/marketplacetesting/constants.go create mode 100644 gost/pkg/marketplacetesting/construction_test.go create mode 100644 gost/pkg/marketplacetesting/create_market_test.go create mode 100644 gost/pkg/marketplacetesting/custodial_exit_test.go create mode 100644 gost/pkg/marketplacetesting/custodial_initiate_test.go create mode 100644 gost/pkg/marketplacetesting/dep.go create mode 100644 gost/pkg/marketplacetesting/env.go create mode 100644 gost/pkg/marketplacetesting/get_ctoken_address_address_test.go create mode 100644 gost/pkg/marketplacetesting/mature_market_test.go create mode 100644 gost/pkg/marketplacetesting/p2p_vault_exchange_test.go create mode 100644 gost/pkg/marketplacetesting/p2p_zc_token_exchange_test.go create mode 100644 gost/pkg/marketplacetesting/redeem_vault_interest_test.go create mode 100644 gost/pkg/marketplacetesting/redeem_zc_token_test.go create mode 100644 gost/pkg/marketplacetesting/set_swivel_address_test.go create mode 100644 gost/pkg/marketplacetesting/transfer_vault_notional_fee_test.go create mode 100644 gost/pkg/marketplacetesting/transfer_vault_notional_test.go create mode 100644 gost/pkg/swiveltesting/constants.go create mode 100644 gost/pkg/swiveltesting/dep.go create mode 100644 gost/pkg/swiveltesting/env.go create mode 100644 gost/pkg/swiveltesting/exit_vault_filling_vault_initiate_test.go create mode 100644 gost/pkg/swiveltesting/exit_vault_filling_zctoken_exit_test.go create mode 100644 gost/pkg/swiveltesting/exit_zctoken_filling_vault_exit_test.go create mode 100644 gost/pkg/swiveltesting/exit_zctoken_filling_zctoken_initiate_test.go create mode 100644 gost/pkg/swiveltesting/initiate_vault_filling_vault_exit_test.go create mode 100644 gost/pkg/swiveltesting/initiate_vault_filling_zctoken_initiate_test.go create mode 100644 gost/pkg/swiveltesting/initiate_zctoken_filling_vault_initiate_test.go create mode 100644 gost/pkg/swiveltesting/initiate_zctoken_filling_zctoken_exit_test.go create mode 100644 gost/pkg/swiveltesting/redeem_vault_interest_test.go create mode 100644 gost/pkg/swiveltesting/redeem_zctoken_test.go create mode 100644 gost/pkg/swiveltesting/split_and_combine_test.go create mode 100644 gost/pkg/swiveltesting/swivel_construction_test.go create mode 100644 gost/pkg/swiveltesting/withdrawal_test.go create mode 100644 gost/pkg/testing/constants.go create mode 100644 gost/pkg/testing/dep.go create mode 100644 gost/pkg/testing/env.go create mode 100644 gost/pkg/testing/hash_test.go create mode 100644 gost/pkg/testing/sig_test.go create mode 100644 gost/pkg/testing/token_test.go create mode 100644 gost/pkg/vaulttrackertesting/add_notional_test.go create mode 100644 gost/pkg/vaulttrackertesting/balances_of_test.go create mode 100644 gost/pkg/vaulttrackertesting/constants.go create mode 100644 gost/pkg/vaulttrackertesting/dep.go create mode 100644 gost/pkg/vaulttrackertesting/env.go create mode 100644 gost/pkg/vaulttrackertesting/mature_vault_test.go create mode 100644 gost/pkg/vaulttrackertesting/redeem_interest_test.go create mode 100644 gost/pkg/vaulttrackertesting/remove_notional_test.go create mode 100644 gost/pkg/vaulttrackertesting/transfer_notional_fee_test.go create mode 100644 gost/pkg/vaulttrackertesting/transfer_notional_from_test.go create mode 100644 gost/pkg/vaulttrackertesting/transfer_notional_test.go create mode 100644 gost/pkg/vaulttrackertesting/vault_tracker_construction_test.go create mode 100644 gost/test/.DS_Store create mode 100644 gost/test/fakes/Hash.abi create mode 100644 gost/test/fakes/Hash.bin create mode 100644 gost/test/fakes/Hash.sol create mode 100644 gost/test/fakes/HashFake.abi create mode 100644 gost/test/fakes/HashFake.bin create mode 100644 gost/test/fakes/HashFake.sol create mode 100644 gost/test/fakes/Sig.abi create mode 100644 gost/test/fakes/Sig.bin create mode 100644 gost/test/fakes/Sig.sol create mode 100644 gost/test/fakes/SigFake.abi create mode 100644 gost/test/fakes/SigFake.bin create mode 100644 gost/test/fakes/SigFake.sol create mode 100644 gost/test/fakes/hashfake.go create mode 100644 gost/test/fakes/sigfake.go create mode 100644 gost/test/marketplace/Abstracts.sol create mode 100644 gost/test/marketplace/CErc20.abi create mode 100644 gost/test/marketplace/CErc20.bin create mode 100644 gost/test/marketplace/Erc20.abi create mode 100644 gost/test/marketplace/Erc20.bin create mode 100644 gost/test/marketplace/MarketPlace.abi create mode 100644 gost/test/marketplace/MarketPlace.bin create mode 100644 gost/test/marketplace/MarketPlace.sol create mode 100644 gost/test/marketplace/VaultTracker.abi create mode 100644 gost/test/marketplace/VaultTracker.bin create mode 100644 gost/test/marketplace/VaultTracker.sol create mode 100644 gost/test/marketplace/ZcToken.abi create mode 100644 gost/test/marketplace/ZcToken.bin create mode 100644 gost/test/marketplace/ZcToken.sol create mode 100644 gost/test/marketplace/marketplace.go create mode 100644 gost/test/mocks/CErc20.abi create mode 100644 gost/test/mocks/CErc20.bin create mode 100644 gost/test/mocks/CErc20.sol create mode 100644 gost/test/mocks/Erc20.abi create mode 100644 gost/test/mocks/Erc20.bin create mode 100644 gost/test/mocks/Erc20.sol create mode 100644 gost/test/mocks/MarketPlace.abi create mode 100644 gost/test/mocks/MarketPlace.bin create mode 100644 gost/test/mocks/MarketPlace.sol create mode 100644 gost/test/mocks/cerc20.go create mode 100644 gost/test/mocks/erc20.go create mode 100644 gost/test/mocks/marketplace.go create mode 100644 gost/test/mocks/vaulttracker.go create mode 100644 gost/test/mocks/zctoken.go create mode 100644 gost/test/swivel/Abstracts.sol create mode 100644 gost/test/swivel/CErc20.abi create mode 100644 gost/test/swivel/CErc20.bin create mode 100644 gost/test/swivel/Erc20.abi create mode 100644 gost/test/swivel/Erc20.bin create mode 100644 gost/test/swivel/Hash.abi create mode 100644 gost/test/swivel/Hash.bin create mode 100644 gost/test/swivel/Hash.sol create mode 100644 gost/test/swivel/MarketPlace.abi create mode 100644 gost/test/swivel/MarketPlace.bin create mode 100644 gost/test/swivel/Sig.abi create mode 100644 gost/test/swivel/Sig.bin create mode 100644 gost/test/swivel/Sig.sol create mode 100644 gost/test/swivel/Swivel.abi create mode 100644 gost/test/swivel/Swivel.bin create mode 100644 gost/test/swivel/Swivel.sol create mode 100644 gost/test/swivel/swivel.go create mode 100644 gost/test/tokens/Erc2612.abi create mode 100644 gost/test/tokens/Erc2612.bin create mode 100644 gost/test/tokens/Erc2612.sol create mode 100644 gost/test/tokens/Hash.abi create mode 100644 gost/test/tokens/Hash.bin create mode 100644 gost/test/tokens/Hash.sol create mode 100644 gost/test/tokens/IErc2612.abi create mode 100644 gost/test/tokens/IErc2612.bin create mode 100644 gost/test/tokens/IErc2612.sol create mode 100644 gost/test/tokens/IPErc20.abi create mode 100644 gost/test/tokens/IPErc20.bin create mode 100644 gost/test/tokens/IPErc20.sol create mode 100644 gost/test/tokens/IZcToken.abi create mode 100644 gost/test/tokens/IZcToken.bin create mode 100644 gost/test/tokens/IZcToken.sol create mode 100644 gost/test/tokens/PErc20.abi create mode 100644 gost/test/tokens/PErc20.bin create mode 100644 gost/test/tokens/PErc20.sol create mode 100644 gost/test/tokens/Underlying.abi create mode 100644 gost/test/tokens/Underlying.bin create mode 100644 gost/test/tokens/Underlying.sol create mode 100644 gost/test/tokens/ZcToken.abi create mode 100644 gost/test/tokens/ZcToken.bin create mode 100644 gost/test/tokens/ZcToken.sol create mode 100644 gost/test/tokens/underlying.go create mode 100644 gost/test/tokens/zctoken.go create mode 100644 gost/test/vaulttracker/Abstracts.sol create mode 100644 gost/test/vaulttracker/CErc20.abi create mode 100644 gost/test/vaulttracker/CErc20.bin create mode 100644 gost/test/vaulttracker/Erc20.abi create mode 100644 gost/test/vaulttracker/Erc20.bin create mode 100644 gost/test/vaulttracker/VaultTracker.abi create mode 100644 gost/test/vaulttracker/VaultTracker.bin create mode 100644 gost/test/vaulttracker/VaultTracker.sol create mode 100644 gost/test/vaulttracker/vaulttracker.go diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..f7a1d7b1ec7352707dfb1b99f148ccec586fb1ac GIT binary patch literal 6148 zcmeHKu};H44E2=^fl8=j1yqIg48Gx1;m({|Kc-%U*HpXwof5Z ziYgWa$d-KX&S&SGchNaVL~e4QjfnIW_mMl+oRCF`mwgyp-g3PWLzY=S7;%mcwk4aLdouzPVQmnd3m3>X7#2DWrK;QD|3_5HscWFuq1 z82DEVxG0^b6TDKWt(}+STI-<~P!{&96zdRlq!h!KOYsmY0=wr9FbP;G!UC}$0inSf JW8g;__yAKzQ&s=~ literal 0 HcmV?d00001 diff --git a/README.md b/README.md new file mode 100644 index 0000000..fbfd250 --- /dev/null +++ b/README.md @@ -0,0 +1,82 @@ +# Swivel contest details +- $67,500 worth of ETH main award pot +- $7,500 worth of ETH gas optimization award pot +- Join [C4 Discord](https://discord.gg/EY5dvm3evD) to register +- Submit findings [using the C4 form](https://code423n4.com/2021-09-swivel-contest/submit) +- [Read our guidelines for more details](https://docs.code4rena.com/roles/wardens) +- Starts September 30, 2021 00:00 UTC +- Ends October 6, 2021 23:59 UTC + +# Introduction + +Swivel is a yield tokenization protocol that allows LP's, stakers and lenders to separate their yield into two components, zcTokens (which represent the 1-1 claim to deposited tokens upon maturity), and nTokens (which represent the claim to any yield generated). In addition to this base functionality, Swivel provides the infrastructure to facilitate the exchange of these tokens through an orderbook. This allows users to lend with low or no slippage, and liquidity providers to avoid the alpha decay inherent to LPing in derivative markets on an AMM. + +Regarding our orderbook infrastructure, the base orderbook functionality is most similar to the original 0x-v3. Users EIP-712 sign an order object which contains information regarding asset, maturity, maker, price, amount, and whether the user is initiating a new position vs exiting/selling a currently held zcToken or nToken position. + +A testnet is currently live at https://swivel.exchange . + +General Project Docs:https://docs.swivel.finance + +Contract Docs: https://docs.swivel.finance/developers/contract + +Recent Video Overview (ETHOnline): https://www.youtube.com/watch?v=hI0Uwd4Xayg . + +### **Order Path:** +A taker initiates their own position using `initiate` or `exit` on Swivel.sol, in the process filling another user's order. Swivel.sol handles fund custody and deposits/withdrawals from underlying protocols (compound). Params are routed to Marketplace.sol and according to the `underlying` and `maturity` of an order, a market is identified (asset-maturity combination), and zcTokens and nTokens are minted/burnt/exchanged within that market according to the params. + +Order fill amounts and cancellations are tracked on chain based on a keccak of the order itself. + +### **nToken and zcToken functionality:** +When a user initiates a new fixed-yield position on our orderbook, or manually calls `splitUnderlying`, an underlying token is split into zcTokens and nTokens. (the fixed-yield comes from immediately selling nTokens). + +A zcToken (standard erc-20 + erc-2612) can be redeemed 1-1 for underlying upon maturity. After maturity, if a user has not redeemed their zcTokens, they begin accruing interest from the deposit in compound. + +An nToken (non-standard contract balance) is a balance within a users `vault`(vault.notional) within VaultTracker.sol. nTokens (notional balance) represent a deposit in an underlying protocol (compound), and accrue the interest from this deposit until maturity. This interest can be redeemed at any time. + + +# Smart Contracts +| **Contracts** | **Link** | **LOC** | **LIBS** | **External** | +|--------------|------|------|------|------| +| Swivel |[Link](https://github.com/Swivel-Finance/gost/blob/v2/test/swivel/Swivel.sol)| 486 | [Abstracts.sol](https://github.com/Swivel-Finance/gost/blob/v2/test/swivel/Abstracts.sol), [Hash.sol](https://github.com/Swivel-Finance/gost/blob/v2/test/swivel/Hash.sol), [Sig.sol](https://github.com/Swivel-Finance/gost/blob/v2/test/swivel/Sig.sol) | [CToken.sol](https://github.com/compound-finance/compound-protocol/blob/master/contracts/CToken.sol) | +| Marketplace |[Link](https://github.com/Swivel-Finance/gost/blob/v2/test/marketplace/MarketPlace.sol)| 259 | [Abstracts.sol](https://github.com/Swivel-Finance/gost/blob/v2/test/marketplace/Abstracts.sol) | +| VaultTracker |[Link](https://github.com/Swivel-Finance/gost/blob/v2/test/vaulttracker/VaultTracker.sol)| 251 | [Abstracts.sol](https://github.com/Swivel-Finance/gost/blob/v2/test/vaulttracker/Abstracts.sol) | [CToken.sol](https://github.com/compound-finance/compound-protocol/blob/master/contracts/CToken.sol) | + +## **Swivel:** +Swivel.sol handles all fund custody, and most all user interaction methods are on Swivel.sol (`initiate`,`exit`,`splitUnderying`,`combineTokens`, `redeemZcTokens`, `redeemVaultInterest`). We categorize all order interactions as either `payingPremium` or `receivingPremium` depending on the params (`vault` & `exit`) of an order filled, and whether a user calls `initiate` or `exit`. + +For example, if `vault` = true, the maker of an order is interacting with their vault, and if `exit` = true, they are selling notional (nTokens) and would be `receivingPremium`. Alternatively, if `vault` = false, and `exit` = false, the maker is initiating a fixed yield, and thus also splitting underlying and selling nTokens, `receivingPremium`. + +A warden, @ItsmeSTYJ was kind enough to organize a matrix which might help understand the potential interactions: [Link](https://cdn.discordapp.com/attachments/893151471388999690/893367485540212756/unknown.png) + + +Outside of this sorting, the basic order interaction logic is: +1. Check Signatures, Cancellations, Fill availability for order validity +2. Calculate either principalFilled or premiumFilled depending on whether the order is paying/receivingPremium +3. Calculate fee +4. Deposit/Withdraw from compound and/or exchange/mint/burn zcTokens and nTokens through marketplace.sol +5. Transfer fees + +Other methods (`splitUnderying`,`combineTokens`, `redeemZcTokens`, `redeemVaultInterest`) largely just handle fund custody from underlying protocols, and shoot burn/mint commands to marketplace.sol. + +## **Marketplace:** +Marketplace.sol acts as the central hub for tracking all markets (defined as an asset-matury pair). Markets are stored in a mapping and admins are the only ones that can create markets. + +Any orderbook interactions that require zcToken or nToken transfers are handled through marketplace burn/mints in order to avoid requiring approvals. + +If a user wants to transfer nTokens are without using our orderbook, they do so directly through the marketplace.sol contract. + +## **VaultTracker:** +A user's vault has three properties, `notional` (nToken balance), `redeemable` (underlying accrued to redeem), and `exchangeRate` (compound exchangeRate of last vault interaction). + +When a user takes on a floating position and purchases nTokens (vault initiate), they increase the notional balance of their vault (`vault.notional`). Opposingly, if they sell nTokens, this balance decreases. + +Every time a user either increases/decreases their nToken balance (`vault.notional`), the marginal interest since the user's last vault interaction is calculated + added to `vault.redeemable`, and a new `vault.exchangeRate` is set. + + +# Areas of Concern: +There are a few primary targets for concern: +1. Ensuring no vulnerabilities in order validity and the use of an order's hash to track cancel status and fill amount. +2. Ensuring the accurate calculation of deposit interest. This includes VaultTracker.sol + the calculation of marginal interest between vault interactions pre-maturity, and Marketplace.sol + the calculation of zcToken interest post-maturity. +3. Ensuring maturity is handled properly. + +One additional small area of concern that isn't necessarily defined in the scope above but may be rewarded could be in the ERC-2612 chain imported as zcToken.sol in Marketplace.sol diff --git a/discord-export/.DS_Store b/discord-export/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..850bf3a874eff599bb2944cca409f1fa8b93d082 GIT binary patch literal 8196 zcmeHM%}&BV5dIbkl6djRu`hrDM54EX2;ND&7^5OaOo}CfKgXVZ0)H;Pj8EX%ck!Fu zRWZm_E6kAHZ`qmIPQOlDW&vOtSG_V&0FY-BTwP)JgNR<*lw|yjC=LCADlTz~3mhYu zvepS@Kp9X5lmTTx8At;Id}oW~XT0~FR(oYY8CXaL!ysPmghH>uH2VzbPJthvFJB)LO@kchkLNWH}^b4#xOz2R1 zWk4C2WEJ!O04lyvEvdw%h<4*8to3S#SX^gV>5276QC$9E#NiKTp5A$)1TV~{}Y|K1x&n#W>P3GcbZucV> zQ^nyR{>sF(#`rA{GtZKTD$2k-GqB`Nt|0aQ&g}jFd8R D8)E2I literal 0 HcmV?d00001 diff --git a/discord-export/Code4rena - Archive-2021 - swivel-sep30 [892486622401159260].html b/discord-export/Code4rena - Archive-2021 - swivel-sep30 [892486622401159260].html new file mode 100644 index 0000000..5c2dbb2 --- /dev/null +++ b/discord-export/Code4rena - Archive-2021 - swivel-sep30 [892486622401159260].html @@ -0,0 +1,1504 @@ + + + + + + + + Code4rena - swivel-sep30 + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ Guild icon +
+
+
Code4rena
+
Archive-2021 / swivel-sep30
+ + +
+
+ +
+ + + +
+ +
+ Avatar +
+ +
+ 👩🏽💻 Jay | C4 + + + 28-Sep-21 02:01 PM + +
+
+
+ 👋 Hello and welcome to the contest channel for the $75K worth of ETH Swivel contest! + +📆 Contest opens Sep 30, 2021 at 0:00 UTC and runs through October 6, 2021 at 23:59 UTC (one week). + +Please give a warm welcome to @Julian | Swivel and @jankisa who will be available during the contest to answer questions either here in channel or via DM. + +We'll be posting relevant links, documentation, etc. here, so if you intend to participate in this contest, you might want to enable notifications. 🐺 + +
+
+ + + + +
+
+ 🎉 + 6 +
+
+ 👋 + 6 +
+
+ swivelSpin + 2 +
+
+
+
+
+ + + +
+ +
+ Avatar +
+ +
+ Julian | Swivel + + + 28-Sep-21 02:03 PM + +
+
+
+ peepoParty + +
+
+ + + + +
+
+
+ + + +
+ +
+ Avatar +
+ +
+ Julian | Swivel + + + 29-Sep-21 05:04 PM + +
+
+
+ Hey hey guys! Julian founder/CEO of Swivel here! + +
+
+ + + + +
+
+ TE_PeepoGoosee + 1 +
+
+ 👋 + 2 +
+
+
+
+
+
+ Our 7 days in the arena have just begun, feel free to reach out to myself for any questions (logic, intended effects, etc.,) or @jankisa if im not around! + +For quick reference our docs can be found at: https://docs.swivel.finance + +
+
+ + +
+
+ +
+
+
+ + + +
+
Documentation for all things Swivel Finance.
+
+ +
+ +
+ + Thumbnail + +
+
+ + +
+
+ + +
+
+
+
+ Excited to see what sort of disgusting things we did / missed 2708fingergunz + +
+
+ + + + +
+
+ 😋 + 2 +
+
+
+
+
+ + + +
+
+
+ Avatar + Julian | Swivel +
+ +Our 7 days in the arena have just begun, feel free to reach out to myself for any questions (logic, intended effects, etc.,) or @jankisa if im not around! + +For quick reference our docs can be found at: https://docs.swivel.finance + +
+
+ +
+ Avatar +
+ +
+ t11s + + + 29-Sep-21 05:52 PM + +
+
+
+ all these links are ded 😅 + +
+
+ +
+ + + Image attachment + +
+ + + +
+
+
+ + + +
+ +
+ Avatar +
+ +
+ Julian | Swivel + + + 29-Sep-21 05:52 PM + +
+
+
+ que pasa + +
+
+ + + + +
+
+
+
+ ill check on that, should be public, just checked a few hrs ago + + (edited) +
+
+ + + + +
+
+
+ + + +
+ +
+ Avatar +
+ +
+ t11s + + + 29-Sep-21 05:54 PM + +
+
+
+ links to a "gost" repo + +
+
+ + + + +
+
+ + + +
+
+ +
+
+
+ + + +
+
Smart contract testing with Geth via the Golang ABIGEN - gost/Swivel.sol at v2 · Swivel-Finance/gost
+
+ +
+ +
+ + Thumbnail + +
+
+ + +
+
+ + +
+
+
+ + + +
+ +
+ Avatar +
+ +
+ Julian | Swivel + + + 29-Sep-21 05:54 PM + +
+
+
+ try... now 🙂 + +
+
+ + + + +
+
+
+
+ gost is our custom testing framework written in go / directly interacting with geth + + (edited) +
+
+ + + + +
+
+
+
+ We decided to link to it instead of a general project repo so folks could check out the tests if they wanted + +
+
+ + + + +
+
+
+ + + +
+ +
+ Avatar +
+ +
+ t11s + + + 29-Sep-21 05:55 PM + +
+
+
+ coolio all good now + +
+
+ + + + +
+
+
+
+ CatJam + +
+
+ + + + +
+
+ chadJam + 1 +
+
+ 👍 + 1 +
+
+
+
+
+ + + +
+ +
+ Avatar +
+ +
+ 0xleastwood + + + 29-Sep-21 06:11 PM + +
+
+
+ excited to jump into the code! + +
+
+ + + + +
+
+ swivelHeat + 1 +
+
+ 👍 + 1 +
+
+
+
+
+ + + +
+ +
+ Avatar +
+ +
+ Julian | Swivel + + + 29-Sep-21 08:24 PM + +
+
+
+ @t11s + +
+
+ +
+ + + Image attachment + +
+ + + +
+
+ 😆 + 1 +
+
+
+
+
+ + + +
+
+
+ Avatar + Julian | Swivel +
+ +@t11s + +
+
+ +
+ Avatar +
+ +
+ t11s + + + 29-Sep-21 08:46 PM + +
+
+
+ 😂 + +
+
+ + + + +
+
+
+ + + +
+ +
+ Avatar +
+ +
+ Julian | Swivel + + + 01-Oct-21 06:52 AM + +
+
+
+ Hey guys, two folks asked for more info on exactly the interaction between the methods exit or initiate, and the exit and vault params in the orders these methods might fill. (its the most needlessly confusing part of our protocol lol) + + (edited) +
+
+ + + + +
+
+
+ + + +
+ +
+ Avatar +
+ +
+ Julian | Swivel + + + 01-Oct-21 07:04 AM + +
+
+
+ That said, @itsmeSTYJ was kind enough to put together a quick sheet that organizes / explicitly explains each 🙂 + +If anyone is interested: https://docs.google.com/spreadsheets/d/1EhHHbfNNv9VC55yPDnR52vZDToOTp3nEBh9-N53yClY/edit?usp=sharing + +
+
+ + + + +
+
+ 😄 + 1 +
+
+ 👍 + 2 +
+
+ 😆 + 1 +
+
+
+
+
+ + + +
+ +
+ Avatar +
+ +
+ csanuragjain + + + 01-Oct-21 08:11 AM + +
+
+
+ Bit confused, why code is calculating interest everytime any user adds ntokens on same vault and not when user exits the ntoken position via redeem? (considering exchange rate can be fluctuating) + + (edited) +
+
+ + + + +
+
+
+ + + +
+ +
+ Avatar +
+ +
+ Julian | Swivel + + + 01-Oct-21 10:30 AM + +
+
+
+ The interest should be recalculated during the redeem + +
+
+ + + + +
+ +
+
+
+ If redeemed pre-maturity, it calculates since the last interaction exchangeRate -> current exchangeRate + +
+
+ + + + +
+
+
+
+ if redeemed post-maturity, it calculates the last interaction exchangeRate -> the rate when the market matured + + (edited) +
+
+ + + + +
+
+
+ + + +
+ +
+ Avatar +
+ +
+ csanuragjain + + + 03-Oct-21 11:21 PM + +
+
+
+ got it thanks + +
+
+ + + + +
+
+
+ + +
+ +
+
Exported 26 message(s)
+
+ + + + diff --git a/discord-export/Code4rena - Archive-2021 - swivel-sep30 [892486622401159260].html_Files/-MUa9tmyPufyVGMmAkKT-437CE.png b/discord-export/Code4rena - Archive-2021 - swivel-sep30 [892486622401159260].html_Files/-MUa9tmyPufyVGMmAkKT-437CE.png new file mode 100644 index 0000000..e69de29 diff --git a/discord-export/Code4rena - Archive-2021 - swivel-sep30 [892486622401159260].html_Files/1f389-28196.svg b/discord-export/Code4rena - Archive-2021 - swivel-sep30 [892486622401159260].html_Files/1f389-28196.svg new file mode 100644 index 0000000..a4b8305 --- /dev/null +++ b/discord-export/Code4rena - Archive-2021 - swivel-sep30 [892486622401159260].html_Files/1f389-28196.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/discord-export/Code4rena - Archive-2021 - swivel-sep30 [892486622401159260].html_Files/1f44b-9E658.svg b/discord-export/Code4rena - Archive-2021 - swivel-sep30 [892486622401159260].html_Files/1f44b-9E658.svg new file mode 100644 index 0000000..8942c68 --- /dev/null +++ b/discord-export/Code4rena - Archive-2021 - swivel-sep30 [892486622401159260].html_Files/1f44b-9E658.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/discord-export/Code4rena - Archive-2021 - swivel-sep30 [892486622401159260].html_Files/1f44d-B3F5F.svg b/discord-export/Code4rena - Archive-2021 - swivel-sep30 [892486622401159260].html_Files/1f44d-B3F5F.svg new file mode 100644 index 0000000..595672d --- /dev/null +++ b/discord-export/Code4rena - Archive-2021 - swivel-sep30 [892486622401159260].html_Files/1f44d-B3F5F.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/discord-export/Code4rena - Archive-2021 - swivel-sep30 [892486622401159260].html_Files/1f604-6061B.svg b/discord-export/Code4rena - Archive-2021 - swivel-sep30 [892486622401159260].html_Files/1f604-6061B.svg new file mode 100644 index 0000000..99ac39c --- /dev/null +++ b/discord-export/Code4rena - Archive-2021 - swivel-sep30 [892486622401159260].html_Files/1f604-6061B.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/discord-export/Code4rena - Archive-2021 - swivel-sep30 [892486622401159260].html_Files/1f606-6F8AE.svg b/discord-export/Code4rena - Archive-2021 - swivel-sep30 [892486622401159260].html_Files/1f606-6F8AE.svg new file mode 100644 index 0000000..fed5ff5 --- /dev/null +++ b/discord-export/Code4rena - Archive-2021 - swivel-sep30 [892486622401159260].html_Files/1f606-6F8AE.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/discord-export/Code4rena - Archive-2021 - swivel-sep30 [892486622401159260].html_Files/1f60b-69108.svg b/discord-export/Code4rena - Archive-2021 - swivel-sep30 [892486622401159260].html_Files/1f60b-69108.svg new file mode 100644 index 0000000..27e0d3a --- /dev/null +++ b/discord-export/Code4rena - Archive-2021 - swivel-sep30 [892486622401159260].html_Files/1f60b-69108.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/discord-export/Code4rena - Archive-2021 - swivel-sep30 [892486622401159260].html_Files/2-ADBB4.png b/discord-export/Code4rena - Archive-2021 - swivel-sep30 [892486622401159260].html_Files/2-ADBB4.png new file mode 100644 index 0000000000000000000000000000000000000000..679e3426d770e1af295813bf02ff14003f033f24 GIT binary patch literal 1325 zcmV+|1=9M7P)kC4rygvXg|yM)5y%;xm#|NsB<`SnMtW>m0nsn@v9=+>Rmt)0@YV77Yl`t`Nl z!nWPP+V0`0*te(nT5ugk<6rcz>i?IdnlO>FaQ7qXGugsRCodG!GQn(004lX{izqJ0ssI2 z0000000000000000D#%K&$YF67y!V^aI6eFs{;rlG<4qo{hfW(9ikdyQS<)()Tb7f zBRk`&C{9vXEKXGP8;xBhnMTCCfQ3qph&oHu?=bkv;QuTvR8xql6g;jbF-RCwpltC= zCTZXSsY)Z^O@R)-r91U#qi>OLrU0z~kDPfwGCy#8y4A zHc6HGZ+IGi&ZHn(Xn zK$;FokVViS39|?^u1td{HLlKrASJFZF9Tfxi2*TQqZcaB6_C7;)dPC40TCjNp5#TK zmq22rYyyIw0v&o}!|Z`XO@R)*vSCjE0aKtu&#d=LK-g1Yi{4q^yMUmlK#Brvz@Hro zV8ELJMNolW14-t;2?}%>Oi>8ye+dk78Qh~7D$pg6RDpJZBoDO-AS&z%@KXaC1<3=i z03S8*5=E&*cR>ejjt6AmhiJL`0JAOOZ_R1sha7RKQs_Ql9Du-SWQW9~&|{Gd7pV&P z$}4_IEptzN{>5!t?GPgALb&ISpVST^vl>{_1{Zk4FCO#jP3K135-?8iBbT}A;fIhO z)}$TIX=;a%8CqHwkWT>I-;)vIw-bo*x{ldJ^FzK7!+NaK|7UOy@x2`|cwGTMb758h zh0M!jwLv@n5}GqY{H}r*$D?ZF5Hh0>br_P}HUV!%^@1tCFL6ykhS$A=wOE-YP>E`U z^-R3xhwMZ(!#i}l4Dv$&7ud-<3{Z?UlojItNZ{glPTRSK_`eSB9UoiJ?je4+LxbC6 z3#ns>|GOhGx=evcvqOMFWHbUBr}ukb@qDV2;;^zWQG-YTkt)6>pee2iMv7g z_Sc`^+PH_z=;b8H9uw?-oLg-vs#gOu#b% z&jdUZ@Jzrn0nY?H6X0nt;9vhtfdBJ=ARZXDD3tYkCg|Tr(sROQJL1iZ+oS(OQT_uv zLxwkDhJ`1?O3t036Z~VUM|5C(*m!cw;*5_y4YW4A~)oR;kYoA)5OWk;N zZ*8l7E~s5xuv&MJMGy#E0wE+JA^S3u%szAX_njM}2${^1nL9ISe%}|!m%IIE&hPy9 zb1uL*#xag@jAI<*7{@rqF^+MJe=o2 zdyQM_s%;8v@upf%E%9$bfI_B%S#G~=)f9IAO$O3l0RUOUeDp{&$0f9L8i<-Q zj9CI$=}E*=+kalQ$a3|A05CC*TLc5rz`9quuD`oARNa{b5z_+E%!rHv0t7j_65Dl! zul{a^;jDWAz#iwVXqwPh%{5)J!bIgXwgk5~%OENV7B}S>a|AfudPC(83to85Kw2-y zgE-3DArjF!MQqioO3TU#?V)|U-C~zNL87Jw#tZ?Bq@7%y|HPH2S+9MO0Afyp%^S@U zSqo0FtX@tavZ04RbW~763A}ykFeV5v-LTZQD({iUrW?+<8vzlo%8vwufGC`*U%Yaf zeu>c~cI@sKj%K`rn9&5#5e78Zbn*Nv@}GIbN>98b0V+Qluof!+jJc+Z&vJPjY5t(jemq zKp+Z=*i-V?OnUpNNo?gWaKx8Fag2Go8E4HkUvhd#_U!87>l_NmDHJDmWE24iAkl@n zzgfOA@8Opj!gT&Osod0xMI&}vnep7qC$aNFt)c4uA=#ZV+8|>HV5287R~5c+TZL)G zQwU&c8YZz!*>v%D%1sx|k`!TgJGXZr)dEF>3?Kl4O7o>9m*=g0p@5ma1^^7HmS_YJ z3}KpGYFv7mg(~Q63GS#D6;4XEP$MC&31A>?)FpWjTz;#3?0NPpmPF>4}I zacP-x*<`QOyQhzDa;I9Ta7bGM6tnYfmrZ!&!CA)h?gN0lRLc_w2osrGIn!{?1-ZHz zt#$s78wTr4>4kK&qd*~sIMa61smtxRJxc&JFGFU1Bye7-?=P=+uerA^w7V~z%FJn{ z0dnYRri*j$yJd0KwSPoFq@$x3FDQmEE|_mweXfo$9cc_~I+ALEhLAP{s5DtLb6v#wNNQ1fQ>FiYPG4oOKJ4^sMNFU-2CXl3s2o}8jzcqahLN~J6s14jx) zrG{mzCbJ8LPX0iRPwL}SB1kG8$`EGaY}?H%PPhK}VG_|Z$B?a$2LdPiKY643zkYT& zu;H-Q57+#QFEcL7JID6(2MXDWYc#6f4Fch!J_1^gfS?eNGy+*vKoS)Y{0a!6)P`sZ zD2`g+2fup1@9tNH=Lg73ew0s!?-v8}E zLf^8^xT0|AT)fe=*GYdoDIbRQI;{-XeN?Bzk^Qbq>eFFD?N zr|;Ky9rS&uNu;0&0rGUE)~gHue7}t<#O=W@albf>r>{KDGDgfJKgK<*f8+KdXLzh)be6d z31B4c)Kc4;3(mCO^r!-mFk4TM0L%Z|3Jb0_tG^Gy*C#>sD?XTYkpXf`>BxgV929^} zPq<;rGoD05WulKE_btNZ_08{j*7Je`9k$dg*v?~)G*Bi45xZ(YL zFlG-E#3=E9Dp>?L@J~N%c*L!eDGi{=AlH84cBR(MaZe2X}5I`We_^bG3>vWibmn!wI7u=iu`J1wMVq1zVr-K**CeO&tgUnlRn4 z^pYaBD$5}>Z*z;C3AIfLBLIz9RAxH2Y|W(g&*kb$?jjJGmrM=gY!abu2M49+8C1_c z5)=u5^U12?hfM=P4ql@u0Nu4by!8_&G<+UZwLltzwb7GKuQIPX4C86|OJ!DU%)#TBMNhpnwUCb^#k4OAxt-&4L@!TLT0u&e)Pr5MsSFh2C z&WY#x(E!{0vI`Ai2dVy}AbkA41JJlJ1cl`~l`voHIRs$NBVp!u3}7js;H=xTpy~>f znn=Rw;aGvq56(ACJA;L$FG9e1QxZLxa&#r7wZ8XX=VWipj!azLHZ#qaUB@6s6KC&u z;2B$fY52j%z;+tjd1sRV>#psEU9b91QqhKN0v23tg1nh@L0f(j7CusaUsOA>5L{Ro2GdW?gk<88GWq(Y*KVgt#YOL~(3OIaowTY_JmMri- z1vWhHhPGYY*InGrTSCyfGX$4BmaY0B;h;K_8oL2Lu^+r*KmL`nkOk!cusxRRW3m|p zqG=0Lifj3BL~H?%tnH3!Vn~5KZ}`4W=8PJ{OjNy%fYs0Cz}!{FuOkEey!uaq&{H>Z z8s5__sR<*kASfJk@(ploK`LpbCojUuxmfNI69IIj1ux4|3BW5n)CdP4sPRr2d*Ad! zGPsmJV+BAA+(g>aZs!0$ABO7h0IoOON-% z0!k42CB_7f6E6G)izU4!c3<1FE@P(ZCS;8b(6foFavUl094*KmgkzwG$P z!8f!-d%u|M#lnKe{zMa5HwQNgq^a9RXUhh#X$B{3Uqn`WLZ&X zH6}<`4G)e+@mp#>tB?fFr<_#xH|7v<&Yd=xy}}Sx=r;sx`(OS+4|qD0TT#R|zn!ZC zkLU<@iqa!C-2R2*q2EV)&zSVKqM*6qj&TYHwR|18DG$t~X8^5H!!OSA9o^2UKX9BA zuE5Do9wGrMSDWCBpIE@%F2csOZfM={%|1_lhYTOw)eqeVd02KwR#e3%Oe|b!O!nYo zTi+Hs2myJ-RyCA`@=lHAzEKmvuCFT8k>;Y2&cU|nsMrQB*$ox+9LORpvB)xdDB;)N zV#jXzFRd_ll|l9Hv1*5;_{9IX`MkH#uwNMFy(i(rCXPtPLEJ140l2J7EJ7X}<~$S1ZcS*Q*H}JgY}O zd9X<&7WV}cXxf>q>V)FXA}N90dZNOsVV+ZHhZq|^Xph+Wc^_XN)heT?rzVX|Rk1pa zGAPg{cEC1%hpH8{M%52YaOvaOU@1r*`LGkZ;2JZmcsLsp#c^!s8-vy05_@7Dd{v}8 z-K@ea2(@9VU)6}E2 z1A}?}PG}D91x}7Tq(nNxa0*_D70t;}oy1T%d4=ZlZo{j&7vleIm za6bSp*IM#Pp!JbkzHo8~Hha-W>ix|}@#GxT;A=ClKYX*V?GW0bF(6O6`&ix#?M~Lk)p(qB_gwkl> zRztjc;1gR@5u1aXui5E-ab2VnBhF}C0@hRc3E#OxR79v38o(oaU^ZQ*Ng5e9g5s(k z{=pFf&i&&ht;bNpK zP7!r4OJ?J?pE(H??*s&t0912(p-F582{LAdPF(Ox{ct3>JDGz>Of4r=j8OCeJ^Gtx;B2|y8s%4DqY9S-XCY3E4Ll`WJf$nkhBD@;^Bes;u_R)u13(&grO?ZNf8NMzJa5 zO@i;3%E#Wm#z0fp)8rD<%?n;2VS^&@a1SE?us92l8lvwO60e3cY-@ zmb3m_KmhXx$1uDm9Z>^hvz7Te(mFXA!bJo8B|0Q0e93KxZYi$3cuIi1{1mAClb|PU zMU&X75li?Zn*fB0N0a_d6tGFy%h#w*qL`qK5t0S3QBSrpFZJY#Q|&*j)={$i`%2t6VeShnS=BAEvlEF{H177LRYA(tQhHp5eYyJ?%kU< zyLe&);FSAe8@E$UAf<~*zyppec-?#x$PqGc8iODavzSETOQK;3z>+zvkuEAvCjtxs z_aE-#YoJc32O)(vR#DrvdY~z|TlMzS5q5g&3=^4W4tG2(0SJPzQG_974qzl;mD?g7 zg`Ipg_)=gJuyfbJ9fG#d0Z8-L$d({Y(PttDA$4!l^fGVHY@z4 z@X#8F)d&yjA41qK zVpswwiljLG)!mu;X$3`4S1BD3>QwU(9|moGOK9J*j9$uL?-MU%0HrP5!4Yh{xC{TI z=}R3F2ppoditR8UyJ0px6S4_=RQ-qeI$jP!kI=04=%ra)9}j~4Ld%!o4u-YyoHXFh zH=ey}B>RyGz#0JWW`aXS+3x{$Z$*E@Zy7&eNN}jYyG>ry=653ef z`}@

>pNzh1CEdv9H%Bw7h1bi|@|#mp9^p?2@|Gf)egMG$6hDzaA)HWdQ`4Q)~8O z+~y)}5oirYzT}>+GV;E0tG2M zH#i@<&Leh?xRF!DIN#0Jw-Si%urSk?k2MmERRSnTsi_UUcXdZ#XT+UCqDu65xcVA| z$W{w8{cHeaNQjhafH6n_MMm=e+Ti-t^{(}YqH$uQ%=9VX<_=*JY_qU476PE$bgUA_ ziZMn2DI|M7{mS#_E1G>9o1?ubrc|$ot8ex4jUQOq@?sJ(8UM!5F+>0%0Iuh@^gnS+ zA6M5C%Y`xL`a`0_?c!_R){$0TPZcc0i-%*qN4j8)5MZD+^wk|3osT{gl=@?CMT)D~ zBS>D!8QQ&tC36oNbrTl=AbULbNi{N^0D=-ae1zM2{ciV5f0Gq4uENJCs(lK$xSGR$ zq3uIETUCJ&F(uPXLIx8+kriR{HrKOPH26Q>Ihu^+sLH)Kg&GvQoNl4qi90v{k-TD`a}CZ*U{NW3{=4q1Slg)$r(rhPcL78 z??>_j-hmg!I8Btl>je1i3$0T_ec8jdphK0=%_wx|@UyBS1$Zx8X;-Tra&WD1n4^ z!X~`q$1k*W`J}dgnCK!qO_(dvxvMBc2%tzHZQJ8{b@f5-`mMNbnaGLs$%)7S0*GF*=gqC|XRql9RktSN0ZE&kk`k01fv(1p2kvVZXhnlxRUPEmpm5adZ|+3L_$=l|!L z8t+^0Ci_8}*k?iZ2Hbr82S#Qx#}L-E$sVSm2EaA^>bl@3S03=bwNZ-)YUZE`l8bi) zwr^$Wf;|Q*|11Ec@mAs|Bh3gPbF%**n+N{ynzrD!s5W{|1T^)~6_6EYa95*GXjyO9 zSI#03Rh-Ipvos=r&#m-5wq;=LPhCQ5((L_kNJ)qm5_<<+TBOlACh|t2bup%a7^^%V`LZNoyHWOaMgzxo&^p-PJXo zzkVVqLP{1HrZh>TfGGF+H|-N;@5fel&O8LfBrUUtDI|apkevVc%KfJ+S^}FIqkS1f zGLRNoI-k(e&Yh`BUQ-pDjR&u3?09+s6aNov(NA7fsZ7!`Jej?I>02sW~AM6k9 z|Cf%kI`mWlHVH}39%@Yh1>~;A(B_+Vy8iOKpajxl5klG!07H@kk~6q#2Z5L^7Ip@H z`&CkV4>cr!A|ag5fBgpsy>D-jLBsdUMnGB-U&fdoL)B5g&`~R-B>^ykLbuy39Da`>?Ho(xElx%XIr#)o+%CE2?#=yc@9_xj zn#T9hB5er(s$bv|9f2KNSY6&emdrhsK$I3-qbI{*7$VEIOSLoJbU1Q>#kZ|-sgcD`+6=VViau{@s7k^lmDox+i|pE>Wp z*(o%2MtVV0IwE5UfFa7hz(8o<&^HO#o0|KNpl8{x5e@gkgu7DZ!=XylAhDlK`Awa=f-T@YW3tz7KcH8NRJd%8TKN z0s;bzx+#UTb8dT@LWUL5LAN;8!w6{f6xQz1fqrsRYzz`532|HU^Hp#r= zdn}c^ibM?F0o^iGTsnaOcyQg4BJ}Z!|Eq4{(0hlx?|$N!93EMb#@xUUVN4U?co^u3 zjGme>-9QzVSeUXB0A#{Wf=yNCXuv7AwK{``k8p~s*}*rZ-#cl>F^+MJV;tic$2i6@ hj&Y1*9OD>0{vU|@7S)9N0q+0+002ovPDHLkV1jhik&OTV literal 0 HcmV?d00001 diff --git a/discord-export/Code4rena - Archive-2021 - swivel-sep30 [892486622401159260].html_Files/797886789380866079-D181A.png b/discord-export/Code4rena - Archive-2021 - swivel-sep30 [892486622401159260].html_Files/797886789380866079-D181A.png new file mode 100644 index 0000000000000000000000000000000000000000..3d4057cc482e6319a6ee4332c8a656eca0714f4e GIT binary patch literal 16796 zcmV)5K*_&}P)Y+YdH0@s&R%=1 z{jG16E%5(tM>GP~TJhM9Juj42|GL)c`3CW7t+Ut|vDsRAw$z4&e^I!K5j(%(7X{RNJ zGj9J+P=_;W0Jd)3TGPV5s}K}^Q@{*KVI^Q;tp8EQ!Bf5F`&z}YF!kH1sG(;&k#3Lgh^9P{?kYQ>5vEK*#^^E zD<9wf_=QI6_b4e}EQ~3nafEiOfpV#cYJCt80tN;;%Me8!WN8nnNzt{c+nn#dKbng^ zvT@_aL((ko*-qx?<-Mza4?lP}zW9ZkuzuYdyyo@SqfjYBDGx$= z@Zdw(4usUmtSW^*UYp4Di&V-(ISq9vAO4y7>?X+9ocXe~#X;|Vg}V8@ux_r9p*}@O ztN_Gv3%lGJ%jYLT$d$hFFBEZh;i{8Y?0wy%wLogi69BW-y72_~omvyYn+&`pi$Q zRmauzz4IgQ3`Hk6eR^{D@`;(fzVBDOEb-?m<-!)f=r^b4rn&*TKF4Abx*Ti7SPN+dO7YoAIJ)67z%dQoeC z(ug|UPV~KdZ+-OOQ-9}~&v)+JSuoOkz?$^8GLr_z2$)nOPzqVx#p9d5k3!MIiR({? z^(2&3kfH!239@7wbCa7Pvl&1wvGeoAnen}ozqz~F`OKzGo6IwR>)Bo(7eQV7&TB`T zo!-@=mc6=CkuL~>v~G|nSS4T!QQ(KONOf1I*lD!-j!E^d>FLJ0xYsR@ttnhqsNyW) zXMwgUda*&0C?t`AG`wa3-}B)6A+k)P+wG#)iy>8jLf`{dL+cdQq)zE7b(rYgr9a>udL%%Gqm*uDi zl?rFSvlvknAxR8i1cbJL@gY%2gjI=xR|o@7hSfwsX%QzWI-MTU3p)&&|JxD3wss3GZplP}Uz(G%g7;*U76>HYM`(wZVv6%&75j6B^O7~-^c^HOHbXwv0-1@CW(jl(NS#4q2AzZV!kc*z@DxPU zgqRseFST};F5lNw!@vE;=JW3O*EH*xpuV+h*M`IAlwLltr2G!A-nmdC4Xn1JJs-J2 zEmi{*iawWJNau?P2n2}Z44qcXnJy(Qg1`f$feHl*fd^0dh*OQZ@dgUT5)3@_(gcN~ zMX?B|BtXRUPLpu=o}F*{ z-d*?4u3PlNzxwcp-`(>|14|6dDOzh`g@lm215_kIrKf-_4Xy%cdZ|=Icp^n=Lj)+m zhlQ|B=yVE!R@l9D9uM7p5a&LBg&1AhJWoZXkAHPp{9bD}eN~8OU$dTb)OY4pi^>Bh zEPc!3Rl^@F4T+O8+4HhA6^+>@g3w2GxB|Z*U}Xj&g#!aoFGI7@LAx12*#HF*A`}HE zE#0gQeIJU0l%_D5hRqB-4xpD}aG-*EX#k_;Ww`pHSL3mJc4Ny!yKw5sXX3HVTkx*8 zzYBx4L44`vFQQbe;PQ(vL)ojK8kSKmgcuteEqGoj`R;?a-}2DC_x9fYwzs`l2>g;x z(~we-6c()|CBj9D4lZA54FVTyG&0jeq9a%>5b6}BJC5em7SL_bb`FCB63bT%V05gA z!CG4syaQutch`pPcQxZ*ebo!M{N0!D{}G?>In}6Fz4288&EVi~4vp2`>Xpr)R*}fE z1g%B~_38kEvIj%T#acHbqn<%$K7zCYzA8e}yre#Ag&OMR8Y;yi21e>gk{EHy^(;XY zN669?QQ8Gc89Y(Mx}|60n#+F?!==Ue;DaB>V-Igev(Z2y2yyVh1SY3u5XBk3@y*-u zwzs_l1N8t9DXfezF*%K`J9kamW-+?&zWYkrWUsK9D0`el#v-#BAc!()7^x{1gy|Fz z?_BQ^+eJ!2r9Dg@+>hxU-@|YvL49yFI#CBf*ulu+5TRFq@|VDqJ5jU;mp0nTpGN8A zIbZwuxgQTEYY$zq>GnP<0iH8Kz3#VPH`0une_S6aUMI^@S&LLyXecQ$I52?FFF=dL z%}!|*dfg1o=?FuWF{GUYNGyhmgBThdg=YdR8XUo87hj5#PCk`D3p^I-nmFwt?)9)^ z?{<9t*3aRTwP)Zp*Srpk29}`LYQxV}&;2H~@6(_Dha9a5fo5wSy(mVdPJz$jksm&S zTfY1)?V+;k1z?7`+}l2WpHRvYxL3{gfj4q#v>1W z7YDZ7i;K@*gG@?zZrue;K?CIwDF)zs1(dN*c>Z*~olN{{f`RkmWre@|!lqY!`4>0c zJkKfdoC#{r__i00olt$9S4t{Ya;6E84x^x?Pm4=9tzfJ`uM?ruOfgg%Lo}nYWN4Yw zqWyag;wxYJIwtl{LJ5h_o%BU~@Gn1v3om*BnFptF92_xZv10K$?AzJE3!Zl&meiIw zt*ll`Sh9Qx>;nQ1KlB5K@-)$ygfqJ@e%T9Q!UW%X;2XH(o`1p4T?dWK25%b~3O-w@ zR6N-1S0GRk@EmX;*ddzBk`%NIybHqpEP)gjO3}AU-7@7V3O0jM8hdw-jEY!-lgEe!*RvDhwj@J@}=Tr%iC?e8YUC8BD+QhWEYrPk;T7zxL>JvPNC` z`fJXv4tal38tbkyN()%eAuvU_O72q9!W-yFpgG?~+A}D~D!e4bOE`oFQ8tlIO{_J3M<^jPVSq;S*M?dz>{tw zSm^_*fQKI1jCP~pG?0o>s029c{8O>!nMPXANrSO4&Z=RSYW z*vheA@|1Xo6rv=B=ioipCYn8(IBHN5_0Z`w(d)Jm_1frmTS$|x^W}&ul*ph=7e!@I zEDd1K9B}u&Q+VY2Q!qV&q7d+P2R3fxYn`Y-g`-g3ppddyOcH(Sp2_yrH-F~DOOLvs z-u#|7S0|>Y-&Gs&UoOi%k8+`JAsyn*AuWtVx0|BXjNq#PA`z&EgV^}eU%@pSUV*RO z^3V9%Enma-AMQkE)H&EviY?#GEIt%el_ zQ5vHc#~4|(2rE`Ch4f>11&zfg)N#V;i!pY}FlOZpy0(c(N0^)MHj=sY!;97E?n|$} zv?`?k0T1#tY3bqQtT=ro{#Gt9{x015N_Qa3sAUaYYgoq`Ya}(%wGK?%;)w$%#3;v{&CU-}=kgPl5?8&1hs14U{ zsK_Au?b>koAEHK9^g=C+7J$kjHO&(dQI=WE&bATwAkMclm~Btu+xOjuyC1p(vz=*lN)y=CnLz;_ zhnCACtW-#CggEUYDOz}e58wAuKmj!fv~Nhz+Q zbdhpFQFCGnBa30u1W{`qQKyMC>g8*e(V4dKcl=85fl^`g`<+xpV<$AtjvXrvmIA@< z?*)Z{;&7DAo!2$`)tNO{w1UELy;cdwDpu}#c$?Vv$d2N+9TTr!bi%SdSH5%Y%^NrV zu0AS)y7t;@RkPB3cXdSlM;*?V((W7*E8z()sLo{P!z_ez7(Jz+b>YA_s-WLC#M8ZDHNa`ZREk%5~^!}MvNs*gB4y0BlQ3&45p*jLu-cz zzE?Ejjl@5WF(LYJ7Qr}k#)~0e7-xGwd&$kGf}csfP!X|0p@|H|v%%#g~n-Fg7_ z@xE!(hOg{?yu75{m|BLodD`jASF9d6XYI-;iOV5#bjtYfz@pTuk z933rvt~w&lPeoHq&Ca1%uA*EnflyYEav{TQx$t|iTEUXfQweMmAk+gGE-%8;!Npj! zd<6#UBj~j>ZvWP8c-o=tF1ytiq?2Jf5; zYDHBYTdqrH@nk#k#%<}2O`C4$9u+~o(HC=Fx+!gy%U_8`*$zAQOS4E?~Fn|7z=9tn%xaS8&eC}9H)cp9FP2qoz! z0qtlV1EsCw_GBWVBMZbDGEPxSErv6N5wC!%WJnK4AP{w8%=IkB6Z_#;zyG5*Evi&L z6(sT6%rji3V61`G44b4#(-^Jx9NO(!q}>*DoIuDzY`oIvfa0d>uDfpA6C-~VpB%C2 zyXe|$i$O4R1%k9@q;Y}?g22sehmsg4;s{f#tj=LMAufFmvU5He<`iLFA?sy87Uk=T z7r9yN%M40#tq5F5fes^YhNdPGkeP+zLZ9Vf4w9gr1w3OM8Cy^R2B9#F5<(TimjM!; zq1kJr5w%>1oD@>Iwiv^aT3+dPUL%X)3Zp2bd~G7COVb2#)I$+zK+uR8~@~{byD=6Gl;G6sQC| z8zAffqLo7SGMJu57x_Wa)KuzY|9xZWio&N^6B2>4@I(kQ+Mee@ zQFFCLl;&Wf6?c#lmq>{)R2ZsMF&J1F5un4Ek|$r~iLSM_;%8*Jxh~N$r+eUj)42Qx z9d}{V3{-NXy=iOlKi~N8-uj#gi4r?vL8-DTl`BCRf}slf8?;bv74ARJ(F6sS3(Y$J zM{0qf3#k1~4D|$RqKL9zM=1yp*bKf%ou~;$a*+!NPayN8TXPut;ronR33`_Tj)zN< zd@Z35l`^))SQDeIVSsW;Aq*@6MQ2pF^Pr2+6Ut1dak}L6(|vESCXFBDAPCw`F6UNI zyZV}yrV+A?@Si8(Z?%co^0evy9K1MkLHTBp^whAMd-g}8$_w!@XX`0ItDqRLODyE> zCQg!dEDwtaj6`MxlGGy21Tq^qzl#(RZxlY)3TE?=cH;YdO)aBi>E=9-?Rk(MLm?8C znuO;AA&T$`a8&}M^6w`)fX@8hTVDD371K&FPiWmO};TPA0oLgCjSP(f1XZDgL za;BOvo$D1{28%F}BKV>X<-~I!o2MP}hy?|koev?$93lCHq04{6g#&oec~HRp)w7(* zKsMXLswl*YatXy$V`_F1^K=>&O;-V=Gzg8UDLe%I8P06arYJHVM4E_j-wUBU1+v?| zVC0olDV%9FQaE3#gA6U%L!>iwVu2|08#>lsQwhEtb;W~=Pg}SDRsa6o&(E?>A+Q<& z!xdH|Q$VUIn9RZPUbll@)N!nRnrNLFd$X5xKJ}L0`JE>ny{8TD(R*=3g1YLutIAfy zzbK?Ba6p~Ob5A(5E@IbikQjwb2z33-#-XsrE6o>*gWtBs`@~$@ z{g+#AxP=r4Hh=hI=cIA+p9(@Op);IF?WiFN%SD|7A6X_rLf1LIMp$dr!#36Ld&}>< zclzjwV@p5;j(H2+dS4utq& zvwV6KD)Wac8oo??DN07WM^ z5+-SfkIqh){w~ebx0V#;<2T)KQ*%K;3&Z&6quW2IB=E_|lYI~#GOmN1 zSOg!Ei7a%>>@F?T|9;zB-twHAyoK{TB0-HTTQ;24=Ih35BQPmoh?a`5&ezHHi{>NO zGQPGs%%%~ndgz?!W46_G;cZ2VCs0TW%Av=AnLZ94=ek6DN6t;#QeQnI>J$VS4r;S0 zKxGPzc8a;_5beo<_DFTnpI*LZZgiHC}wpcw;|C z8v8M{bU$hXT_}GF5?z-(DRclx<#bA$T(6w5P{Hh4h6Oc%x}i440ElN;0I( zGBR+Xa3($aegTDI?))aYgy#HG?BBB#^K)b9MQae7Q;~|LNXguL5#YsxIt{L~W?5zt zY0pP`$HTklPQ7c_@QW@OE_=R_OaaT|PA*31@*tQeNa18$0(k|5=xK^1j+ibjYqg<; zsdp^obePPGTP%ZciK!V?slCS zQ#37ZT@mmN5uZd#zXcYaR0utfb_d!M@JdyLssLkr7$#z70`rYJ+LINu+EuiBOA#d} zA=4{iFoHzZU?mw11COyVU2qe{h)i`tW|)QW#TZPfRTm+_LBru6YlEDya)2Q>)6{L9 z<@HUyUI(2{3+;9bN&Hji^&eFM9+pNe`_AKovsiLT;tlxBYqQx9bhZw2<2~%1-Gf^F zF$`6Hh>|yfV%UY}B`Ek2d_Ms}x#Q{tsT~WgLT0GKm=GqC$a+BB@z9Nn=*A^<<3aTF z2s%*>nW-Yy%V2CBKmiaX_h?-8#jYYtkZ0|p#!A~la57KH3#$m`+S%U9syv${}$ zhOvR;5_70Z%#p{;7Sg}0i2=)8^~B|?GwuZI4W(&%SYvm%(mSjl(^<4eNpC&q`pXPj z_|EZ^%EF}UF*ms$?a3Ylnh4A^eA$2sX5a@?@cmhMG9oYP7XQc!MDU?)6*?J$O@?8U zDuk)Ph$6J8A`@j~D8ta-ayfP6_9&8tH82MN%m<`H?IOFb!h>s#a1J%J4?ip5`Df1K zvgi4z6^I^uxBhSqdg9i9YMJlgzyqxU`NP<~cA2tDq?JM?Ur?X;;&c1tumpw9&QrYN zqJcbPB}a9HEnO+^5T31R#TFGOQU$@v18dSUNn1K$MYs z^pEoF*99QMN3N9%$tsLN#SuwZqQ5-vLrOe8Iy%Zo?J>I@mY_U8+pTQe6~>lb!aVUE zL+?o$Dr+K6_CQrfA?;$fws72B;DR)h$1fxz{ z-1rfG_stCb5@ixd+k~&1&R@y03beln%&CQlop~d>>Ksu1hM|UVZuM1$4^$rq>p5=y z*vHd^Wl{H=c;%(QtFA~e5XKN<0GfUqLnJPd)2XZb)`HgLn#G82;z-yej&rTzZ@D_G zqn>H^w6lKZi^J2XYIQb=dpo3z&NQ|l>3=XU0gAanMR;-rd@~Ij?T1a~pk&Fd1?08e zY^5OVJSv4pF*LLb^?DoKxQaao*TLAA0;uMeivnRt!wDomb%tH}k3#9YUG5LLnEI34 zeIb{dM2b^RNO8@@Wh^N-9W#}A)E2ZzylB#znb$*FV*KRI>#+d95z-Wl2`qbYOoA)+leKoSNeXm1Hb zerK%{nF&rBNeoq-oq` z2&fJuV@Vi5A_yb`C_96|Z=t?4g7pkMVX^k)48@6^czpZA2yh`{@`ic(PoI|JZ&+wa z)5Ts6Tu(Tu`)ipco8dv4#0iV(0HK(~`Rm)b;Pf$sss+uz^C(&7Dh3^c!W?mmiyR&S zKG_mZ6c^G+os+9mY8M@Hvgo|a>VX3X_`^T@q->=a?@Z7==!>kDxCEAbf^o*V@Hb5% zHOF|6mIKULUUWgj!0yD7;m1&^bn|jbQ$VvNFf~QJ7=y4Oq+}*)K7$t~K+bK1{Us?c zd7=K2kCRp-v=Jm45TXqw<}q3v$4f3e2_w}xx0DeKFy2J-%e*`WBWZ;>1zd%OLv<-K zO(>oqO?W4eNMK0P5)|dv<=1MBV`};iQ=Y;2N#)(Vzprjhk5p8uAW9!xv(TZM-p0@@G(H*tYtw&6UaffnR%Ulad zAc7bYZAjCA5?ur;M!Cci8iS###iB}#3r<;zGgn*qq6LAn3sq1^E^_>YVc|LF?=dUN zX_L*6u!%>)+N%UvN^_W}EIT7>h2Lz}e?9~?@q=IOtbXA=_q0rMEtKc--<$(#NX62$ zuw-&!keNZp0^}Gbo^c#pqgloH>=2@;hHiT$8tu~&d#4~~#19gZge!9^L=O@XJi)>0 zLYYbUs*Pf(Q7dN{qF@F*RLZ_9FZBvQyZSc+001BWNklO$+;j)z6+kJuYJ+4Mj73=}qoHi#23HDJ1N2}bnz1<`WcI=U=Ch0N;Pz9IsWDhxf;2@4zYHl0 z4ooO?5ugKQ+mP8L%0Uy=QiS0FAJw4@l>r}>Qiy`jJUyCAl1H2vDYTbi>1YY3t{K8W zKxpB)9u!1uP8fYZiDr+2;+o?UWprMRkt9)Hlj2;PX!_zDVDJmHe7^6mShRF(F@V`) zBc>xw7qiU=13j}hkYnp;t{A`Z^#LH7hcyZjJ%5=YD3l@O39z0A?UfM;frtUctPDjw zsOI6@{RnjfRX;(s*uy|ILapLsc(jOGH9#>`@Kg#dLKqhUVPG#0>JcQ6Lkw*Tiw8d{TN?<@xHGYlv0EVY9y12dT@2F;3e z!Zc2E6FZGNef20ti%iC3f{Jj*utGZ;iY&^4Gh}oEosm8w;$zlpu0ecc)nL-?A#?S? zu`BIibeTOR+`?qh)>_Z}+z1NTsN?u={)dqM<(^o2dM2bu!ZM61K&Exa%SmA%ZH54C zcxDEHoKvb9arW7I^@RMD)M&>@w2WeiIGHIP=F3R zP>UENV@52clt-mpVYSZEZnN2B{>3r79g#-yEJwQ&n`eW{=ViKMT}Q49Gh2YP2@0YC zWA{Pg07^lITE$|hsxdZVF*@WSbn&3YxoP5oSXmB+=o$HCD4!IQA+PQPLkfp{TN2Np zTma5ow;C&!E_NY^TBV4B&sY{Ad+chgl*iCXj^>#0L@I&;VpTh<=oiX6xjr$socZLv zZVSwpcW94wP*LO(Z>X?teIkq}2Po3nZg>2c0SW&45ew?kM>i#>T>Agr&`r~`3Mzd? zFDt1)c2Nl@v3SKK)+{fhTr9idX2C3U zn2wgkV8apL6Nn?S5KM>8+as{j(3w0(Dds$%g?=oKOHXU2#ld_oZ$~UBp4?;K`GW(i z&iaGTjxCK}xOmNQZLnHEwNOJ)DMBfVgfXI=*l}@nE-TKOv6vu#?tB@(=bAxLw=6o1 zNi3-fyyB`0Q1J5g29|I;gJ$9h6D9}^s1+$==FAriT>UK9HVTh!wsThdY0xx(jz4i( zO=<40IUk9EL6(|QYrC#;gU4oN3j0WC*Z0GD$JDFonc3N6#!7IEkBXq&ObW)ob@tgO zZmutu7b;ee(YDjncuaWV;4nj$Ar1wp=~t0;=oc<8kf;ngIf9pqej8KcJF#-zA{2Z^ zg^f#dW>O`q6rBv1vYa2u2_&~r6rON|s$&b8mq!Mc4L$grYn3C1`@T}fx~CYaPQU`S zILTRi3Yo3kSfs{8P&bkKxfP6&{9KT-&!*zL?)~J!Mq~fYX`JX(OK6!>E}r&XLl4$9 zIft0Yi_lFGu@TX65UCA$A|+(vo-1K7y?+;$E*S(vQK|Kyv%DXlE8cJsUTP~#aZJAz z8~a$Wf}V~t&yuK)ZQ+9zjRIvjo+}@L0-G;t1`BzUf?KOE|X9l__1 zx}a{q>ErFkH$VEZ$;t6=TM;|&=#b8jri*-`&{%!KGKB2Q=W3xS@?1v=4)Ph!fy}j* zibAl!_lexJ$=65~eE;8!Q*3$}ckn@3lLYOQB&=~?> zpjIh6Q{}$P$ST>pEbr9M?=s(khjm%F1QC6qIB~j4_PjR0SDx$V=PuT<4LSS3tk={< zbg5~C^A_x3&d>(ijxGpk;Vc(~Wg!MiB}O)n-R(IM6ik1?dkDT~(_{P!m zqn>h--}ugVR&L$4|C;aKb*~=|4I*QrBN$rG;k0u&pYr*qJ*DiVayj2@@GDB8tNNpz zp*Q9;>xnXV>rGyYlYc+gh=mN-TvJK7<`o$Iav7(sEH)s>pfw|Wr(zSDb6ujztHrRIzIfzipZHotKj)19GseVji6jiDCr`N zb92ST-!dP(FRVPrA$A-cHOfr_W)<;Zu7zk$Cvjb4-UJ`%@bZxn+@znb%yDN!Va5J@ zis{a>-&O3%RPb-KTex?xeA419n&)n*BUfs{sLo0F3E)2!eq!i*hetHHHX1J$0IU( zsNXh}uid)S@1@7|WNH*m9RpEjMPCQF3$0_XLwT{epGeKVMy*^AoZG7KZGu5^%| zBf}Co)>yb&8b*>emD&LIA9x5!aw>#M0n4fk?sGwg-7!7xldkl%Kiyo0hV!pzRyoqS z#^jo$-5Nw_Pt)ge%bhkQ4%RDI$kuO%?dTCkr`d!!@5#i^6W%K?_@Pqb4v{-;3#a{@ zKOV70edQ~+E%tr!JH~YWG_$?snbv|u$~k|-+`14KoOwF3-hO1gIS6)^V%&-Oc{!{0 zqZi3wqaR?lsWCIx1=1Lbi817Q(>&m};7d`g1Qt11pb#jW9Au=9HZn-*^fGtDl6>vC z=bHI{hJ#N&Fz;dEawoVRvb8rMA|X1>Fr&&MW$`~$Q2)Lv`_Fj;kY^6cVLNTCfj#?q z&pS^i%^QI9^;T*YEr~eIIP0K1A5!@!h82{n6|gP9uDz3})ED<5FGC!zQp)+D3nxYe z>$|mR&rM_LP!U4|Au`u3#W_lD4mbgkZJ>>E{#jm?L7{QLscGy+NjRUIzuZ*1tRlM3 zu6w52ex)DApc%}gz>KX`wa8=CDlPEw|iK`ob4J z_Y20P@AqYTu8=~qcF7%(6`4MB9s-16h*Gfx;RQJTly!J)+jo(6r=ZG%U|$MXO7l$H zM?pEi2&fJWW7qg3PFPWOo0J%nxT?gw-Z^I*2nzZMwO~I83V;xs3(*2?M9@K)PD+Ua zc2i-2V0Anmzr*7hR}G&tM1Ax}VpsZ5vS1OG?=vF2Yhh9y%f~}DeYf6r+w#<8f1-8r z{|nnYmt}%^aw5k@qEM)ySg65gA1e_eaSp0MtyI7TXP$)lscn#ktp})0&+hO#hgK?- z>cbeHoX1=%%KN{v{}9u<$R=co;{eJ0vA&kAzSu}AZ*$FtQfwVcjxX+aT%lQX(LXo7 zIR*7pvXx$VE=KnOMq}8tnDG)eRPt*R!j%5%y6gV^)Ug!M!fzdtpl-YCw&lIn%txc% z+}lmoULs8D_IGi0ifMrHx?jCS>lr6)RUH?Qs^RyX7U7+XBAW)3}nzz z`XzJ|iSdIobT^@OAMIrX7kNOCf+6yA6@ex}s`KYgP&&^b%1vR8;G84t07Xu^=4Lh@ z4r=EDZRGZUVm>>`LeI~HSNPwxM11vFgNOw|{nTsJ*S~(tNv-De$K&4IO9N!SM@~jC z?a@QZWr7HfVrSgRnWOyBoWtB9#w2uFBgjx<%g%9xm9aj9y>Ke|QpMq9oiw=Z99an6 zL#J^7CoCI=<-pSq;=ev;M*+Etb;l?$6*L{@Q^j&-U0p`>EEbTR#2ik-3S3@9!jYFZ2~#wK8hz zyXY(h#M#F{Ew`>3I4kD?W z3yf3}qqy$2kSoX?3d{ARSRVRpr*&w15*}?a{zO4>Baz92d*2Wrn7CTlG{{&0<^{+! znYY}Z;nr8okziU@z-CjD8!_^4>=CQLusW0vPgfvPgY~PH;*ssU;0-K-m1PIJ+cT30 zJ%OM$gghh{A!B|7b-{)>Fg}Mhs|H-=>H_}YU~}LXZUhp1&yje29m@a4&+tx$B7cV_ zFgJ<)Z@a_LeD~KW31r6N{`(%nfyoZC)-f&FUAUwt9)F^sdWpGAL;Q{myg{qk4vkfK z96W}x$!c>eA)6zuRKsUAn$DbnTwsEO=Ym2xi(U3ZoOSxiczov`#MwbexemVdF|qH5 z=rnfW+zYS9#KB4Qq6q|*3bsD787Gg8VBZdnHOrPjvc`(7dt5jq7Yv1yBef@mws3_` z!=91`@KnL_dn}yedk&O1Az2t@F*P%dJMa9y*?+M8ckQmYZ7{6#MZ9q2WBd55g5r+N z0K#qiribPmbHCk-dQ1IcQ3QsX!iX!w;L4dl8X6X=F(yP-nioyKg$X6>D<5;S5!y@F zq9$)sGgK?#+|y3Nx3?U`=-4T)?@;J>;0;b;$IdUiy`!qN6tj&KwE-qH8SLNB4JOwj zEE1X#aO6Va@A2+5X~F0{Mawvx{2M=$3zO({;q!S~y7QR`?LC^?43o`iY}>a7Ch+v| z;xWI}@PE18G-s?@wc*BHyPm!|=CKmj(*(7D|NhdJZCkF|vv=<=l&iIsS+_CT?X@m& z0ZxW0m~-c@oC8ijh`YcD_(7Ow9r)Vi!;x6-bvkZSNan?{p92*87AXg*g-LMQiK}qW z5B8&wHC?uA8qXjocM%R5m|_q00UzZ+qj@01qS6Ws*a8wg51BEW>B)SF1tDO&4rmLWBn+p_1Z^^5SGyY7Xr6I}HCGjPx24Wuj(P}-G{l8E)g0Bqd&wY$E7 zawt$L6i^6Cs8d4eaaXitRn3@dJT2c&aOmg4tSmdKM@`rdFw?J;+zWtJBWBQAe zQ#*#b-FbImWEGg(=E^fg-l>=!R5-$vKbIMgQYVaQ!R8P?|P zCu>cvEiYzf-8x&lX>^kqEz`q|-}pSlm<3AA7LHwBIk#+(+H>n2)0SO&vQ`kWhqPf3 zS|1fJ#EPYhaQ5jZp->3>>s22la6RQLaZEak4>&^kjx}zbQ^nno!GGVrd;E)^_?yoh zn4X?ahS#shk}I$5-TtpMWIV)iKH`tNHL4S%mS~7fds?argJ;6`3&cc%$t0v=*a(ri z3?%4ic8K^GWMiS2+dZ0jsG7<8d615SkqeV-cAh-qSZ>li+(ggCjaXG7T&gqo);w|1 zYHXd{g7V^!`--~tkoCcuZLNJGGq}dV$|!Vax)`6H#`3{sC{{;Y<9Qc!wZ4lb(MHo8 zl1X1k}aKmu%Q@ zr{L`R8NcO*z*=$BO*hHW(NXuhTCMWY@AZ1&+}zxHt?Vmcve(+Iy_)e^&Q!6Gsp{ZG zo}I&moTI@kR&Ke#Rsk$cqM#_CCp5|pAi28C?Wy5>A~sNDIgHKFXf<(gdJ;49)0mu_ zKs#B#5s|8<~~$Vn=Y3I z|C{fZKXTb+*Blpu^>F5d6Ujf=v~PPU&hnY2~I*sK5$Y>KYWjUMUa%)#{Uq_nmaoH9xY~ z?N1tqB?Y_)lN@{PQ|d=f7FRXLz3WU4FS6SJ@xxd68&F?Os&z07Y8R4eOj5LRcOmL?t)c@ejGZ)=?+G!h)PoL2vkx>7; zha{+l-~0Q&|41z;6yD@X^ShqVi)^X|x7#+PmwX~BwxZ7W;BZ}hU8`!EJo+wq9LPOV zP)zS4d%*mLl>6FR$F@7cl6iM1jccHBcgb?n{@ximWlxhz^hmg`T-_~Gm7A?DG>Thf zx&FqtzWYDlO%`e4{C^%F4@*$IP_A1*_iUj1M@rZ$rLhGUm2%mz#DQcEC>$~ac}6M$ z1@r9a3%O(zMi;q*4SNp7kwc8WPnxOEfcGIbak)DbA2T}5eVFZHNiHsud90afP0Oq~ zDYkFjik%ZtYi#wI@A~7vx$#rSE7*55C&bgZzC$_i#*G_^gYUob#{d3XzOUX0*jF2! ztk+r3&jmzkhqKtrlwnV8Em_d)pgkWwCggLM=ma`pGmbpPm{oz4ENLF1HQtD{E!)kx zC#12YvBK*J8%|m4|4ZP94-eJrYaaT+gD;)me*fC}=~;NirF+{mQ{Vl!AS8~#VGC+O zs2ex_`p#Q#z4gz^W&61_?Oi!NIk6H#3_<$CLW(WcdRv3ASQA2@ZFG92L_8!sDVR*@ z)|LJa(KJ_~$1H`Mz@qzv!z zRPhUeSGXrDj?MQq+DYM8b6G^c|LXJZgBEkpx}Nm9rBKHV*ZiBf9Th<>jD!$w?+e1S zXO{MJA#dGy65%(k-(}$G2vv3_hi;qWDP(SGcH*VaR z-2B>k4`VJD^{L*PpLTkzE(TkUQ%MY@NGNj2HUQE+uJ&avc?n( z<*7!h+uC4An#3;#;+WPj{iN$ZlD{8QLGeTjncnO-CmX^1_8}Y1BGb!fruR?$m+RmD zXSek^wy@Vh{*`ylxn(G1Fb4UmI8U64vHx1pnAKqHht#4Mn zOxGm)`(=0RdUVIvj|MTi{L~e&-0@SgY%VSMFsIQ;{}~%YCfaG z`n(n;WL7-7>E_$#59zFb%!id12+ioTQYb(RnfA{Az{V@eKjz~?uWUY>SQ#vRxt~BsO z!0t#dZvXh?sPa%H8$#F_s5J0QbX>0SNU!CY-#;$1ZD?o_pb8?^tdsJOTDW0i=avnk z+Zx~oeww>kOSuv~EPLif|2)1vF0-vz63ud{(rY(;m^eD(=<237zOi81yI(y1@Llh! z#`A201f2?WlVqec5S(r;9{G7EWsi$SDPgqqg47CWh0RuO+O*-YC(Nb|8@%SO@BLD1 z-{y~$lj*e;p?OrdbE&k3!RBB3i?_UN#m}P_J@uTAi=cXO&@qV~&y2R#q|Yx+mPVd> zQit?>T{SS!YeN~8DnWu`C=jI#i+ETxSiq7I|C+g(y?^vuFFp5^TR-y7pIb`luxIii z4dydGJUEB${-`sa>4fpa^=Xuz1>oQ_KK4_++;qb&-S@oW;=d{j)2kZuN4g!Ax~V`V zWVT@!CCn6-6bIk1dt&C2d;Yoeoj-ofd4GH2`Ik*CUv);>nQBj7{myqLhr)jRR44Tu zeCW71gZ94r{7--VV;^eofBdbwm)K?`KCygg{d?Z<(SJDX&c`3T?!;dnOlEJG+S9DI zdOil~MHEF7l|hT*;0Weh8qJ<>BUzhAQ0sZcP%CA32DO0)C2(7+@%`fHs+lQ_bvJE# za=+f^V9XEekjF<*)~dhz^I!X5G`{6sSz|^Xm}<`z23P(0!1^=(=Ixt4-agbTx$#5S z78^UZd{njC*YDUe?iGUqYSj=@#gM9tYQ;ynT!&FLbWI68?&Ir9NfRX27$Ji>i*S1) zsyk5{zFRAKM>bsk!KO{0JZi4PpPqLGPJo{4B3Wyu}xo;(-@+=DI2@0POJ}7MTA|P!Yms%6r;& z`^wkK76opTj*<(TY1@%e91r(mJuG#6em9zbc~{HbX`}HT0AGHVpF1vZ9T!3IN^O=t z<_ptpN9|g@S{8)?GoS{=3ernmUs-`7xNnH|B&@QC*a3!>DIQyt zR!yP?XS`}KUrx>ADl+2=;dI3>j7J6!92bfFm>)fEf~uGN1HJhqW`<@^@R7z1;fc6Z zE2@ii*1WjHVzq*o7~P0vRq$wb8&cRZpq+D^Do%A z@%WY%{um+g?c*jWGXZ7+nf?LMe*gdhOG!jQR9UI4Lewr6>w{3GBK)x6`tL=(Hi|4Q zMabf~09FRfb@7>JVYp`$P%enHP_F)?F061NjKBTr-9NC_KK#*-zAHHCjA6ZD!}~R( z%DliQ+g{%UJPK7Fg4%NL<~5?+E!z|H_c#6iUmZ2B@n0F|BmUEI6V!Y&8L4|E-!Ih= zv!2Q$K_Q@Jh?tw6Aagw`GMDx0b_{bD%N;*czcOX4{qk>Y+VsR?--pQ_?ZHv>SOn)W43cD4 zbhS=(oFwH=7wpq^>)0ao@Ua@CpM~E!F7SNe!Z%%eZ7`YbJ+UN`%RC#uvKV0PV6D0| zGNB5}L*E>%mi{Tt>?5WaG~10iJvTF7**88h+)nN0o4&ne=fZLRZ+QGa?4s$VL|1)v P00000NkvXXu0mjfy-kxn literal 0 HcmV?d00001 diff --git a/discord-export/Code4rena - Archive-2021 - swivel-sep30 [892486622401159260].html_Files/862404106545922051-D26C2.gif b/discord-export/Code4rena - Archive-2021 - swivel-sep30 [892486622401159260].html_Files/862404106545922051-D26C2.gif new file mode 100644 index 0000000000000000000000000000000000000000..ab30cb0b283e7ce8f509a6ea391a1d830bfc9587 GIT binary patch literal 91182 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 R8P9+fB1HL#ULNSR{vVp?_v8Qo literal 0 HcmV?d00001 diff --git a/discord-export/Code4rena - Archive-2021 - swivel-sep30 [892486622401159260].html_Files/892635967494692896-61FB3.gif b/discord-export/Code4rena - Archive-2021 - swivel-sep30 [892486622401159260].html_Files/892635967494692896-61FB3.gif new file mode 100644 index 0000000000000000000000000000000000000000..f863f1cd4e162d3a19dc76e12294d6314daab0a4 GIT binary patch literal 19019 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 D!o+tS literal 0 HcmV?d00001 diff --git a/discord-export/Code4rena - Archive-2021 - swivel-sep30 [892486622401159260].html_Files/892635968027394048-5E523.gif b/discord-export/Code4rena - Archive-2021 - swivel-sep30 [892486622401159260].html_Files/892635968027394048-5E523.gif new file mode 100644 index 0000000000000000000000000000000000000000..fc1666683833b8783e8e278f59fbdf7708dc5eb9 GIT binary patch literal 22391 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 DUaB-W literal 0 HcmV?d00001 diff --git a/discord-export/Code4rena - Archive-2021 - swivel-sep30 [892486622401159260].html_Files/Screen_Shot_2021-09-29_at_5.52.46_PM-DA8FF.png b/discord-export/Code4rena - Archive-2021 - swivel-sep30 [892486622401159260].html_Files/Screen_Shot_2021-09-29_at_5.52.46_PM-DA8FF.png new file mode 100644 index 0000000000000000000000000000000000000000..0f68f5acdd594d8806bab982159c4e6560d19afd GIT binary patch literal 101230 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�!6$l-**BY0B13PvGEBL`f^%O zWEppgsT>;}2CqwM`t4szzzK^?l$Vj{VDJ668?YXDT1x59%YUbni`xILIWqEFA#Wl~ zUxKN8@b_n93}|dm37dQjT7~`f$R&m<3bW2(o%y1g;ee16Ia~8TnT$7_yMj~4>+u(N zfI(Vqmi!n6^yL88EO=UmVqGm7QW(a-=u**NQow=~`s%2~1)es338`tWE{o3o@ftc} z!1GxSa2_EdLX>x61XfgkD%$I3%NbR`NQ(`(=mE9+h5v(XARb`FWi=&$Xru||w8j#t z`se?O{JMcZN#F7&%0;}S^mi~9PRo{fo<;;<8a0#}s}%%bw2;WuzxhW4MqEDdo7JDI z%er4}nK~J3l8KTN{X3oDWMEHlaiOJdX#p!Lij#!!xwI(60#+2g!X5s1M3_6kS05fW zVzSr+?N?>B&D1-8ga51~2=ZUvksGcL=m%23H2QLhhC^QtFzo_L^K3ig3}7W;2$jBs zB||n!zeO4}o-@)6CK&GD>Z%m_D)!7%g$^1kU{YfHnV4gw23S$VHhdh<-b8X#z=~2! zzhrrZ4s+Rvse=TJq%wrqU*CAPSQ@7NdG7&ZzK#9MDHUQHLJE!srt#tPS3Ky;`Qrl9 zs4cqG#div0MDDHj8cql>iMzmz@2>q_iN>BBJrbnv10VGH-{~|m1sqovz&xK)O#xpu z-Wlgl&sIChGQf%|;W;#XLke?XPg#cnjAY&xFU)@rhX3aW!{2j<+jF|{)t^^%Ui0Ad z3EAqRcYmE*2Yvr)D#ExL zW|*`0@daYBaU7mZjt68TM|+YcO;;2tex|~bY`(>|bz+j0GFUmL5j9w(s@-jTVEue? zTI&4tSGV)sGPVpc3t`1>QU;(}K5Fld0WVmuIRNVFD94Qx>fMra8)QmlnJ?%y;rh|U zf-*FUnT4`R%*y598anmC`1AR)8`=gf$+Ikf{ewNfA^m9DiAzJzvvUFouN$gci;oI2 z@A}?jA;CWzn*6p1yal$`FpW|F-OUoB;x70G(fM{loR1;1W*zXwP@xVLZJzAU*$5r+ z>)^_=)(Um%Y?V`;HB{07sJ}89LejX!rAn0n{?iACJe99Ps!^U#LJW9dw|<40Q&5M$ zgZ&HYyi^X?$SOmcsnk)RQ+cO3OR3Z3v5%KfrKLW?<=LY|ud`tbXtsldAMe9UXG_aC zD0OET>l_}eJ5zgDzV1)iAI!2Iu{GLGhFNPoftQ#U>}?hg*ylS;lO{$>;`)^5*a~b{ zwnVt!gV)tAEw_amOCIX52dzsrO(t3%=Qf$M{QArJ6b-%ov`1DNbY!g6eqXUxk-que zMe_}9^7rIbf}S{GVV+D7w$zuvi`I(TvV)t3L;g=2$)`|gpjrBAp@%xqaMu#T*RnRG=F>cTi0{)UI5F< ztmy9M6czo`C3n)NCB<1mo$r*d>mJ@yCHzVHMFr|2s~ijD+}3ZnYc;mG8$Q=bYdw@u@4aa0s9n{ zRg+_==|(1skEd%MU)Ic7%1)|_p>mR);Pidx;j+Z(dcW#yg+a(i|CXn}u=1$_k(q*C z)M7F19{_56HW+A}k33#=KByh$5$<`K;q$qDmXaspjyPCNBt?WB#PzH0FZulYs&gq{ zfn9;V>~#G@UWTdDkiO6p^PFSQcP7E2Ei(GYZ`#WDQj-T8J^1k&a|v@*`keuMZikpT z1X?hp{MN~U;R<=TA4jXXqI=~B{Q1o+5%Rm&8V{B%>uKom8P50 zpo_2wex;y_+r=ZtYahKeT$iPVuNm;gUg%kSl~haCg@rtfn7WPRFn`T70htMd1feQ?D7>dSu9=e7A%qv2+^eq;>@;WxZ zNAEi8If^XZa$K5H^$I!4@2@X!z(!^f!1%fzwqX2~DUrW1-`0?ceRpqu50!h#)Z<_2 z?TuHka~5k#RrE`v>JW9mpdWVBh)}JZdj%`g!Li(MjF;dcNbZ8q5}7B(?ngmO(~(^_ zSP7U`6ad%mmL>(|OB*T+NJBP8sRW`F#u{w-ckY9#t7+3qL;_}a!{^xPG|H3rSRHfp zgPH42)9j&ME#faPilU!1N2pl5nl8zB0%!c{$IZ#$Y4P6)*@FG{gr?tkYb9|9V{mAk z4;C(LS@i-Oe1Ps<@;T|jS~ag!N@I8QZg;PuUq(1%ZKQ;dN(5D*tpgDWAq)Y~)l$Hg zWlq-Vr#D@~jojYGy2fGQaT^x$#4~Hl@zIH$0+K_;3&%u)@QqMK(^SjsrkXCHDWl^O zWSg$6Lo*>izirn+F@)ORF9r?mTnEu%2Nh;SbfKxjTW6?gDC>gmsZqQAitxE|)4^&K+Ru;f7^I9vN5c5*|aQ?sqp>=;`wKH zaRhKxv9;{w+0;lT7iqqvey^MU?1PfY>lG!_sVm9}hsw`hB%kYk+SO^{bH0OFzYh-T zSgF$<;WpWMTY4#q>!Qy*Rk`rv642Au-tM#T0|d@%$0Wnf&WA_Dn&bl9jwbmDU4Y_X z$TL0s0zac5VWFyY-*I*SH!l<)bevvifv1iB1lIsyP7FH#i_uB1Q)=S)(F?cYU9joA ze3+%`l3QF!SM1_|$ASW{sDMRu(=7DE}Mn#WQ?cua+OJ-U&BwF??NNy`6v}lRs`8*QSx3L z`Jo$lJ($UqwxDEi#$$+3?6eKS4(5ob(;Ou}KO3rq1XQ;JS0a8a3VO{`ARi~mOVd`< z;j+(_!AEkbk|F-CP$5BvH?jTX^6|3utV_`J`zy5$y(X#5SaK1+a>61DBqfs;_IbB^ z=Fl8z*4)ky9_)L)Q7?*)C)>9TZ5(+p2{Mm&ZV=Ch9v7U|1D6I<`M4aw)r=*k9`6qJ zQ3q8i)CO>sscBeW6K#TslMJ|oDYE-rt=+VYXSojfCK^|4RZ_>Ref9U2>*E@vTg*Eo zA@!-)(Me<-OW6w`2Hvx_!q1Spl}#9Kq8Xq106rJwwCJ#7MC|^k+;kIxD(%+H7U$yv zVp!P0*G))V57*lOmyq)_TB9b`haz8>$%*Z?{Z9&^>k@etc}`MFa54O_Vf|-@{YO~Q zOHP`kDtq~?p)^8QH19x>{E9m(*jMp3;vB3n5VMfHh|_%Jyw>Q#w4m(Z?}6(sm0|O`Ec1U_%gJiAJc?5 z{EJ>ASE%^zRBv#u{ngG`%3Zutd>V_X-e3ZGgCRtIsqHTCGNfu8r04r_R>IH;NvJAJ zdO^@5!@>Rc$Rye7lXab}^psz>L>0_HnZ zZvEG-BN2RH=3vmWW)pDD$J*im-2wKvfM$om%EKY{*>h>j4W}VcG;moy=Ms54Dom-l z3$dmvaR}PjYbiqLI95AwQCfO12nggT)qd%+wA2-jq;#)0a+SrdNlFKTcxMeIQ{c7J zePHQk($K80qWE*Mpty4#RQ&{Ugw+OoN8n8ibWBZhj%LN(dIj%cmpY!*npZ4jvC|Ad zd%SwtMcW9=9min7d9U}MN3DJP2ADEmsJx2;J1v5l755(n5IyKAYp>J{=e$aVJALo{7>^9Zvh0Q(z;1-#)j`5;u> zsl(aIDI0J+luun7DhLN=7oi4-+8Syx9+90LZAKST{`4xjb%Q4Bx6^e#cW8usCUuoM zrf<55xa|Nk80DvtmMZ6)4V2)Xy_H59^$I;{JIA|L+kOQ?VTZ86spQZbG!hPfK+t8g zD50Z~x#d6MxCIx6%Oo~gB$u7c+Pz(D3~M_DK5cn#GCw$&NGGq)*N``y!fwUQFf@<9 zl0dKVHdD1sc@h+Yz?tH1kY0e=`J)W>q24+@m0W~i+m`kF1?|)p*|fN+Ht4hS`J&HW zzHe9L(2C+4H%d z{FtbSI$TgWHIWc-b=XX@DVD1081!|6n_Oyj+r9W|+~29+gfWuEKWVDH?D`S5RPrLa zBp9P7zqpDdxI>SueHwGvM*}>q|D>ZJpuqpsTybDc8yLa0wwVBU*kmU6uSOzmIlML@l8@$6w!?@>QQ zpxT!Um@6=(X|+988-jU9Df%;|J&K#JDbf+hZEvl-N%fHctCA|Ow#yR-#;=O@X`x!f zkofDMi4*hfPv2;V^uwqsIWIo!!kx5IYc2C5_Kn@>IQ~HGK@|A?ab>2?k;! zJ@gl>0A2`^F|`a~bAixW2c26~*{Qr?>VHQp3QWBzuWGt^6*n9?I? zNZoOahJB^q5!@ee#r-H zE6GAc2_ZIPJd!vr>8R$OvD#`$SRWkr&1QVAFaq!?VPN-quX&F?F_6I!a#@M;yFKK; zw^^>kJRMR}w7MPU<njdV&*7z2wOA)OmY z4K_ySsQbk4@4D{efBmoD!~4m7{GRaOJa(L%pU?aC?!u880xQ-b!>JELCS!oU%+@!c zv1WTFqq@N*5dj$e5AC6L%INf@T{Ewxfp<@B(Q8BQc0w+b3s(eetW-#cvqK4=b)83_ zM%j?O`0;f>idrHop%4-^iaQo^cKAsOf4=vD$8a`!%qOr;uw^C?{$UQnfo=SF`wlP! z4-=B9$vC;LYnev31dkGs#ts=pqI=oT3fTy}L^@ zHwd~T_c)P!R9DR?>b`GR!)}$uu%+L_&6GCGjVRT53kSWn%Y^Yg?+gi&QuBddbI;+D2=&WW;*-DfsJsTh>PR3}(wC;U`NT z`(<=FoK*+~5phe;6m59)#o9J>?G1`Ir<@|VTP?@T{Fv2K`>bl&td@mMV)?)*QfB?)LY6R5L#WeepdZ$4%Eq{LoGtg5as|GRL@F7VFE&6p6%= zmlz-ly938`x^Kh8Z=t85M=V>SmmvE-T89BtOw=$`}a#?4u zzG11|6^;8p?wp?VxBenc5_co+@dBIukWF1c%_ZOi8CE?tFfz6Aa9SHO?92Q)C)7TIqb8NjHVoyrO<)^bLBM>w@vV><4f(DMOhP{!qk zvGZhp)5E2kSBxt3yIlMXz<+EWOH%==X~oaVYHOZuG0M8HZ5}e8!`w|`ekVCRE1PR! zlgLp8j7}Qu+*VJ#VY`#D@rJk=oBr$1L>&Zt#@v*m!pw+8S6&(x>hyu1vR_0#P_p)X z(gQxj6jtp&Gm&LGj9OfOyJQ%-z##7UxVW`!E`0I>CcQp{3~NLkkmMtpsy{1RUA3+3%qOdTW%&k83&9KPkXT6A*~yHM<*{*BSt&v zutqxeD%n@xr+_ma**Qh)t0!5}qktaRTvx1oPg(fv_ve=-f3a*&^AR}=>hsi#Ly>i! zBSlssI8)^Ir#Yj-inyOyE!)nd0oX;_%XNdt;Sv%lKXctupvY2u|AP4KBPHrm%O#{@mgOrW2m8Svl)r4t|qF4Vv80zUHy{s_~cL?dbPEvy2WmXnnSI zr$X=3m)n(2a@n{ zomrOv8lZEImr*RJxN@cjBO4f6po!C5dnkIeUX96wW8c`wC|*5wD=@ZeC+hlI-QV#% zElUo2EQQ&_SCrG=V)ZS@yF3r!-q;hIri3m=j_;rGJSoAoh|BL2MlEyFtgQ4S9lk@4 zQm1bUHndnx21KI-%`XN1K@LG$iGwjy8zbMCn;70bD*}4CvTdhSv4ej{^SHZ;jQ&j; zYMtvZkL4j_+Mn{m2f-S0f3)2l`giOP?BaF(7Tl>iUnv=5XkI^2lb>hjrkJdE zw<|tVPbpIAiOOhxl1lF5J#bk7?_+5-AZC&mv+fMkz$5=tivXp=dW|fMD)Ut+4WQ3X;Ip`Bbf-nctnbQs-Mx zP;pz7j$4nt)Iuikz215wnYXG4-cnXGG|M7bxyy^I}?*$e{` zVrD$YHhSInB5AN{GFrQV3WwiKLN&@dBoJrT&6Ca^54W;xS{4x(+1lS{l#cD_c%1%# z=PMUgt~tNHBzHfc*FQm0HL+2vs%X29pFbV$`u^$@qXzRLIWcEHm9ocP7G9IhR96(z zgsY2oUuwFQiNz!|e`jUkRkU~l*&>h3aLdqzf^d>$M~xJbSPy!&AYYcVie=c_1bX?9 zELr#PKI%aKGOfTPlfb7XL$S4FoP7aHSZ9}Jis0X$OMV>s-+M)uMyY@{KQ#28-4p3S zt7zfB(l9QJ8t%>owJ7p~jSEnY?wVTb7Q;)z!L-M8yzdqn7Dkgz#`ce=(b-hoRp`Dn zo-9z}ZEII!WSBQnOzLZ)EQ@nlO)FKVMdntK%EgkNlYpYyCThao@6{TiQKoq>Xt?Mwy+u7$x(j%4h$rcZ6^Iee_D?nKwxkjtsztY+y&j~s3X`Mb$ zz@0qa#$SEHPLVzT6&Eya1@P9oA( zAK7s>y}Pqm|Hmy#^08Wwv*2YSl!Qxr#aLf}XO}H-lqsxf5ob^Ur9C?e|5)45RZF37 ziTj=Wbo)|K-Jox`_PR*fzT(7TI?gd0v+0Q4%4n*r*=FXZAh~c|fgMkJA*aUuR_P5- zBDwVlu70q25!{d_SNE*erkdGH3uiHKW=g=98CUUGzzdrH>DS->R`Riy^AYs_|ZimDQ-aqYSb1+i!3_0+cl^T89Plf_NqIe?hzQFJqeIlvVz?v zn?>it4%`i0E9Ek$i&UAjsS+R`;!4p}MeW|I`byRlvZUanogEev)z@i^!@~=*a@a?i zx|HUYL1xY=5e^hG+uz}*;7W`7VOcrHqo0Rq24gFKs1(|W5vwzo&XQ1T=;a!`{1a40 z5|MrSD6HlkU5~RQpV&eEYijw?rc^XTi^UTv-33EryObMCY{}CE>1m_7k-_};^Fau; z5eBlIizHl`;L`kSLB*|8Vns3iMT*71Aa@krYvzSO2>4soF}bL>S-eE!FIK{2diAJGJ~E4&n-;x&L+m<- zG1*P1OQztKk@}{PAv-y(p~Lt4Dc1?@g7sGK!TT|}R#D{jVvzk{;zR8O zs$UqV4U@gPQ>gQPyzhRn`&&mPwr+@o|ED^X3}LWeYx6=*lZ7pm?@Rma@5IrmKMrYW zX?-|3?;csg*3*R1`ceOK!;S#Nak?8%#a=UiXYOQN_8~;3 zwGZ!0(funFEQ*DGWO}p}#%j8(&OZ4st9@*{e>GQ$Tlo#lJV4I8h?lrL*c~2nx;hOxJmEpW2=QoRkQ17?zt}aP zJ28y`^+(s^QH5144Jkfrm35}Bi`I6{GIm0psPK&KgNra*kc-KiNsi|_g&9pc)G(0qo87%Uk(j7#xZJd_ z`2(4$f;Z3hW`-|~FOhY>HPT5+NpXkGG&Oexn3hoY4IR{OPK`Y8LX`w);}^uCn7fqj z2s9ECNzZ?mi1rxF^}sbxQ8FJFYh}v)>>E``3JGNkbj8j7?jv5JW=#}82R!zUZd|UA zSnLrwnGyDB5UElo)r-+s)rB$y%2rg`F$Olp58UXHi14xYA~dxNrjc;BxEr*TX1Q$8ZD!X>a~3W}6;W8%#Nln?Knh^Blk;Up zlWyRMvm){LP9nWt2wKN+Xr;037gHF{_GGlTK4e?;FgjwH-p}dBRMYNBwXw;oh|?>M z6b9ntDTs<(6yg#jhP zVHazgp$!B$g3fzOE{I6#C|ucJj=5xyg_c6rga6#COz4`^IJYP^zf3Uy6|3nNFDuxK zIOQ>*~%+{w-bL^~Grm4z2%@BVp+F=%j<>3y&m4 z5G#-2wsN1e69ks9zPkBff$i6CI?di2_es!gQ$D&zvItCFGIHEhEq@bpu#%^*>}5P4m*@k z7Uj8y2Zuw)RGnI&2N-zb{@R(EgDLukz|2<*@99THD0b{Yb2e~l=7_v7G0>6p=vN&x zbwCD|!(jRIA+{DK=@^iXx{G`k1Q zw#O?6nupZUXeV;TW~>eQ`(~6k#`Vq;T*f%-@YUDHEk7pt87W%BdPA)?X+1Z?DveNYzm3)7vjyXmxX&1oy-G!pW&Sj2J$#l2_9OCZ4OgpKa z?K_6mb^tklzgJN3MT}LsJb(URnW_KNF)KSnFYrfttI9R&HGbU=y-(wfZ*Iy+)>tU4 z!@8tLU-Pwk+!5YVP~WexbwImC3u2r739_uM{vseTT)o?#cb-C8S=QiS#xXK8vV5d^ z0vBm7v%k1?4usyRdY9k(UjXtmQW3jPPFnD9UwK-gJB6+xjcRT86-x%icEeR!u=QVe znX0<3z4C((9hz2D)-x%boS?J@13yTPdN_4=o+$ZV$nnljLsED5%@_^=2IuJ2D}O}= z*M-Xpi*Ev`)ceoO%=$}mhiK^r`x=q0TjdaCLPjuvwUosK}vorkW-p31CS*`$yR*OHgIX+)fJ{!JFxF9KJT(hn zEToG9%q+r)d%2mis?4Tok9H3}4rHkHATYOKuH^TM$Uao=gkOKm$#B;Y|6JEQ<=qll ztVd>~W}}y`7P`~1bmg-Zsw3T?UA@#X`fMjoj4IJ;u+qu<+GnFtG2(ZVz-jin+DgkJ zK?_@{n|0^!QwIH5jz>n6B8mg$<3o1;`nYYREp&8}H~ooS4(mE9^4<4lr(z#=A{MS0P24&H1_ zsEbm?2&y$!UfEq@zpy)|fA4|R#<3Fb?8<#W`Cb6Lg%^+h;!C>FCfz(dA52hsnHkVb zQtbP=VVpmFSD~`;e)ctZQ(sJy_p}O&{D8V1|HYrdy`Z~c zfJw#d4p>wX7BUh0DFzawn4yr<@Ra;BWirAlZp<*D`m@^j%b0V280)h#{S;VAv53|h zh5A_m1E>Ei^{0xf?Xe-nY)M!m}Q+c8M*- z4rW_$dvY<;H`tNW4f4XM?ScC!ZZT>x(ZB|#IbZ3jor<1DZvD8{xbdT|!$+7*X~pL| zkOpxvs}G1q@&-SYvD*Mip6Xe*Pq+GqVCeN6u2=77@)ua7=qwd_=%())Hmq_8dl7H? zLpSvskFxgMZ%YXbr9Qn^e%cc2z3pu?PJ7S(_>Ch$hDB4WBfm=vFv@7du3CXgi+5-J z)_!8g=ie`Xy{pp%%u+}jMJD>4x@NRRoQM>)hSuW;8}@y_Af~-_EG^`~o|}*RTzmRC zP{}CyOJ~(%jZOL&C2_^$-;u1yqi$fN)aq`!s5>{%IUQrx;?Hs;EK=QGa3`id2R*+~ zZ62SWWNE&IKs+JiLPcb=`M9N$6zfo4)kNVbzD^xzr_R^4ZTr?G=h_OaD3=OVK@;k; zi@Yg{55ev{e7#lLXshca++KPfXsp3LT}q_!#-w1H;&l;_y{}Q}6hEtP)_TrLh&^%9 zo)cuBTzmGdbqk{=Z9k5(K!2b1IYb5bH*~B%9P3^6mO1)e8JY2Y0a_7MD)S=HJ8WqB zEZ7)kpjqx-B)S6I^%|Ys))6MGyy}1Y2UtA$ioUb!s4n@ZI0C%rtQT@RJGgeBzLL2= zsO#J1wSMYQNOBjYAi$9G?lecDJU65C+U?tNo^{Al36R)} zjnBe9#A|^Q;S84Sf@ah;v0C%$tqsot4@V|EH)a(jmzF;-(wD7eM2tCrG{`aEjFGAq{4xgmgwHsS4bfq;dJj<<+e7&|0;oCat)Gb#O!Uch~ZaG0aZP|A1 zxuI`dWF^WyOLyE?&-Mu?(w76|xLQMZClReKy8d3@mG(t#FK(cdsI->>A2OA3HT&Ty zPsy{AJXrlZe-UoX?rDtYKDgp;a-ie6giSQz3c$DqFN~dJ!lJBB4=gGPoAMHYbz+vo zBMhnyd}3sJ#P*FLmPiCXkgJXY@d;_rp?2#z@;10PKv@ctPi^gNIwh@0v3?53F8JHT zJ(d~nd(?@nX@{Rj!oeEs0?BFnZr&oGMMAO~0#WAQrVh#4W902DB$43V;Y`W)%1e|z zlBdCcA}Nko=f3OH-EkHlY4*EcnyS-B)&Tz*UlCqlwmTe_)#&a}WJ~zGJv7seFfQZM zF3^$Ju_R;VXsjR(BhK~V9RZU0Xx_FkfrG{;#$b5 z+P-(7xD=StMEh*!gVftU^|ErXR^6ea(-9WHaR~5VS>M|5D(R@R`E}^|V-wQ4Y~xGe z>Kj~iq{VwVPw?(C#TA`FIcS4KRqgvt5COkY|#;hM| zp}U`a8tfa(Dicc*vNnBKgm*mreFqH#C*0r|J~B2O7Lj$xZeX$jSfiD>b&nIslaB{~ zsT(W|d?vX{etEEox87>tX%ob#78MH#T|GP*= z+Oj)ElX4J2VWU;oTvjm^pwTK(zq?EW+1V5WhS9D}BHg zL{YsvcJqOHO?}he8qqzPer+yY`hhu6tDEdzuz^1|`w{^T7rQ*?9Xekb_+=Q2L)ix`4dnXX}=ZnLy+x)D%5$)DU8l;hi+Xzy39*Ef@im8nY%vGsdpXf$Gm0MVq$jRHptY7NWmcOv1N~Lk80M}h z6zry#N~3VWabqI9ttHi~_hv~yb#>t%b8t0GiP6E0AfrTG0uanVOvH1rU;fPIL|euVMkw+R5Libd z6=I~|Lc)fE@OF3*0fu@OpLhO`R>C^3&$$9&qN3&HkrMR5@+0+>ll=>|kJ9QkOpdhOM248cKDF*q3n7k%B^t6DSi93+ z=Fa$@^26k+&BUSFR|ZRdZqZ;L%RUsbsL2e$2?^H+cD+lsWLz!#yltkZlgaETvTjviS@R~3NCB`ZGdq-HrK3_j?S@{xvs z`^{Tq=b{7Z(@$nY4U8Y{gp%sfF!!*BeS3bRv*bt=yVI)xOU;oBgZ{_9@9Al;{ zUvE^~@M!W2BsRTb{#MKGa^o5df%qmu0|jYF;H6G21}YshhkI}j;K7+np3OAJhn?#*16;8JBRh}o5K6m%P)k^-7>(hfZuo=t4jnBGwNqKe5Zo82bOr_a!NG>|@vbs^e z&`lrJNnUrqEbk#yDl=-X`FW`)^6h-@jiafP?UsOY6mlRAE_2{&SQ zc1l(=e)ZO;-7-|NK!B!>j8J`u?L`0_RT9wTPxZLQMFxIz6$i5lo~=ccBNoD2%vg`> zhPD=*+A1?Fe|=g+_u&3i$ms;ZeSqiJ(Z03Z0VgQwMwmWtaIJh+K6O!tscnhVmT&qZ zq2>p(p#(A~?ohmSU(q9gnp^%XqzbL{Q;r)SI+^E^wfk*%f!5$G7sn_4EL(E(MA~*K zYHK!3k*274%u@!ky8Mx5UKyg$*ekpLzU4B&M+3#S%b74t)z1~vmS?8tL=h%=7S zg8Ax2g8V+OScXq#V4;#_2o$D))o<}g7gt~3eO0c$`jwu8RI4c~4-E6(7cRvFKjuM+ z7hWj#W(hW}|HinUH``T0T_!pcG;f9#13%l6_oZNU)6VAsEUdlNlMbq-aVA#cOo@Li zy&L6T`UuPPQTnO(jGV+65U=nyo8p4Mi{Y{7q-2NS^Qg;bKgl%13kgHm+n3ty_x~U>B-g@SC4)Gb5`QXOX`f0Clm&b zGbvrW$1stZALQV0{xyU5lK`>lmGH17>olt8z(oz`-=ukI>IjAm?c& z#0Aeex!%B4vcfa=Dn8BIur9O0{VyiTa*C0rGX&yPUPWL_ZBv0rLQ6)j;D>|yo8n_b zD<3Z8)QNdf0zqNQwN&-}gfSxe>^IJ46j5$91SFVvog4~xUa_02y5SdviXMM)mu_@X zKidDv)8X1iSXfy{hxW^0+@7`A=O(sDRk%nk_{(? zg^pF?iiIj)D__aTcmIvXz0(Z?83ySzI#j42NN&m46>DWlp?60{AH`CIj04ujM#HNu zi=xNdg?WmF{?HycLm(N|r^C$-Cc>y#$dt7IqzzzMNkq}cb!mZ|7fVMx)ykGDSLXb` zF&YB4zdyKqt-5E8km2PkCuS<@-N_DtS!rkrwSp2W5x(ev#;E{qH}X#z!acf#fETO9 zH2V3SX%4wE#aYmE~1F0yXn;=VlzqpuqiCH}yJwkyDWu$ka>*Z3tzV9!Pc zy?*q)?sv-A)4@@0sP}=07y#6`EW<8oE+I%EjUqD^@@q*W7g^{S5bzoFG}k?oA+Sg(`sD0w zbC)<@w}SkawV3`8uJz!=!SM3hikYHQewh%MkYrZ?Ek+Atoz!Do^1`~2R5`<4PEtKfnk5>A*%z0Y*Jifs`XI+l@)i{tLuV)64XwWe zHlG_JY&;`(l^)CR+#})UUv~kbT*;%Ti_+x`tb>{mACgXZ!Nv^m^ywLDWJl`$ z3ml4vcthKwtRRs!G+@OOzxaqCu;EmOH|Mfn2)Tm<83weLH1)53rS6WI8TMOc`OGdy zyV!JfZkii#$pN+s0YW#M7K@Q$v;^|m1YL2B*Hi8=w|SP7h0yF!f!7h&yvUSwNQmMg zV*)ITg-p=6EaXuWwPl2?xG8Sh5M|bTGVD>rsq@M8;!|;z3wojlgG0Cn>&fYOi|7kNe>E8@kEpGVza94J zq?^LCWu%+E!mx32x5mdpBSnj13CYQ!aZ}gDNcwE{`)grhNs)cuv_zhH^hlXkf;Vp5 za*u#^gbNH(4*PcHg}2zB9t`Q8yVCxD+Dz^;``A;;7?tbkNHsvY{I^u(^9^VA=>_Xi zyW|Hwnf?}T{)nxiWWC8r+wMASp1CqavL4zr!1%eeUV1ITtU=N;I_t>Rc$S~bKnGj| zkzLj9S0a<{-xsj2YCtflC)k`x$ z6k7w*Q5wCxI$QipAJgQ!diM1@7$GKzxVjRfP8d2z#4FD-aBqdHsxN@wpr~+0mngfK zvLnT`xsY0nN1K^g_{)vM;WvS$P#fxSk*c4jwj@$VPZIlof~$U7p&ukvxX+2MF!f7u zf1McQkWG=OSep;fIqn0ybs8O!m+&21g zlI7sqE7lC+Yw4JT+Li!cXT5QEx>0vSXNn?Bbbs92(MLBh`Dk)TiYM*T*mMDpe;T_#8RDuA(_oI_F{&fFyF!Pc|9PP`D zRy#)xY;K3dIPtH7twOhVE=G(>-0c1x9Cj)$!CcqH-xpZ5Ch(B6uAY#8v2`4c46u+{ zah4jjwZNZFHk(L@GkBGk2GHqzjQFJ161QBAKY_n%2pFw|Wad{utW1y7(cnsWL3QQl z*6_@V8ISFY6pmAX)1JSt1a59Enebps906F3z*4k&s+Es_fas6j0-{YM7v>n)L3FJ~ zm8K$aG|1_?{g8e9f0jHU^!`F``WOo@4`%+FGmx9jOLZjb%XJiv_s%c z%ELmb8p(WjIxOs2`|^Db@q(?B-@o3AeWZW&W)Jkt?NLPm6}H;W*Q${q)myIYJ|zGj z!M`NCWQQhF`i=!6VC%`YF|wmnhE_oX7jIvc2}fpmSs;lc9U(43Y{8&B>KyM6@AJZA zqHl|C@y=seE-f5cQIGQn^i`Wnv$)7ULOq#;Uexh5hsxuPC!0Eg$|UbCrsAFTwAiR1 zda7g)ska84?sr!2ikY6yLoY1|mNDguP%!g4F6c@>bYy)kSwTG-GIIhq6=DnwqFnbg z>1&d59fixU)4Itf%`n=2{yGw#>7HOYSe>==J$C|ZV?Jf)%jV!ugl*45j|c)uqNXO} z!p7LuVregVt$RSAdg4ypyH+ewwhBBG0!1!Zwt?So!Ano$s~Wj^Jqunc(_^3%vPH<x|I2`A@jI8!r8wy2mn$2AtPPCwem~j2`Ov*JpSwi^Je>t{$QPj*dV#a# z?75|{Un_ny3BwPkaO|WFyDXRe-oF4;G0+PGzXV=#ISJH?%`Fw662DLS%;Zi9H`Td< zxNHiTG2gzuHk~A-}QI&vr^IGU6hi; zF7Cx`%U(H_pS3#`&yS(N?n-)`6;aXt2=nmr3vhUD@*~yrr+$E*`_9BQ%=(q&NilBL z`uYaltkkakm0-?YM&g4VSrXhxO1RefU6Nc-;`p}iUtAjXn({qp%;?F3$e${}Q&M_> zeILHaqwA+s$Q!xb@miq{GzO_tckj%#^it+m%_iGrbW{3U4hSNBP79FKRjhsUts+3u zYxTc`&Pn?HoTQjXxqIIz6_kuFU3wi>1sW?6)La%R8T)OLyM9Hls)f()Z%&2%`U8@X zeq|#tv+I)!Un`aLpE94L<@y%@S79${EBxF+H!4(tPOZF)Uv)lfdn!}yeqwSKA~F|` zInjFlJ;wFR=>SQemkGs4Tmwk@yqF_~=A5LK07*C6uhd@xUQsIb=+=cG;1$7UO4;hj zw=GwLb;AO7?eF}x4nQyU&T&m5N|=sQMlJzUujMY`#3tYT4V98y_`wN~blmyFJmqVEq_>>k z+n$s3)wx7&_D~|cWD0vzN<~FZVntGEV3qvaQNJp;N@<2R$1>Qg^Zb_pf(*}bRoe7u zJnkG<`FW4d(ZX&G;EIHd%X|~ybMxpIGM7~-USz7KFT7>OiAfCG>`3ZW4R9`;b2&gf zae$;hjcu8sw*Zp<(9>kTcmDK0qT>IzqGBCD#iWOa%s)8(2L*qj0Q_mxoXzvnT&kp< zbN$P%!uJ6@D?j^Vl?F0Az{iRFmCFC;pC9bNPySn&TmghhUvm6E;`{&n;XnKjaBBWd zc2H8{NT2$-{`=p);_tKX|9RDa?&`k)@*gk&-18sC`A1s(2MqrK!+)!-|A65?VEF$I z4B}%+$H129ZW=Y_kN7^6WbPrwOuRkHq#Kx{wQ#)Mm()%PO`z44`EJ(3_3urY%fEO4 z8%d|w&fIOPA=`d4zMuwZJU)crjVGFX(p}LFy_}udXNEjMlMv5INcch|N-*I;QdM%T zX3{m;{xHSZ&K<0SYK9uHT+eO~CHMr>%%!@3Elh(9Wv5Wf5xH@R50VABC~;%a-CShn ze!*Yo;D7#k=?9c#wtY^#k1w}qReVdy#=|5Y6qhS9s-Qh~B(2elucEN0C=qO#zArI? zoY>EhhPevv*FgvfJ_$R_$daX5jknowiPHw8Gl%5qq1}I9`u}CYU5^F)LBB-LL#fuY z7Vujcajo;vdw~c)Y$Qq8Ng;F~%rJE@qj5XmWgpWLF})SzFj%H$GGpI(Cjn&WUi`R^ zKn; zTM*8Z`5$-iLnxS;dnb_IVsifI^}pW^$%Px|*^#-CuIJKuvVnU~fS$C(=ilbqn zJcrh;R~Z2~o(Xezz3`LG4mSPWNhTH9=9QAC_ZB8`Bh3?y4p|_>$`TEo3;*upxq*)d zVhs`d*6q>R+_ABK!syJb7eB6eDyD6hZ)V0M#>!7DGZk;r50=_{txQxzNk~7(j+KMC zSk~7$TTk{7fge~V;R$<$$*I5|X>e zp0SCf4u76H(TDeG>$8WRzOx+``s_WO|6Td5>O!C+eJesiNATHrdghny!2Pu(!PaAq z7%3t*kLj1Nn|ylg&tt_9R3AWwzUun_iYEMDWDg4iP~JWKByVNRGMft>u(Ky?OHhKY zrhe34I^GUSkxr9xH;m8$4>HS_hR$FH^F5RuedK8MfLkXuz8dl7-}nLxq`*lUb8d)u zT?IN0J_0>UNA6MpiW+y5$y-p(Y4}lS+*Eq~j>FXUe^tY+3k%l@Yyf;4*)Z9iz@=MA zaSxOPkrMyMY5res>)joIKgo66Er+YUB+iS?W(=NH@1Tp__k&Di63zapt?17)<^dC# z{ewp}eOqEGL~WNSp5mQUqn3K_Lou|$DUc) z$!aM;{FVmdH^sjv*K**QFm1T+Fms}v^+*R;r-MakiDaieQhzHa_XBqL%D+ne{f#!@ z5**GV$h)@%^DlhwN$O5UsyOIm+c*-Y;8p_7J6FA`rDdIe&Fjw-T?mIHuUS8?^!IwF zq|q8=u?Q}r!1fM@I?$=T+Gjwc)r|dax%HT>GWlcvp;>go=j<)n*y1E=dnYsS`uhFw zt8`i}bkg!7B;3119KOnae+{kw<7yBc->pD4A?mR3{~MkEf>)zHfVax>(H-5=zaHWq2SKpUh(vFLr%id5sTKmnQW zCbrH_csp~2$z?3oiDzK}*1T@nxSy3cY5=6C#a#~+7{!o3dG5~DF0%CIo5WVq_=kv8 z^#o`K?5<$pPdGm?-Ak&fyjiV927{r|I=~(w`j2e=TBpZF-3LXgsBng4b+28Zv!V{w zc2w@s+7sY9nqR%MHlbbjnDO7SJ0R2O0H-=X^ip+un0|Z+^-g>tT%y}J6GOd|l46y~ zVpK>D7Co3tvAG!GeKIM5=8l!$dpA>911xTBJTC1Fi>aOK!4^K5&=jn8v?cs>B`E;! z8dX>hN!&6#s2j5Dx_c%-nHh}3B3Y!Od>66WTp2H3m77(Y#z-#Rf;}w{OF`%}(;9He z-dn6}8ie%%IqvfwUSNKO=H7uf+jy-717xJ8ab50Tfvf+82cO6RaO^U{?%l2e!!19F zLg}_w#U2{Ay1O+Jagp(YP)sVmz4ir$X}iE{jP+@m^M?Hi&fat3qnaweMeCnn$aLLf z!z^s;4RJ>2TV-3W5rIqtjTq)G4(-o{{$jJ2CaQ}o zn|aK4Nu%|6E6T7uUN|d0t!fC`m&s9}p?V409uuhgHkO$HmbD4NWSA_rI;KQ+4yA3< zW+gq>{qUi?6{uFU>q+>DJ_c@F?rcu81T1L(j29lJOp9!SeN5&bbibHCZ&&Y(9z~?d zLK`{yi|B>K6a4w6meRyb%?c6;SX@_WG^wn78V~n@UJC~xQsqtOutRNhrb7x zXzJ~$DH1cyQ>29k6rYg|e*IJ7?yE|w*YwnUUIQFrW|k)87H?4rvzeV$v&Ze+#<&iw z9bp0;Tc$`?@xAE<4iy1U@shXub+h?Wl90n`KJsw4BeONT6M*BhGDVHvUJIT^V={hwWE`7EtZW)K7QTh11P~@M{FzeIc>3+(p?UjX z38%I;vO?bPrVa7rF!1^>YWZXCk;-i=48l7a}Ed%~L{5ZT%91j2P>hs2kT zxTq%n=>eMciiewo0wx%&+~d=6nALLn%|l{&%BoOeMh_lZK0hTkS0OQ$qDU>jT%NpC zL|!HOZc&@T((h&S)(LVVryf+ptA~a=2L&Omj2cXb1jqHb0 zf$|Mq#J1D`P+czUJN>5EHbVseSQ73HfuVr{nUp?o;MeUwm7i1YA0yaS@ja8-w<#4? zRL>1lz$|&kt>#!q7uP_(#mSPr0+cfQ)wVJD9jzhO3j!$5l2u}5h4pYF(Nv}W6ekM_ z(Sx%MQ^<+E<96z?E};(Qc>$CYsC(kY{+euFMU&2>Kl1KlFZ+b${(Web9n?0X@Ft9$ z9uorl$OmqiW|fEZXUWo_<}-OLkNL{#dq2Dji?1bQ!e(rfT7Lk{P^9yT9T3<*GNHpe zRPci61WEj2+Sckq$rf>1B7^U!7P_7_SPrq3fNsR)3j5>!b{riqcKqtoTAa8BH z?#!iLn^lM#O`Y%JjdKBeFZnPts`59|#j&x>hyn(7Gt0*l3(lKvGzFS|L!YW(zK2p3 zPK3|I!x%LF{3vR~JBouA>Azk0chCfp$^m(qAiYivnn!*cIYEt(1lQx8(5=mm>`vmo zd>l}Kde=QG877)wDchu4A>VbCU3SZK=avRo3K&RIVKISsnZ*zCK2UMRd)Mzzx>RZQ z%bna!hP-fCU8ZrjJh5Oj>o`f1Ue_u&-^)5T^83n9($YY~F)Y#x-B*q7c6&HDXrKDL#9)woWD6O4#E}>=3`?`*N6H~xpv*%Z+$Eh88a-q zs~hV-*k{!cR8Z%P7Pnzxu~6?YCH{$EE12|=P~ihQmgO+)YAim9$Gc-zo}2cIdC4h~ zXEFoyhM2@OP-3zNG@@^7bZR{ys`j-Lqn4MxIhrJyKk$7|hFqIj?`a0GFYnr|gC{DM zzI|G^Bvc<*fxGzQL5Z5*|1DJ%!~ucPt=eP9>%6_hFWia4xdVa&l0{s2KcBC3*lGP+ z{_OZ(3fPFpnVE~y)a_qN*+1x4g0TDXuXmnow?!4)E3L-*hCJfEo9~N2QbHLlP21NR z`m2}_zHaNuIxK5q64gZ_=f$-f{42kCn!;0j<-cx3ORj~ScLR^u=Lif}7kg_x5Rnz} zh`$yrQ_qpo$R}Oc5zE4FRQ8NO{}|L=V13?J{l6(H1$L(MZsvOq!u0ik`iBfQC!rr_ z&m5*J-t+R`&k7E*(Blu<_TdRJ7HVvKo=_}2WA;!NXim3bn3rfb09xbojZjO%kZw`` zg@NZwYpam;TLyhsfuS7)G{QvSL12=B)-SBZwpB`PBwfOJtyv|vmE?o*Lf#{vO9$QM zWBDmXfr>@el)u~3GpZ5IQ!?8-%kS1mt|+web_e`VmGj@u_H7!#%%kBS-KFyz!^Kn) zkSswdkf?iZ{tMcZ!P(@w&5&{1*9FdtWs6&$B^BP@ER-@3P`7#%#^SEqBpM4ysLA>a zU!k#o{G1=}?4`B`j$9TF=3}C|fv$HA3fzf8=y?UyQ~SNZoD@+c^5c25z#Td&?A+L( zG&uSMlV8y#%Ds@1EEr;Om7Z@I&OPLRAxBudi{E?amDh)FD~hkAzF!}!c<|B z!70D}?eEa4=2&JAd>@jCt!{@4&!=;(!gMsjt(2He zJ$8F7HV-T=&*tQrgYnX<*WU@#5KSx4B~@mCqk`I61v1{wuX7SU|E9A4>ia&}3PpesDKZVinsajefaN46 zO>=Aq&d+D8Rv|CEbQ@ha84Rb~x^shSrG~di&~%N*kA^f`ZHDJ#bUo$z)eS!R>=6$h z4>1i5O)oe-9^x-O;w(Zh!C(|IoA~(4h(`~ODLE;(Z@X4=dc~oHN7HN@TSOz*KQ5X}45pkGcSS3ssvdkw>H7ahE`Fuf= z#uPPqHr^^^qqWP!hfmN_o9A!6 ziN3wF!Ht_&xpw^kjTp-?&y9NVK>*2wahoxN=qbDyJ!Pl)_E zksp#pI#aXU5_=@E!9{<-Z~x8@`KRCc9<@e`#j0Rq_X?Z4&vQ9XIG-%}^8P6sof_?Cojiy0 z%L#Fu((0HTT&;6YSd$^d}+hy%zocjLGGc)g-{12Bcw3|2$C{@r|!trCuxW=LsiI2kh%DP$|yH7+M5Q=9(1={!Zc>Gm=hHdi*!MAt46tQGa8&h8j;2cXfT_N$?`-6 zYL*pfy3YRYHGDs3<%J|^LaxQwB^})|NRu2r%Sl%mgQs&945kH_7emT=n=DIdH0l^X z|MOpeXE9&0T&)OaOTxKNl7gQy@34!3T3na(pr6;$kjqNWE0X zwQV%rVt6(oi83@(!#nucpT zT)+J?4<9`w3_T1()=Z}krtuvi9!Uck}GfL<%7>}DkKgyH3T?Ce+g)&KXm@s~3e z^Es_%8{4tT6AfL938FcEGR82geD4RphY=TScQl%94W}sa;NB%WJDcq7mB~_*i{lmh zd%FxS7xcQ@^e^U|oE=f5IldR6>p8lXGhdELq5^N2&@NTkXf&uh70Q-L9w)@}g2c~M zIb6&m_I9uE>gzW!?40p%s?zm8_>J%KgCBpc{(snC;rkg;6w+*$>2XyW@mwr!zj38hkr`N}5>bJ8fMT&hs3HF0c{FbJqtDpH{7?p^2P>?v^^ zQsgPUjShG2-e57AlgBx6mf;66X_S)qI(n|NvC(Gkd6>414j6B}@%lT<#S-6}5iFJ@ zK|)@DZWx%Rfo|Fqg-&4>m<tYpF)or4t+{yhs(1|vP4Q71VKu(Q^PP# zY^zGisd4gT$b&CVnLJtG&874#$+MUwj#S!>B99`^uq<8S8^^Yp&u1iw&oY?v@X-?< zJ~`pTkDubC8m8-FIIaSzW??cLctoDZ>#twq#`Qh+_Pabi8ejkga*GAcUKvRNo1LD@ zbgNZFk`$y#fu@;s+HK+}#Y{Ypr0m#48Dxb{XJ>vHt?l7oXf6;mTzu6XOKw|V2u+sx-nKKSShMiY-LhoUeUO&4T^g>FEzRRt|0$zp8B zpu16m%%t1sG8(UV{N)KnESROrWH_f@tI+Qc&@?E!C0whlO3Gq1C73OUVvj7#)*!9O zRTj+iT&3kA&qL}91^UAaP_}-8B;Jt@zbb4%VHo5ok z3B68>BGS<^lR`6@31$frtWrv0uBcT@EXIjK)3#l3{qPDmuI;kjuJicuv3k&sVQ$ z*X`nkKIO7atJCD>&3&{YXFOifY_!?kxz<4@mx$xBI zx+PPAwxWnt#;I3ZD!Q{c1w&FaG}|4Po=;IEq)Eg^uR#)rRNNZjDkRNw{3ueHPp&C9 zGqNIA05J+ug%gZ#y!HG$v+q)|dHsVOgT9UIfIFie}xolTmZ3UQL*trEJu zEgn61NUc;t&mfJV)o!TGBa3ygy+fYIWLb!=TWoB$8IPxA`ih;sGNGSwapuwOwb#FJw4dHMcF8E_il}!eDr|Ds9@5M zAa}^KjL47F#_Dx?^!rnq^#)ntqZBQAStbH%}AQYNe89^Fp;# zQVt~`blp(jQyG$VR?rPifij8MJe97=rQWP^es)ROH5KNmRO*aJeWsHIrlB*RuNaT# z#BoHf>FU{sNlcRE)N56>U=p2i9Aj%HT7qixWbtI<3F0>ln^t$5>8wv)B&r=YO-luB z)vYlZj8#VVRR$2OsiQjqv#7 zQmbLRHl1FFO1;YI#R-Gq2yYpw4<@&X!<4*;R9$y0QvtXz4w+2H3WaWMZ>m(?>uxZ* z9AZfioW^uEEIK`d&8;5GAmV#J`WR_V+r2Wwi-_@Lf^KExvCXYpo4okaT|#e#qf2_7 zquUurM{~S!q;AU6%jyA^N?6WI6XKgdNIcs~L*?5nh5^S3H4EK`bRH z53no?%W}AV`#RljOYs(~*-E{Sr%DMlH(Ge1N1hdw9Cw{%EC=JY*YCa)CpjA%+kE!% z$K+|M*gxAca4ZYWu*o%paHf5?6X`fxOS_@cpPzjK19nL z;&4i}+{H9?;$+0ecAeh#O$r)lS%PWgECj?wKGkxCqR^<<8dwfoo?f!K-DAG=n2rQV zSIP5)uU$8I{iZ>~j2gs=L0wpxdgk)oami?f)V zmMH)|#dziQ7v72Dlxnra{m(zg)_Iotg}gCv%T?S;ox(5`(NLk3WYQw$dIuo>8J+e5$wjI?CBuPq|W~v0ar5ww$8T4n^ zc2%{wretv)7RykvxaGQm=S3>RyRM@)tZX{7-MhwY`iRq$GX>gYX9-Irslt*i3@qkT zwpw*cu1%b#c>aKc-2)~U4=I-#_@1ZIpa79}txmmCq1S6NUDVZwOy>g*4;yHj>^_a^ z<^g-VSNZ(Ce}bh$5YIuY@iX6gp5b^-t<^$HOFVjfM5WXrO>B-Y`vgyY>g77uR~pNU ziK0BcbjWZ0*7qQ{*t@d9b1&|YX)%tO({5~Yd^Bfz5waLgX*OKa%;46|eTEn3ow#$vkU{-ei4NzQOQ!}9~Wtv0QCjg3wl-%H5zRCNtPEJ-$~ zl&V;Ufa{9N7L`h>%9>@{c!@_=L@LurK$rsX6?v$sjq=kBMxo=DZ1l`jYiwI(5!5@A9KA(MhL8H~Ay_0e4 zg>3>qq*`e*ou`~#_++WA*s^ZLz|<3d|9+u}lrYi>A`R(~1-HneN`y&kDCj>;6Vfzg zF<&V_=lLPFYvQ=3O6zfwa%FFiZoSOj)~?DP?QV@`yM*tpn2m=l#w%t+4=u4+jzjd= zVSKS*I`I|tT|sf{R+M zvbxqJNmQh#NycpKtF=j!RB0m;w3UjDxtR7Tmn~+ar8IwP=Lp)B9WGjcYzABETn^*$ zj8<(EEy`I=hs*~H?p(djY?+c|3+9VC?M7D#8s&18l$6N#6;mZQAocR$m*2zHZI+`k zS}gssOI|d{qcT7K;Uj!6rCHge-Ak1oP;ndFxcUOa;RkH(bSb$Sp``Ivjl*jlPM`QV zCS19(Nu^SvS?}`kyZ6zeG9{;h-L`n)xjTIE!DFJu6fM=6PA*9cjoEU+@mOEChZ5q# zv&(G@QD-D7+68e-MpXQ}rmZu9Vc0mB3e`p> zc}AsNR*{<}iQ@hDw{Nnw-(x(yU^twxwX;o>q^h^=^&+ZOi>ljI1jTeQrQE1fDYs}e zG^+Iqrma)0z)#*grd8{ZhXK0YpwYcecV=*Y`M&B+N24dyW;WNaZu00$AzD(JWd|*d z+3p=OWr1s$j4lIC9$#>{+v1I{T;YwkZqRD&@q?RJc>kl%n9KvN-@d9)awIwvA`0-%zPkQm>?CSq%C2t1rLCC!hR; zOwzVw&Ah-*bBu6FtJ7e%3VC`qB91ebo<}GPqnYYi2+;P!49m1wt~?d7l1U{KOB*cF zYg?xJe@W`5Y2sQoX&MoP9<@fBD2ov}U%+3d-JrcuA@Ony(@+~oHm$VSa;2$>NFJB{AuDBeJR9lxO!CD%fF4)*`saMO?Dh_P{RIbjKkIs4dt9R*j znmqjCf+wdZeEi8{bj?vfu2LJP=owQI3qH8FnRgjth zWa*kpC07YMTia{hATLsd102&~v$v&KNcqwY$yz3ExuW!zLMyOLo7r@Z>zY(cRi?wa z;t}LoO7~*PTACu?J4AU*wN+toIl$c57ltXt5ec|Z)YqEi5Zzk9U{NSED&md^7)4<* zoGevlSWbP|FDN@@7Sj+dH|Y1zRb4!|a*ZrYs5a{gGelv=Y&KofuM63|6)f8#iAJ10 zHJDAO+`j#s>f=YlQ#7Gq9fSGQV=`aj`6=_+6ELEoQV`EUOwuyIRR`V36>|$yKfuAy+FUXq>O18`CB%&Cl2{jTbYb$w>c&IqCv}afq#@z7J54MXE-nU&n-|f@HYy#3Z|5P#e&_I7m*s59`IjeHg@#jgm5@<(9ITS7ZusEZAwej~?~;$*1?Z`{Fj$vUDC3Dtf~7 z;sU!`R>V}>N!aSxOqMyha2tZ|brrh`0l~#r26K-C(2cc%A&z97_7Kd`h{s|Zh zM7s|YWjK-R5b0FfFJVokY)EF1mk38`7Oyu>mME@7WZ&6*p@baCexkaT?FwNWp&2nEnUY`NgdwO5M65YFJXUO$}-5C0I?%QVZ!i z4z6pfKcx+ndN06O`fJ%RmMP#(>goDVQAJh6D>hJ9ktPLu(`q%T*6V!w$zvvi1y!xmm1+Y`$HCBZb!~<#T~sKl z`MSjExxz$B;tylRWfDrZR zO0jdTg5yUQ6ls|UU!L-hfAu>I`yP#Url{6Nr@`r<&uY0?)3G!-Iq&n}{uyUaFL>?c ztNh&8@9@&yE8KnlI*%THLjUrTM1bb#gg^h6zDD=@4iEZMP6sQ(L{k|+kg#PLSc0%E z6UVl&?e+Im1;}%fBvQSEuUSCGMiiuXAH)3+TBfzn>V-Lxqj_7AN}wHy!l)q z)Eoob&=gNEw5jaIQnkv?{sHfO@Iwyv_Q*1eG>=uC?R7gCn$%cHcd*%ODVo$@B#M@* zRBN!2Gk za2sPpJ(}HrjgsB;7 z^Qwg{G{xnM$I`9TR9P|v+%;SV!wJ*zQk4TSg9t;bx|X6)j-zs=%xF5JQm!aBwpo}u z%jJw9^3=^}X`vo~WxERG6k(toD0ZpBV0xlR9+8iQ4ePX;#7RgV3(A(%GZ0^ ze#Yj;F1hrq(UK@OC{=T88`|wM&)>PqYPuxL>kJ=_@dBNl!yZMPQF3%nA1x?Coo~GP zGPBu=$$ZRe9CCRvV{fy@)$7|Fog6cn)_C;gQ{q*dAOH9vH?QupwNd8sVnUGweEjq& zTX)(-ZbU7uDFfwbIm1mI+}ywpER0aYjP-S-XxiF+q%?p+xo1=W2_V$6^`hkKzPb=} zt-#zm(sc#?QZ&s_B|xSAEXUST?jF{7|It$YuAUc)$@2nVJv%9_5AHo?8TrZtW8}H& ztP0msboY(x*OZ}U6@`ifvJ4Z~wG_!Fo1$8KhGYDc@p47D@M*af^|PWL%BK7&=#*=$ zI1aT^1u=9Oz1`Y7i^-J1=>>>aT`Wgxbapq<001BWNklA{Vgy8mj06a_m27D_Z~5y z`8al2)%C;==xlE@3`5R>a~xX&YR%NyB~dmj#Cd{8fTzaDe)l+Gb}LHrM5y3kM| zt>j_Wx}EB|jXYzstuqhT0@1p2D9H3oMQ4#YVpLKxxkRaWB#k^|9vZ5PkWQ}NZm{r{ zlq#m;8EVxklj&4_ieMJ$#sslz)*82%SoprD+B&%=!4gTd!gd<00#DJ>!X$3(Y%v{< zDA_ha5Gow^Q`J&Rog?_BT2iIw#g}eiN-wF%ku+OVhRPDIav*^$V7o#hSDZrZNsEzF za>Qb_QhmNKSF)=Q4-a_r?Ylg9aKXk#PdQ(O-V}mI+APT;{r-Y#xlE;8<>|?sqo*@g zengngdHKaVZ0|NXJDsz&vB}}J9`C>ZIit}O!%Fa@IYI1EtJ%bP$kBsK0?+06Xo+D~ zIJn;7`MWPLnT+`2gHPxmKPIeBRWt|l9KT2~Y>j%Wj&9~OIwgwKUDwtmT}QI8c*~gi zXv}7#Ng?iCPeYH^21>EbOLN((80>Z|E+;;@X0APV!XRcAg_dI*GoHJ%&x5BPv!za6 z*c{IjGF_ZZ3t}y&oETV+g}+*;=PuocX!=5ywVDmujSl_GzLL*Ro}RG3wXagRlnv2k z6gQ8?%9~?Ya!n<&Nyzcj6H0Db;TNfFf&&cmr+Q|tHbS8r%9n6*a*FZxpL+fs@y8u~ z@l-{v)Hx+h3XLdgpjePgCAPM9sMc%B0h=T_XQvnRHrgB6`>qZP*|1CE{?)9$sD1TAc% z;E9q|Axf9rxN(DE<*``I6@aW%nw&g2QxB->y111Ce&)45$Cd6~W&J9ZYUFyxWH?rJ z)h^pgC)aJ^^^Iph&>)B++)fGVI$Fu#+SOP2_y4{BhClmf{w=OvyNgq5F`dmh9cLtx zEp$sMbeT}CMXc(3o)l^tC&&!KJSFl1mC5`hXSxbi<{XLr%MZ{pW8G>d!traQ0uJ=m?s!OK^zLorM1Dw zi-gGy6hC9mh9QqWJ7?u(G^=6&(a4iT5j*9wqaM;q+%HDKcs|D!^lDg2vaQq_?Cfr; zDV4xq@X<$~D!_Qg99}MUZ zE_v&X*O>O7^4I?Bzs75?ze(u({G)$pvAus2tEKTf@BTv`Uw+Q`Ob8$$MWlX8s!zyb zgED1q@4wFT`>*r*bKk&BY(Dwq6Tb7{k5o^8aPU0WcK3PfXa5X^l!v?^%u@c&@BB@^ zxcnGTB;3Ftq%7_gBQmq+%qMZb8@9GQDowluI>6^9gwhj~_gimPGkG6^LQ&X_SR7vJ_MLs9Kxl zY`6pkp)!k&Z5W{7YufBPUQn}#a!>9b*FTO&hX0TlPeC?apv43=e z=Px*Zct)pTDm7B-^KbmdZ}30-kN*>w1E2r$ul;rY+yDH3<-L1<#JAu5dpsH4XL7kB z({<`K8#}D<-~9*w8@I3A;q=KVfBnDsulViX`E9}|Q0>+)|MD;MD}Vb}Xjwl0$H6V$ z`r6O33YYxf-~L;Cx%?EpS}45WaHgE8K#X z=BiZ`JRru;Mx~Ay$BN7flRz4EwE=~IQrvPEjxQfPRITPJifOktIJ{EhTfcBuIb$nznO0i+70R_bo7-Iuu5@_i zwL`+E7QI@T#}Dsw=g#wd``f>ZW7#-P%HRGwe}_h+!GH80|A&0#g>Uf5{r9+c@&T)G z3Vw}ld6!%Jw^c^?@BhZ%;8%bBA1jb60U-j7OcYHgbINV_^5Fw|2fO^rxBn(*;XN=i zjBITU6Cx6T(plOj=4u;z%z!B*LzUU4zp68*`T-Hjba7h_d& zrPUVTr<8BVP@m4Etbo z>h3#IS8P+GUMVX|QC>2IB33a0DwRf^D_3_^R+xwtT7ZS2v$MUcF5vUezMx#Lu?iP> zamvG^Bcdqh>cNh(V5ddFWIDjDYs~x+=NEmtojRsgWcm4{Uc9*@aYrK5xZQgqB=Xvwxx7q6KG8_$+U+{1K zjsFG5c6j5>ukz^eBPC=>DUbopPOU`yN|)bz@c%F^j#cDp&+KF3+LkuY6ho=lw+k?Z zik%h=y?})`S2~5zw1TC?Oj<9k$GJ4!R5H9<5lzBctE;Z9c#3MduG~Xnm!!(sKSINmmMy*<5YkQxw;TgSNl~-ST38Pzc-jSUmle>b@ zWp2z;y0fLyN3GUSUVpQytAPdSVYarn)nJ5d0x>F_JUvyQ;_%vm>IimschpV4_124g z`2Obo{Tv+QtoZ?{a?7I`M^C1TMNETOF{RQfnz=!xR8zJy z89$E&u$FD~+)&Qn<#+8;Ho)v~)r^_ryssQ%3UC7{0~BW=Q97KYLd zgvPFxOY9$BSIp|&mktQx6jO*AQRk!%$;659;qpde8xrM7bY^K!-v8j7ya@Qln_p2{ zzwAQgE)`}6=yrRmHp!GxySa(Gv(J0)e#-S5hs=W|Z+`W*I&&cNV0_{8wYOg7;9$g$ ze(;#dJW&=e(YB*3q-?v4FHRMAkOTppUYUh&tNQs%|HfDG{TZX-oJOmnM4i3eL*`?j zI24Aj#yNAo^XU<*ddk~BcZZ$Crn;NaAJ6fo3E#i>2VDJwedWD78$9G;|6^w91sFNL z8}j%6@Jn9#*Eb1Q5sR@;_mzF5{XVhY<6rqtZql+eqCzJa23S=`xr3f107bM2@LCfu z>+~x;y`%^^3qS^AUENZQX`ZjG-lF8m{6wQ!1A8sph^5>xoHf`JcES*uUQ8#2qML(2 zhIq^9q1f0Iv8mR>aVsoC8H9BduVLv0o1GR5KY7-!>T0a*i!U^;UfahkSJuM>LR#g@ zz!1`KU1e#K_D}3jx}$M;?Fz%eP}!MebBM!5z=wGB#G58tesDQrF`MJH>&jMr*`KH# z+vt|rzOu&$-~WV8yQ2t=T3jPfWPV^hsUr4qu{7C^r9_tNFW%(-gU6JdocSW4KOFG& zpLv1lY|5ZNR)deHXUFVqUt={Nuy@ep;n9~|IXt9(*yP~uJ|7=FvjEHCOC7 z6?OfU){tNO=x?#MW;}~tW8GP&YcCvu?<+mOzHQT#0a+yuP4|n ze{jKgxKa;8FS`t4^ny~$#;IG1DXg`tO6FY%P|}5FbyWS7PDkWqiLiPlA=6SK z>t9I!&%TOh5nHU20;#UyM(cE(7BRMrpNYCCiBniX(NAQ@=;AO+QTaD6DA{GQc%?Ru z93UaKJWJP<3Mu1gV%=B7U6!dKoc6{hj#F0MnCKYEGpo8;vj3Q=l++PKp&IlN_O;h) zVupUSu7tU!TAgJS5X1>?l2fZ%q!h}%v$do1%2y8XS2JwQR$YR4++;XZ+L=nNOdMrQ zr!%g0yBL2aP;+!v!Ghz{b5$B%fAwV^Jv^r`bNFX74z6y{?~jz6Ds|bI`276ARhFxi2S0q5 zSF{Rm)t`r%xO`DGb*2oT8q=o%k&_d;IjI#uNhDR#h)re5lB^`+mL?+G$WvmIrx)l~ zOl9c&mo`AL7GCl-aja_aR#4_^uixQv^w06e{#rtonSB|X%QXf3)O3+BcX3QghGSIF za_J^=)x*o;3t%kLM3n)t?A5C^h4!Tki?6}5JPvodOvZg>(Mz*jjho4^mjHKhLrJhV zt5umR;``tKuE^1nk|Oott7mLS*?*TVD z-L*L<3kcCwns=0eqon#^`A#!*naFHIq~p3RN~uG!$kfBjpT)IVfTbDK%T)|F=EKQ| z@otJ{|BK77tJ*I=S3GkVn>kcdhikjrRGb=-5wGX`WU@-e>a;aiFHsmJ365#9bFi~V z8u&HU4#{;jZ!VD~Xh&2o5rI~|PsuRX`v36-Tip$|w|ac?;R#7<%1J;ZPEMs(;)R#4 zGMHR4oF|lO26}9Aczv6_LviaEJihmI?Mk&!7rIykG%7W&-MGo`|Ni^Ri{0tgmCijI zuM{v{7M}9U31~5!70Q)5quGk5M|~W-qNZX+1K-`f!sW#!gUdNze0IXkTUU7PXYTOp zUrzYapJ4Clq*9DcUAchMLd}|E%Sk4YLoG9@xDIv8R_0Eb{|l0IO@|jycO825nu=(@ z$S8H1ync0$-_PD(505)G-Z5b!Nf^NY+&&>mu*w5#>@<4YG=Jc(qtiZ#0y}4H-0*!BUZb z%O&M&6opbsfy@h(s;<&S%)-SK0!RTp#LI>{jYHh30&*(Vy0R;ks=^6Gto#+;V#sJZ zArRLS-E~n$E>i>o3esa?1#TVbE*XgqIPq}t|j|X2qQKx_jE&7!= zp2IX>;J1GLJA8TXMDYU8ziN$wLdpsH`kZmXvp{6E)<;q2Okl|Ya;WCMpB}nN2$VWYY(At0+q6k+iGz9WTvh}6UmYpnr)N6`pbWo zYFV_1hDx7?>GI~+p5y89nVKfb5|hbt!o_e!ckIyIbJn7W8u(lhaL8yRzNu3o`T9%kjS6F%lU5;as50d^>)FP?jjZT|p ztEGHv%3WLNWTZ@I>uKMOy%KMI^BQ|sHkHHFa#FSq8dRGu<%+8mwexYG{`i8ger2CG zUpgR8W+X*~VR}6O!WO^yOK)=Z)h)*Uh|zSc(z2*ria2pBws*D_3ithxufB1I@#KP! z@Yqt-v9T$s?2j3kMowvYSDAGyz&_txt@~A%g7iv0*)&S)!vCxuU>_T9_7Tdl$V_*?cG=6yIf8qUVrlzzxj{eCrek)1g5egMnu?< zhkxV7t}-q}@tnKQ9q_{4tGKSAP687{=;dI*!Qnn>ADWF4wMv7JK6uFG=^20VFTBF< z{*#Y5AI_Lv6pW6>Z0wcM%yfNhipZfdrmgJYC@o**2LZt8dQ3t^wun2~`v1gKDROcy z2%dEtryFb2WvXSAaG6;%`lIzhjQbltZr|dcy|-kNh)vs3<96~pX_2buJ{+&uDC=ry z!*B}KQ3)`YY;|&Sf$NAZn=K%>}^^yz?^bAi(0}Y{?{ znzf`|ZL0x?(R)67hg-zy94{F0(o1(4jMpPlo1Ka}z3bki&l&Z7H9|J&XOtQy_5Ndi z?yc9T*+=}|Z+@t>adGMf-byWq7$l^-5V!AmJf>1{xq5Ar>2gUpUMO%RH(x2&IX*r^ z%gVg`@)dS=U0!*d3zaGjob(K0xvN z8PEKE+S&=U{u8B96zju-6o(*2Q8{i!sPJ^0Gs!%@ef%yxGHz%gnWuAUS3>WwzD(Ye}PFTQx4c(vrU*Pd4qHaZu4h|gYbCM58r zm{?3E74G|=u)R^^Kl@LAj`!X_<)a@xA`;5CQeika=U}(RR=YwhXXfb9HJQ$E&4}Hd9fDQBAO7>7P;*zzXJd@ldTLThPC9ezuwAc_cm~spl`@UW z0w!^~Hh4bs^s5t6oV6Kdz3M81uL%`xJq09ABHfacNKAG9PN`y3zgEV-Kc+^Ykb&2% z;$H1yj#g~>2EkdxRJ;{g!jA7Tu5Dt~bQaSUg{1o+B?uQ-!p>GIG%6JagP|J6)kWRQ zHO$Pw(rsm|5hYfLAj@=#g=Q==y1g!|Qmp5nw4VgCsnbEFo`{>L+NpDJeIL&Y)fs^j1?MLx5c_C)z+$`<6S-P2 z`3PC4$zY^r<<*o=+hKRN$8xb^W3$0%5HK1n)I!LSC(D(O=Vk2g9B}j620J@D{NUY> zxP51rddpKJPqW^^Db+c7GUX>9eU4>Sx%b6WCc})ug&go0tL2gQ=ic#S;!c9zAFVCf z2d!t``hRgb4fT>fyU^COZSg0;u3q`G@2y|OpZwe(|3vZZT%Q~k7Rg6v*ipgi+9u_@ zZ7lbvMp6TB9;!LTTlbet$`$s2c15Fb9A2!IdARuhNqg@Y&GY-d@AZ3rPw#!6>3w&$ z@80fJ-X6&liwY%M&7?$2GGbVU5j%*}5IaD;K%75}AV?tCj$5Kwk!4!dv@FS@$U7d% zE4z2wcV~9WPM@du-k;#}dFEJT2{DiX1_yH6%>2stQ{L~_yF+8t({->EoT35};>w`i z!{>3~a5;6VCw>MIdbE2ZhP?qUt6g_CV%G8a{kr@yEe?(kcNA`Ex0u>N$+eWCP~I3a zYM-2*SM6kMK8(4xl(^OG^ojaC^twZxOiBCKJ^cv?@w(X+?|(_LY+^#3iwCg@{Ml|& zC^WPnTU?ImPfezWqA!R>5?Yyy#9RDwPD_vv?>tZ^QAf@+!%nT5SCgZVN2I`%vtA0m z*WS3ui!V;msMguvN|Ts~k<8{fImjY!tP7W>$tIf|9OlWSiafZtq1t+J5giY6SX=`f zsR}L8&o72gwfdG*SJ0{4`?MdheBVX?{tx3%eOkWn_k8d7kBzkT^$gy2i*(3GWG$c_ z2B*s)xq0f<4j!9@PgdI0Dkb{9IM|1{TRn~}1`U~x8K%|)vK%sOqwl(y+O?+cX@mpd zb9;3=DpV3NsyM7Rx~-Pp6ror`2X~!Tm3FO&Da$;ETSd1zL6ljK#ZdTWd}ftI!eo1W z4|94Vc&k!vCC$)13i8F~tO+}zq#VpzM=RK!`S(!y%7KT=hd%OW<_4Yb_#mUUhg-K@) zsFa!tdiMFpl#**#uMm#-$>(!=ZYQRu@%!A0Q6E{H)XW}%6)WB90B^oV*=EB%7sMu$ zPQ8kw|L8*h|NF2oZ1u72S14HRc$Na#J%$#?A1{OCKdo|)p~uNmu+2;E5qAbQYKEPB zrN-r6mlK;Cm!-$hVb_bK6Ipq8m@@j2-APY(2Og(Ow#C}hi*GR!4q_2+U~fQTYF??K za%|{ixz|B?yV`#S{Z(@7jLft<2_!R%%Q7}S%dZK|4g%J$@?CbpJd`Ll6 z%QT4zWqmTC>tjRka>nP) z*!v;^)|PL2GQzM{V*Vl%001BWNkl0Kwp;;c45ZJ7cO?CPM4s6ELxQF zQ-p~N%M*G>=5q!8OL|yobVqpoVP@wiaJb~oEaLW9$By7)js2Ztwk1qq?+Ax4z~aiX z+PlDYI-BldTD!{UDP(#i4+cDam}2MortS(vVJu4!LDC-|WT+K}+`GNY`qM+6Z|5mx z>f}>R8s#CiVHKBGM}3SMT|MJPW7ji>w5`MOZ2sfIPWJV^;i;|L&{kJZ_tAJ#Xq-Y7 z{B1k_j_pq!2ICJ|8Osmd(iT>Mi8Ewl&>oHv3&!_uHK~~#ZXXOAg#C7ocX|v12|}{2 z?G0!JysX*a!0V&h?kY?}v;l&Sm6}XOzEZ;UWTdOMuyOA%qg|=9eU^?={#d_Dhg?}iT0UDAkzDG>CtxU`^^r6`G?Z=PT^JTw|LCMVte#7};LK*UP3Q^jFAXjHP) zOJy?0Y5LtViAf(rv&q70h{-9@`MG%dV4Ym9K&{oK(GY>ExL;jl(O-nW>D1 zR+VhEtRp&B*&z(|-_uVRFN>eW*z)Qv_ow) z;AXVT%|(N9&w|S|sR%AN64OFfdUpXx7i$%f24HuLZQWu(m209>Z>#mxY24FVO=c(3 z1&Gf=+(0fpPR4VM@%J_0)ZwO^!IiVKV^56%sKg4vUqE_yUg~?$OLA$(-cX@X%>lun#;`%VSikShi&Y zD5P?ksJX)96|B)Ra5dUg2H;J&HPJ-60dX|RbL~_gzxmzQ;mG*Gg^rxTZC#6tFVIx1 zimbW~9i{g5!VlGGY1O~0J*w-UlS*3!1AkVf;4-o1P5QAO_Rmf*`86vui$xB*CgnRd zTvzAt>=Y=p>U!3T@l(F8pkx{}@@lUyH9I=&F&wV(O)wm)R-q$r$ePgJYwA9>d4sx+ zZpvC=s0(TB0J>t$Q)Tc-$HRMjNn9Qm`f?P0jjUm%|CDOfuI!p|kLz@~HGv~I;iFy4 z>f}uZF*_*1p;b3%HL^Ti-=JO|aC}(8;j}Qj zI8EyL3DMY$7KOb|PhVTLazU%rgvUWSS3!idVm@uQ3JN`Rxt%&TP9G-`zof-(+WShOL6nD1$VzIP1R4U_V)i_hWVn_CT#)Pl@Lr zKlvlQ>7~{aX`6gyxol?~H>1GUo)9}~svMCP#%{H1fhIg%x!VTq5xGnbCl)&Ot~z}t zV$0$$di?hy4)Fc}K+d@rSXzCxvm zIqImDc68b z*^2w5NY-lNyAah2txw?SdlD_arvm&lK294x$>dQUFWB7Uqz{o32*FctDP#1#HqU9* z-`6N~)uXR(6gh_If3IHX4ON69%cFwFML3#Z@}S7xL5}>j8K!I@A`4*-KRi^%K&#hL z;<_;!i$yZo;#e%x@9PbyI6K)V2+ptH)oEzI+fXW7y;8#KwCihr*dLonq{tQgjOBF9 zEwa6Aw#;Z$!>SlKH4_;6i>9#d`W+Q(27@7L^^&6ALm@AXQWak~e7XlWn3|d;9FF0% zj{^;?wi>D9V@f&kzPl)w+mtIQeD1K0ne*8SZm%4QJ+9n1PxA1Dd|E8uO=a4eBP*V0 zKzTY&ar&C$jn=B<85uVA4>EK;UKNDO%36TV-9{Zx*a1z0%Dv~zI&7pTLWDwAEyj$G zCp`a2AL9X!RMNG_1!7hk6|<(p93k0Tf>t~M`xx&c_Hd(z8FIp5nf$XNQ?E{*P8NQ! z-w?o~z$6W!kynb8S{|li=V_!Z1Z^&=)iRY_Nuf_}zeknPTCEF*XefZK7KUw1EFUUg z**<-Qdgc~GMOT|LXoqV&uWH1B;+9+4l*+xV{RsZ+ifs8DY-%+{RU*Rb$nDH6!7!u zAG)ePpj@t|HGpW~Bs@WG)&30M! zdWbn}%nwcC76+~dv`$*I(@mgmKGEq z{pkLtvg#(M6HLz~ID2M+RBNiJMYe159U3F9&A2!k3<%#?P^vk`_g~Z>{1|=rAo%`jeRMhkHfS7FIX7~u zK*QD>D?wa+@C=45jOgd4G>$l4&*3U}n67m> z==2%n%gjZiG)FC3eh;nn6Ly|w@e2FL%9!sr9FKbi`t0-iwNMwVT*w!oP$|>u4fR0~ z_>_o4gyiNAg((YsOIZ5-md+Ad-QiesD5_)ArZrt+_6$~g53gf5J_5A8kdxZ$pjDT( zZG^_4tdTHscShZ^*f25d9Xzg}f|Z^>+o6yqq*lP_4y}F=R%F?%}2LI3e&^>w&hwJo+`0g)Q#<@m@ z3s0es*C7?uxONzPEUT9D)0ETQBwuM@o_Fc%-WGFXOtiE%Fiz_ZRWr$;xNqVri02>D zb`#r7n11FthxH6D=ZNY@HOj{&mEJ`sW7?zll|niugAThLUEo;VcD*r%il()XSp^nT zlieggLE+I(&-li(7}Ps`y2Eium)kn70Ynrk6GYh#I)`4(F)~9D-z|9#++GL4m_xPk zgTZ)p%24pHA=bCIiB9^6%{b@`sw^y?V{Yauo`8o?VyM-BJTBeBF>bqGUtdQjCrS;K z$T(SST)uLN$(b1qfbe^QoE&8pZ}P(Rv()NY1X)|JHFWIj_eF6!1IpI7*}aO7O+=%3 z+%B$MU1MS*#)FUUGdq2j>o;%mWPOvw>l3(RGKM|1M*lhIzA>~=uL?5Wru%&32Y#bL zuiR%MKOkba)017gZqnqwF>rN9^o+5cYop)Bzu+E+WOfZICvD^x#fmM`IIA(v0ub4K zx!l8;578D)|9YBs83wy$$ky4>X$-UjF)R+eu~W<5u%p}rWfct3u0_`VG9;4Cp)Wp1TM%-he3vUd=(UJW1#t&u zs1jl8X^IJtM+w-;!Z9|Ng>JvC(JS$I2&=VEVm{8yq7{#4h4!F8y82WhPpfCv7>wri z?mOJi;_`ab>z65IxpeV7!LXCV{S6w8AWLUwxc_j6*Is{YZ@|y;$|A?ddEWibZLO*&mzTJE=eD-3s$cl-6mB%O`g~jf7~dQ8$UY+w zbB{;0qaVEZ@@JdLHj{1#4eJP3M6%R$CZxKiQ;7rB$HU=l1S{2hOy|9--+o!Ln_04f5Q7#3k!h zQARF*%*E=E_)CBNuk!LsaVqT@zWuEPAEmeO z;ot}6z2CjQe}3cl{guI}Z^u_J;Wm9*3-n~VH~8-2Sm7Ct9wgg+Jo5n>od%iv16s8f zjdF*ZUtY!Hmi?fQR;kC{dxyB{Jx0Sej+p?q%W)NfZf_?EPlxq*lreNT;8FjWw7TQL z73#d+-hMtFM!8(N`xhNyI+q`lP1IF1&|1K-Th&IM6Jd_%6D{Kbm%Kq_wj;wgISOQm zWp}tVPg$WK!vR)**h(m3$Lq7{AVa)q!lSK~+cexA{8kG$uFryXKrA*%Cf%S=IbmUD z4NK39%`(txyxwYKGpq!{BWmLM>G=uzW++!PsygoWsvMqto6#VM)4oVJ4J1)=tt%{?jk|4?O?03tgt{P8tr2lDgEjW9pk7XBWB>)n*u^`z<2#9y;kdUSE%n zIie)Hd`V}qqp^Apmz&ga7t3J8+Gl6*#2qR#?KS)K>IS}msro-LhYp4vEu7npK3>_| zJ8Z~?Rt_kETU8_wS}pnJcu%3$GV7RLCJ&#eg=K&yO68%2fKMXgf(p-&w?bR84$SdQ zoR@23)G*c5JH%XE3*K^i4Yha)u|V3#)JaZ<3?c{>1Ho}R&*nx|EnKGXZA(pdH})u= zr0KWnR5BT!-oLLY8#1b$44q-nv=Vkld3gICwRW0t+^cBWOtMa`Ugp`OyBbw1nYcgn zna}AscV_+qH*UPZwHN0(dv1=0_qR0w`RvLHGt<*J0|vkOtG~%-{^F;}A00^f#r)KD zjh&4;;yie?fg@<1_W$PT`EJo8KxX?Y`ZWIZx&OUepwk>sDhivwgQYbd8xQRA)XVFC zM0aGNm>;sfpQcqQ;R-l$%?9u-`5D<=6mxC5wH~ExhkC0{bk@h(%}ET;@Klm+CA-xk zw^OFwZ4wtbcc-g<0FihJOG(;aA(9BTR=P29Flmq%7PWvGqW_cO&v1y{>D0lIcqmP^ z^N**TVyTx}Ld+*3HS3>>R|Kdbzel`bd`zV;?gS7=sZjFHxz!{Zl18Wb05FQLLuKFF)_u$ z)EaY>vm}qQ6mku&ziF&3&iuKBCWn}A*!`?>L@A7m0 z^oPxB;F@w^nf8(nj@a%rIjMBX$^t3brF~SVW*O2x>t*H>lQ<{5Y7aN;c7h=Xkx4hj zd>5NZJ@+s z7H;{y9vuM5mdxu6VIA6Z<0Y?dr_+PebZPMr@Hr?Y%lLf}YR#Sw9k#a)DCKJ^$aL5Y z4t5{WXk=)0s_gF_6810S^@Wsr<*>TRq*8c2F(xNwG!``yo5W%Bs?EIDukzlv-%) zz;xfkti?~I*@l3rIRWEo-GBUHIV}pMg>*WHctRe1LW_qfDp3dJ#Qi)Mc}< zFgv4hZldv*7F|L;$BQUQM60T3Rdb6@iRI!d5*>$T5Xv@iFh=|ur@@z+d#L8fk=_8( zQAie)2u3wG@F#xqv$urOT`p7+MwZL!C6mf%Z!QZSQQ7tw=moIa2GmLowPuTTOP;7R zYZuwu+18&XC-*bKe4jYe%iG&+sj;Ubwl#^JT-xotCS zJbrpt)i0^zJV9@W!@~+UZ@!Mh=D_U;^7#I9C74Z2E>Mr=@GW|=c!#|AM-NFQi{$ei zyu&^#F^A5HWQHT>;*YMKB|(70Oo2hjtt=gtcU!(s+BF)UYX8QdfLf|c?)EPpSHLXyv*f^MJ7CUKKuIX#DgIo zJ$l1rx;HKAAUl5J%)aiUVIV{@8J#S;W0 z4n>v8WXmdw6$vM952$p??DV#oUtZRIcCK3Iq*USjnKimClSa+L(~VtP_n%?+n9R@3 zYk`?7-WE%RN}Mv4G?7S<<%M%&;n%d-k+q!LI!UMf4y$J_@cOHt zV*XQvF z8YYv(>S)sq*v76Nao1FBbPX$Ai@~(Z%Fj$K67aal$=O>N@!Q{C=jz-N$ISxS+9B;+ z9b3ze8FcZJXD?ye1`Lc5wRV@(PK)AjK*ipn*s3e;cGl&^H!=y@gG@Lac%n`f#dKRW z%P%l?>s3TD{et%FI{ws5n-1+b$_D`}rSzo8# z?wq1s#;aX1@9KVEia6!WSjNC=b6jf(c28~+eJhA?k=cyWqX zmS?dDgW$AqG)~pvvac&u+jKikW@1t0_w*%isNbj7Y>+SY`S;0v{E~0fk}klb?4v}~ zhea&k14&Mo&8CUZAH?qVkji9vzPUlEQs*R_Q+2lBcqGqRo>qZE=$22|!?GJ_O9H5& zK2GsrNa3eWKXdF67^j|$=hEhB;iqDlkJZsaKo9uh*zH~N#j?tbMQM8O+_G|ij*gT1 z+L@e8=+K~;s}gWIx$^pJ`dazD-~BfP0$~yXx3)5SM=3Ie7QJB>cW|0kRlIw7lG&`< zvGmh4iCMg)5A#?|ajROn_h_9fYghQ;AN~TtP?&bN&-T_9J3Ct>Pcq!UyFoJb$0{fP zNB{62v3h1j1Ets8=Xv{1l0Y!QkG*=6POZxC{pvqsV3cSN1~mFZ=0jebuesEYJsR&s zB;;T3rK%z3WO&vBT%hr?o_H*m6>tnu2S?bOPBI!Qb=hDaAZ;g`Xa zXG`@gbl5k(+$|kMFRzpV1gx@e|6bSEJ~JSEk@rYFiaWLKJUEjgc>rOV`;GvFP(8sf;j#%N(B^ zYthqf))f~Q^!T`NZjCFK&at>S%hvV-R+rBa^aivLtVtGeu|iBbl0t{KzVS9&JJ0Dg zo4BnO%)SM4VDjlpXNdYvD`FXZh&)WTorZ;SvC9789^p?c6X@IU4J_PF9Z`=PG^hIv z>?5wlCo%sMhe?BOo6Tf}fBw!xo}OfBRodM6#HV=jY#)y=M6KDu?ekKuHWh~_@jH?N zK1Sz^vwg<71J*HO$7)Bx z`uB|M22nc6zp0;IkK+==?bmPjGyA ztQ$UA^~zIwX5}3IfS;q|V|4*DGI2XR#04_#apExTO28iWrD(EgV1f=olv*Jf{t2EM{U-mB2 z<_R}ZuzE6F5~}DpH^?~65gbd~WItd|PbO}8eL-zq%}KN~Amz zbm&wYmyp3st3$2X@4k0ipI%Asx_9?34UJfDaCUWdY$_QHRM{%D9GAmnDi&cf8ewsE zMroES^NR$$9-_ez^>R~15#mHHl}Z{!AtdhW*RRv;)X3+vggh~h5BE4aIM8}R011<` zvn(#pbK~+gOruY=*`YKr`J4a!e~m2?=25;)?9wGRD<#%G`NP~!HhBB}hrIRZDFH`_ z(7?mqcAiMZfxlv>bT?11WWiY+VmA6*U7bf@V56~S{Im`j8!V)r=(hTN^z4w|y0gt+ z_-kKgVL7H?&1X;UF%xVsG(vp&=YEFcz2}&g96ooI{-8q4c*w}Gl9)ZugU63?YJQPr zEM6Uscle5kHP9Yk3O||6G&L$_IF6gKnQBZG?WcUo5iYsSBJDRmj*2nHt)IyIWUeFa zs$D-?5CmKPVP*Q=~7EYhtvb#Ab_wxr|9ZWqlS z6xOip54&;5u_&i0<~<8ru&$0DSPX>5Ksey>3;Q|7I2eMq6w zAQ*CM+}fL;`V_rZiFfaOfYm+2=6;5q#~<<9t5>;o>+h)7|MC4hJidEd?b7aGg7x>` z*P_unZ1GEK0GcbE?N1?7(bIy@rc;ugs&vvDS5DUPGF9Y8EFaS z`_RJhKm5i&9ogJ&Jx5lTmPwuLD>FEk%VTr6^(@-kJtUdTuzPUG#^$CbYADR9TEXM< z>PS+wX617*8vp-BEV}mKE-eR%dg;b+xh$(Z?dquK(?6Y#;Y&$ zzx|Vc%-7y}pI`cgFY@oc`YnudfeAMxl+`=H7xc4vm?9&T6pvSd)&Jxl|9$oj%lza2 zbS!fsSGAL zw-6+Iw8Q$-gK_I710B<*vMxcpi@HbLTQbsROtr!1axxL{v9LHpUKk3#AdfdT6mZpS z^|WgkoQ6lKjrqh9yhq zvUix(A66-!SE9yIHqXRVRM*>)NC;2B%So=mqxWy~g`awn&F2rf```|KYlmX5#7B4D z<7YqfX}N$xsgb!kzl+VUo_DM+%0!{tzxo+lvg zAFEz`!KKTL+a>ZVhgY?18(Ukn8cn*+xT9WxOJ^4uS**N#{UUaYm3*;CB;>2xOUv+IhY|pit{_@m!E*yTh3oldZ=# zmcvU_s>j@WTII=hidSylq}3{D?%!ZE&`c)Z}RP2VT^$FYc#w9{o{;~AM; zUbE$dS95rM_Yzd*oUJ z&Y!pAw>$Xeqa1$v9OeoHd`{}kA?0#|^XJdgAKBU7d&b1XB>8rqd_E&uX$qM%i*t*3 zodypde8>mu+g!hRnJe=jFdf(>of+bfNZoDn=-B|L)CE-ox5HpD;iq|+;EkI#Hji5* zGdPP3&GKBc!ioodaONl!<*1E)(}!kykgW#KwI&{*4Xs+bIXK1)7* zGA2znsw&f#b17f0YRIHOrDVT65s#~aNTSZ92JpLF1e`89)rR`o6TuLEhf_O&s~66* zG&_UWd#YvbGBy2E$A{eVm7&yhLI zk(gS+YISm)N-}q57Q4SiBy7VKb@RsSKg;zCFY*t6<^LvM>`=(H$z|%gE68Wl3RONz zcL>dSxqfk;Z@j(5!O5|_9^O?|&hy;^QiTdzJI4eAA=UerD;1t@ zZ7A;c;j0TiE!`Kj?A$euw|zZ#l7=Ltc8p!JT^szxpRFT-^+x{pl`u z9}eks?Hrs`NvCQ!1*cQ3=*CXkKY5G=8RK(06dGX)`>)^CpSQlsP3zbX_;E`prVyD} zN-mKxwuzbJa2)M8rlJvj=!~Zye0}ujqk9A+A>xTiDk3@RcSxQjwFq>2JhZw^cDJ5U zFEL%Ky0MM=6)pw;SXD<}a+UatqI&8lsnKN!$+Uq-oNc04>erj#!bi9}ggm{;<3 zC=?>#_bUNgr03#qv-U0QB=`7W=MI_UEb;j{#hM=NwQ%}9T)((N*zacVc@l}dU0I5g zEj77&`!SbqoaLyt!P4vtTt0t6>w`+W#n#<*-u|O+@#@X%^hYl4+<&NFulNfi(SVMn z!y!K*Tal>=FWKWEzyJ1Q7N#eN#q4z3CWBE|XX)|S1nWD;3@i?!5~=HV>o`_IGZP6P zzw_Jg@wa~N0&ep=6e?X7B382HK2vi}+>QpDyCF8VTin~~^X0!7Arf-){s(pb)z`aR zcwr5TEkw6c;Ba%BsYH}YsisGf#WIeqU7VRA7LO1P1gMmXlqzMd{w0#PT&ZgpC+=<; zG6`f;*1{rekrvi#v+~jv8QeLQ{JL{^g84H)`uSTgfAUlK0zSo#j!YAW3KLyS%}wcF z;`ew};uI2B5aWM9*a4|@TEPvnH;|`bb#Y!43}jMC#kxx+E7<}!Ubw`Kmu|4Qw8FVd z7xfEzdjA34Mw!X52d~{qIF`WW^%DyENEHuxda$EU%i7fhyBj%8@~G6CO10S9IN|ce z3&azWTin+ORe4PckwoI?F0L%_@SWS3Ee9`LJI{ak_kYZfec?@h{!3rxv!DF}*I!=d zTW@`+N?GwS%7@UmW)ea5CS1BW!}+y2_I8gsvoMX%?W5XiapA%R>a`M)SX5h8@z$AE zH^pj=U@$laN>&~dcRy!-(ZbcU7QT7c!N2~aHfNVz+-KTn%$!$yT?gRvIVk5x%e%0 zOvyx6G@DWo%b0jv3&=3ZWM*ng)xuBKpK+8cP?x0h|Lo^~_Exo0rdrIhxAlz4sVQ8p zah!Uy*2FRzD5y|C3i4}}N|8`3j9YG)QzeQ7JULC1>3EcxnMs{F%dluBF`;t-8AwR< zNyzVI`SL|3XJnFhmPkCVDP*S0i#HM@nn+;tIr;kSKf$zjs1(Y~%`J2J+zk$n_f)8H z<>Dm`TwH&4NTuA-`S|_&Pubbauz2Mh=dP|XmxwbTjWM%yiBh@DAOHSaEUhgP3fb6v z_LRGKzs2w2!p?UTw45n{Z>bYr)AIXOvTI{o@; zmwbaTz`{C57r69yS#n7jFUQfNna_~>BtbRQ03LD7g?K|WOY8lR5VD$=T@gsUuqe1 z{8o@Dko+9#jfNUZWn3kbR8xWH)-f=0*ry>I&Ab3RO@cu`on{^LuYBn*-I|`8#A447M7V18kdm6cVZ6HzW+I8Ucmp;RgHi+|%k z=gg(cTsXH%qnzjZ^&6bIa7n|XY=bsVZ%{F7a^nbwrav;YZAl*;akTZEckX;P!NZ8JxJEB_e&}@sqL`*bI z-Q!D5b>+f2?Re&=XLa~C8jZck<4AeiI7Y@8X>zC(eKMYx2UTce@^?w`H{o;g=~rIV z#gqBNH?Q4txNUS=4Mex<3k7(-y~9wlgdKL~m)3L+Ero~RW8xE2H0mv-g9?CfZefl} zF;6HMLdw6I#I%iR2&h8vr9hqCQEjIr@jITvzi_IICa4IofzfgMzvE&jvp zZ{l09YbsfBzlqZ&K#CY%*GRJor{~Y}*MH#`aM%aQHDw)I|@X*X1vb=bPky%&4>el_=hg*I-# zT_bN};V{c*LJS-hcDB;0s~7#k>f#iZQI}%5&Fa}jve^>#MvI3JwsqAQnh5aIUkLFt z(>4y@36inKIDGV+S3X~*a1>@XQsO7ibjW(U+$l8p-~TVs1dPvWSy;6@L+bSbq4*T9 zyzxm5e##X~3cE;UbL=ILd471HSYHu?$V)(WC^A8mi$4*KFg=;jH@Q6ha{k*!7M5nF z`SH(xhF7m$&}01m#umn%ul~xYA>P3Lh>m#F<1^U3K_zd*qtleDS>n^PI>3>;$QMd* zu(d&}p4aiQ@Oa&UpxzV$Dwtkb(K&+8?Wfym=xb8mf8|^nXE?pvc%HL86r^+ zM?23nK}*^^`@kSP9b$4~g|Ghluk$m1?TZ|xj#--yv%a}QY+{ydeurj7kTq@ zKSd^4<2V1!Z?Um?z>BY*V{J)p+!4!@3D&m?R7<9Urwf%fE?Wah!`(S5W3`4g>P3!{ zXwXfoTPNra@WnU%%vIt%J5KX+2^-HM2Nc6S-u})qXD>8yyYoES>u~#hD<{d4&P%GT z8vT~3un9%kIeh%WU-=T35-wW#G_^vRW~0mQ$q_D}UnO8C=`2f&^BAKc`-evw94USP zY5y9{j;@BokpMooN9!gj8sEKlk8Z22c?4F|7a(MM=rpBYoz=)RL6}O8Pqkjh7oDP5 zs9?3aRJj6W+V!f2El8-*@!k>PS(sQngI_WSoo;2_%f34hnWA1P;Pi%c*dt@*?!`8~ zfLrx|se?lbg^KReJ#Gi<&!3T4zQlwrj@|91+)3iF)F_@j!!;0(VVj}Rp_O}pd*(%a z{xHA)yT8WV(mX%*na`?&XGMIC^#*6poaOy*eT$b~zKO*#;+yyWkl*>b2w!}73y(S8 ztnk{auj}CC-S@vvJwG522;#A&s219UUOFRuFY@&s!Kjx?sm%WFE-r6OH+qe73bSWW z6&fjh{Js#^u3jJ(^Rv8ghG92DrgMjL^M~B=^jWW1c=T?M8;&gIVTboqHM$-PosLDl z0nxaRm}7x@u|%%WV18ka=LaWr8fCunul|VO`rH4Sb1$r6SlZ0b#MrpI z&-(q84o(*4rf}h7dHMn?bF0ixPqMwS&hB1HXXV!(kt}ERrYvPrIEGDv&T;6a$0m$J7f!p2cmCuXNIsn;X}$5uPxJ13zm3P} z@!$UPm-z7RBX(0|92Pqhu@wzanx62pzk5KpRn`K`ZR^r351EQCV6o;%A0HA37l}>G z@#x7Bey^Q!zM;`JXD=*MtW;TlUSec!^XSPAD~nMw#|PB99$tRs6=u(WmRu&I^Z0-F zPM7B=1?tT%wRTZECa0`r=}<46(3c^P@Q<@6*i0vz8{6DCzedz6{)(bv^~K^{mny$6 zPM;h`GN%$T5t7K3RwUn2cZvGAUaLUAs`y`_iAlTe@_9HoJW`5?wOOwz4o=ERPd!Md z*HS@5?)Z>uK9AKHP^(om%1tgGvY1`Df{pqKjba9m*F&z_U~~Pk z>Hs``x55)e+AMDhhh?N95LqXS0(tLHvis_Id{IK-2sd8-92YLV!P-hfT|{CUnTQE& zHOVFa4Yg7w3tqBYk9m0eK8;j~kb8({^jvW&Zg+?e-@UEojLpZl@mL&`>lHedu12%u zk1I?qEO1y((&!hdl|@2Z(SwUJ?{aut;_Tc6 z$D4V5EsqQ*K1ui*4te9+CG`Y`tP|9#RrdFj$g|qFjc|w-K-|DqlctDXPf`D}fD>l-^FJ|=Vkny1ubm`3< z#l{q>4JIaL84Vn|r#{#};N;|(aHOc@Fj-v45F-|j>fJ8-bpa$={5~RXD^pX`dgltc zQmXk;x1|9I4tIdxdF!jpzdTPOu}H04Vkh|l>&XvU-dH4i(olKYr(d3CX6_6nnPs;F zeE#)C3d<|3ox4IlTi}Ct-l5quxc2fZ)M{Ohb~cp6`G;S-OVHb4WhP9rCPtDyY#xJJ z{g_mt%4}kuoYBQL>=FsPFf9YM%FF9tOtVg}%tMm2D$*g<@cZMWYDYMoOA4dhSU+ZF zE>2;;j@1&NQLEE#_87K%)T$lcd*@wD>C;U+|Kiua!nrf^%!i9yzdA>^(&bWOUQIb} zr%OlavbhvGi{NkM_3m&wRF5GmUK!>d?Cp`sR@px~;V6~H?)51`Kb_C3N?DEq*&E32 zrC2KJzCbz!>~5;}n*7n?u)%H><_?vUquhipIFrc*1b1WLq=GH9seb1EyA zFoRy-81rRpPV%`t0iTa(G@=0qvi-Yy^}6cbrWTiRcwB@+LAuQb$-M)%cXxUEbb~wZ zy{7{vF`RVeh#0kblzG6}*XHm~dg-}(_-6cgf>s938l6!In^Q)cE=+rnYikkmD;~FpfZt6j*WvgiLwn%h?Ak2JWRBQmluRnE z7s^m%%Q#nXD6l7?u`>>R8jkE3E*J4=h)V8|u+zd_p>zq+745T3f&!XI58KM=8s@N~NN1YZ+Gy+NU9-b=i&zXSmzb{l82G zdxNfym4|~d$H@BXkNylEf0S}DLoJ^tBO_R&hbOSAUiHw~Ak|t!BiRbsocaeD^~2o5FTq(@iOA-=@e^R{nV!sVC~!Ad5e#}*5RkV^p`PvMGiLK#~)t6Zf&T0 zw(sck!TaA}&YPx@AF!Rhr?1Jit2ap(Qdk;6zVyYv!LXAhSJ+fRYAIL5=L4^=%hKv9 z4>ukuGtuP>stjI`^5JlVdSw%j8Dc6C#Afwr5j?UjVi?a!rZY+fv)f!)jE<&_^m}7p zzr@uEc|@pR!%mr=aFmJ;jAn+{&aQHBaEQ+rRFTcr{t1<8bxiT-^fi8GXc^&lyXm&Z zNno|kfX+!)c}>$(5mr{-Wc%4VpTGGccb{yKt2C(BTX?*2O)8hopeU8(1`$<}Ok@Ql zC6o}^>{3nl~RQ>=g#RYwJq+||)(hANO=2_CDo9Yw>0(@APGWqJ&_z+Rb{h>oc={gy?ya|&m`>1Xv}n?$ z-X3Dc+)T$7u;%+bI!N)>+j;)Wzapt&KIl1cyRB?JeV^hL-bqXjsd#=sL3S+7^ z3_?a)ojc-qe*Eq;E?imT!nM!Q9yw|Dq#B;bX}7aBH%)g`QO4fUQC=B);=^xAF2U*? z^+K6cAx$P#!{-TO7!4(*36!bQacWDLKi<}#myklFAeHaW>oKYJ#yN~aIBhk@I}26x zj0|dx7U^P%uHoX*&WWb0O5N0GG*$f3>-IG4Ipp^c363RV0+H_b#l>_&A(xe`UlQ>s zl3sgm?VLh0NGjCy2jGE^APeftkkrk6r+fM9YwBewe;x?+L*l> z+YjH@1y8e-r(dtC22F&GqD1M)cEf;Q|FwTXwQD70OOQ>r3C_5%Scf$GX$BTI3o93K z1Pz|vdB#_NKdrTgz$6)zu=Ptkd%8iY+GTQe0lVR3ZGIAKtIC77GpZ5n;v+JDT`_6< z`!v^owYoKD1}w0kCdTWO5mKusKO&jb#qpM_}; z?~a;^S#kR(aoOs$tCDnJ0@* z%S6y)Gu7ZC^+Tq$#CeFtQ7?`G&d2a*KKRNQWn)oGO6cUES6yJ z@QB@mBfjyquhFbFXjba1-@nVw(~lT*E4q}h%P3O{>T+Jmmyhp0B6lK6-<(3G^^UU` zI{kaJ{hVC2jBRMB`O|6hD@D9N3gUN!6-nQf{JoBW3m3UknT3T_;z2jLJPoRYO~CU1EMO51yuUKi~~SSeXxzO{ZCylF+PzCW$*8 zeWFo2wYrE%N2-_TD)Z0D$l{_=%i{I;Xf&%jbnEtqr%=mrB#nG}TyDGqnbwG!fjWO% z>iZv1Z+EqgY|8&u9YvQ`tD)WvS#i5gc|tN25?Prhp!UXUV}W@HYG1df;tVPl%Ury0 zR%KlK>AVhNeBmJTv-8-jBhH*#BbCb2?;AuX;)EhGzWwe;G#V`e0S~c=hrRtHCMFK) zc88P-Ib3wOe(e&WfE&Nxr3(q$sWL^@ku2 zP1z_HpA&F9v3ep5Dit<1wrN-PXjC%H&d+f+WJj_%x`R6HdXAwZNGuj(X>pF^)&?P4 zp5x8mVq`{{nE0#ongx3O29{xuTC+l_Q6k{*JKk&uPQyaH-;4I7c#4Hf&=@kVMT(QKv9Z%?mWt+9doR)%Q!pp3T9aQ`h!U zigl;+3h{!o#=9}u( ztLo}*c5_g3Y*HpEnOaJg0mFhecjyoHHXcV~#M+xlsi}BpThQu6~snaql;r?|kRrd^}WMIvS5~bkxUqd?cPh6h+E! zq$*Qy_~iTqA3y#j#v=z^Cq*=S4!@ei-aNsipJBFmhB%{5{1StXhmqexv44&-jpTdJ z0Z-1a>2=J&$*ysH+7S?Pef3ggl1^Y&q3Oi+);sUO_xFhNC3ewVLY0-BYnh=k*8l(@ z07*naRI-+2E`EEp#y(9j>W?tHOR?T?wqE0S~~JU}E9(mwP2VQUcuyQvp;Fd%(^M>wCdl`8xa^_D55lskd!M)^i^5AG|schK6Rn>@q z2PPeKTQC5LbZze*>(|>$2!O3I-w=U4}DwI}=v0tIx4KbOF z1Qz*@gG02%^?I$UbFo_B(W8fm_9;BCki|*5&sBWfu9n!Q5%!x1^SdpEbg#03d!tYx z%&%kg(lyf3MUlCB(23L)kQ%U~OGo-v6@J&4})uyfMM*<11`;CG1U(BY%YZ z_bar61g)UPezrtiZ?WHQ@wN9ZQF_4DX9ae*E9Bb*xyTq54!P0n4_Xc`E{^cC|NBz8 zx2jfJ7TxS3{O-5Ehi9Mv5*tQd8dKXwC-DE5I1;DNF-x7C$5e6SYgCqM`6OylR@f(d z9R|MSDowN}r~|@WcAq^QX9fcCIA}?gWgFMxfu+>Ae$t z@ROei+3AY!^TN#SGmVSZ6iPdlqs|w(J(} zorPM0`102u;O~C1!e9UIPjGqB!9RQd2+O#Q)#iZRvnhfw!Q^CuM_>ITYZYcw6 z;tf)5m#llKnY|1mY^T}pH@6qf;wPzJ{2zZWqn(VR8;#{$a`CnlN4Y!5lwr$EqBJXG zG>-h}v!`;Yn693{b1ZaxUrUaU?w{h~e1aeR!S@ifxr{MH%PldVZ!udhq+rP{S{7?Z zlQHhU@lb2o-(vqvc#;B31XJ1}JbK!4>`)dstQJ__y}Fx! zKmO$k|LXTG+&qmCc04>^#Q2kc_bq&Wy}^I`>&N)gG%`yiZy)gF(-*jR7GPgw_^ZEq zf%7g=#tQFThM2>HRjlyo&;C37i&K2-dtU@`ur_Dpaf~>ruv#XJCm2qS#A^Q4FFrvO z?=U1a?Bx_ktudCf4O*QL^ZgVzs|d&EkMP#RJ~lh8LWeCB4W|v?$yMIh2q{!2{o-6Xi{AK&o(8DOaO%G;9BX_;sVRC$my2x;I{TxXU zVA${D=fC<);?MW)9Si+i&TplpL1M+D(=$AH>j5qvK0v$O)2LSfQIUvqPx~`U%hM3q z&TAZ2cLv;ucUa9=xVgE;)2mzT4l$gzhaddl9v&PI5bsKS@!?dh(ZBfaLp;9TN)G+( za)1v$dkKoLf9DH5tUGO79oh&7z};1jD5(%6B~C^y%tGKMsW2QAGQ`Ytx{N)-WaMMm zKb0oW^W_HVHp9Rh;l=YAKD&xVooag(KKbqEID6!1T6lbv;i%I?+piHVe00`;@3`2L zfZ}vW-GEhKhS`v|2gZlwxTuJ`MZw1l}aDtX- zV~iy9b*7LMTS3vrzxkDSaWh@w+0BjN?$m>&L5Ubq*Pyg}f81_0^r((5AHLGie z`Q09mpIj>q(3z9f{dBg#e6@w=h3Iz!Id5nyh~N>Ufgs9Mqg~k>IR#GNc!>KKJvgg9 z-g@&AqppwMpbsY);(B_6)&2zv$5YYxrTYgIOet^O!;_n*c;m}&;Qilw6CZx~F@Ey5 zzs2JN5Dd7ZkR$92V0Xvp`8B@%wQq=IdHd`Io_%_So9Prza4Hq_kAMAZJpA%^;kWki zS{3fy3-Q*2F@F7}sOXZy=lBo7~{RF;KumL$t;gHo|@B=ImSRtl*;hY}+x>H*s!I8`loA-_Le`K(2vr<78-|-#x}hPp&atF0qU&Ja{m~KYZ|0 zxZw!zef1p>>)CA=Dk#+sCqLrUXdA87uLiV>sZ0G3{zVYOZp;a&K|{?tU#nln9*xvf z17sMn!z9ZZbt+542&#HmjlfY+R*mF55XXs(DyP#0@@y|nox^?y->tP^x?V3uFd0qW zkbvXz=5ut0_wZu+82i-_LKOlIBA7csaOC%U?5_J1q>m9nD1+tBno| ztN8J8ANwfNOWbef2&^1md+#eUid?NDv*#zZaM#GiIcD{X#isgvZZtbaABinDe-9a6 ztQ#idiF^e_^Y3->;QR~^PLE;zo8Nz*QviKPiW~7iBC^J%L^)KH26SM7I2`n(QKuiS z)7UI8HnQa8pE1t>0zQ;2W3!xo0UQ1t6zKR~bNU`YTb+u(T8#?es+ zi^V~nKb7mjvIBVsaQ;5Kd!`Dy#|`FvAqg4!;*L8Ny#5*9`TD=c-~Y{DAg1qbno4|; z<_d&p8IbN>9^>TvScla2J)EAOq2+fZ&U|_@7P&KQWh!_NQG#}>5((z#A3nj$d5So0 z2^?B&QY5)q)gm>H!yMi&=2=BM9eV4vPLB*cSRy*ml#yZIC*V`N63d`Aaam^iyj-^> z;g&y%?KO20G66x5E`S;N*9~r9>G`w0qh=5<9?7CCBs-l@BY8$^wtid@=U^*I4se++ z+9BL-*b)U=HmZDg$n$_^4@!vH@iv^1lx{U;`SwV6fkwt_^ z7MTi{cCW3p&<=g^+K#E$r{boi;m)Ir3z0>(`!yb4-C`fb$ZA^H=K36)i0Wg7WM*nN zhFdOB2No_bzKSUN6suK)+4UVhzxzv^k56&)DA3^~D6_g=YE|v%IE3AI z5icv`tw6N(PAf!}lZgI{V0yd7C(mY>Z=?yPjQROk`9oV5Mcv*>a8bK1Q5D>t{MVR88PkFMXSAgXnRTiw5-3 z>X(#6b2HZUZM^a<<2z{6IEs?6WiC*UX45S3q6 z$tC2iNBw)A;K1k3pC?BP-e4|irkN2s@@Y!k>uM3fYNSa#-;oj~ml3J;$MtC9(A@sz z3iozV3x4JoBVw3l{K6j6%tJdoLsexc;|wofTp@QYc1toSKmFs=gu>Dc7<+X!*^=<3cZkzajy$_R*H1XJ;M-Lbc^AnW$f+aL}|#Q z9E)Gzu#Iu`;((`DE5v&bL8p)V_fBMWGdUXLuseul>vr0(29&zD#ml#DRE@l|! zsU$`n_#LCSv)f^@-fBghp|Hb6mBktvms0{C?NJAxe)^d-_DF|{Nx-O#QYI9+Otq{M zg*)-OH8$EU3!RpY0fiLn3}NWP^=wJjh5@%_Y_phAShA_PzRghDLr_2A&C7=}bzpkr zUgU1OlW@j*zcXf&6mkeXy!GgwtXoOg=nuN+_XlG8P)C6J3DdhN=BtBTK8q@bRaw}@ zx!BQ*Xpdc*X`IWK&aNp=3(>pztSBwdV%)Y{y5)@8tk+(31XbfI%EQ9{mSLZ1fkn41 zZvjV_lfVDs;y&)CGgyEAAAeZ0cw4QuXm>hD^F*x$=K`DU&IlF-HiC9nk%6m6^ue|D?*hR_FlMm3Ay1Hz>2!Hs`zmIRe|81O~-A7%f*zY#_Z}@q5KyPnuu$XV~@@^%4p3zYs-7vtThxgD6 z%`zt64?6(XOiSLpypYHP^RpjxWG=N^N1A%_d2>OQ+I`{#l#m<@FXCc-z+$(@n%uz( z0)H&k45gx|B;;y?9`etyZG$1y&BhR;tmNkod&$Z0-%+HS^BuR{jBp*NuK~osHkBng zV^uZ5bh^YQPSkg=_o+}NqG^2K3_+A66(*NJbAvh)t1WUjj*yNh^nIXmb3_3C0ANj0f;6qosF9p|R+o+f(aV%~$d$Ec6hX zJorykyex%Ps2`^ffGq^Agq2(3_O*Q%!y&~n&+xUkFVre6X4lxvr-H(dPw0|5)!6&u zY=l!*><22UK!q0PAx^8*=ZcFM*Ee&_7aN6Y(!DeeW;<9x?KVl7Tn3?c;%6^jh*-<* zE2^b&y`C#vuRICKfpGnSWZ(Hb*(I57$`+B87(bs2(LjDarX9{y_$WGkBS^slleE6^ z@hJ|6y`=xxmAHdJ4+E=*l;i^#+ZBQa913w8b-7P4-=>HX3t8dn!6x~^%mI|wD+w(- zFi4Z>^oWO5I*lwmC_T%Lf>k+d30AMX)scuIg<4Ejs0?R396?|r0?7|&m**ISK3tpa z-d08mn>fXKpJ=<4+D06YG6%Ac*W`;khmB)~)%>4*xbIjJq!@HVoE#0%vPzsD4J2xD z?{tE*(-Xv5tu?Fxz5q+_hnE;Kcjt=$ZU(xh^`)+C^qiltoGB~wC1X} z9PAH!wRUzhD^RV$SwN!(!YE7GpN!;OMdlJ@fs^w|7@uNb)}R0A&uT*$ERc|7a7YB( z5_?|CAFz_J;wyEb0+srE?g+4`qs#c|c%=4(?9>%sP_#FpxQ0}!40PGZE$Y`_UDHaU z1`NS+`*2+qJ+Z(j8}~*>Xty1Oe{R8W*@1d|+c=eg^Fg`4GGIq#NE7;UE!RxpJXc?o zFP^RGXb__7*;>1%yCz*o_+W-7$EIK-F@^ek+@*6J?KN-_#cpyZ4-|iHRb&#=-o`n$ zyTquLSgy2rWzeXHpUSsLZa!6^P)^?mF3r&6i1hT~aDZXJh|1c?jEwiRhYh=01D~rF zOR?R@x>zjADg3mJb~=zW)}%tq-QCm(NwcO30v&?oe4);aBmC>zTXh%mA}9*@uJf81 zWc~0Dzh8@nR1~V{ndhj{$BJ<<8fj=iJvqmy6{8?gAx=bcWZ@<+nm7>)HLFTlobiLE zG&UsqRhm3Y#ctA_okpOYkwAL*VW^kSL$_6DVcahUed-2y%J;Xkl@1kgZSoNKS0d~5 zQX@|-K+4t4QqjluZ4?GFz~s;1;oi`%k1cDFA@Dqeo~ub6Z~yt}i7Mxy-A9t_C24zk zHi2Ci!Y#_OqvP(NgTh0@c?sQJUHSC}lE3GHK4euhnM*{> z5IagjPMHocRn|D-e&q}vcDmZZ;H@t5qUi_3qvYD*d~kpO`zz9L^ z26-L49DL8+Zdd-$TrY3y8F{vfC!QvLc-oKp!31H;*X@x1e3>C)!3IY!h(!u-qw=Za ziVw(fB+V!LL8z9GbN^DUTMoCj(I&Ama5YolpU1+GgQ)FhgH>dTo{S_DPPIr_EF;W{ zOdGN5DAq0;b7-cYTQz;K)xe^7O_ngow24^jI6<5hN;7-zI})s7)tqvuQ(~J}m?st1 zNiERC^>#*K6qeS`x$b>3?BVQqgl;!8Mh#YmZIt5W%?ep+iCM$S+^P*Bv}F@}2=sYr zG0P39&CYZgybM+8Xf=(R#boU6t3+dIcs|0x1Pivv%O#3(`da9L?|=v&!LN!@sG)of zI$aDpJ#}h_EEE6Wz&@XQ-x|C5@xcb}RG5hr>4 zgW38C!K#ge24O}hpQj3W+$uTHtdK^{?1NDWlwf$38qTy4vF;jX}I8;@hP>D2Hma>e8`&@I>IzK2N4O=HM0v2R0iF)evORYXrHJvB4kW| zMOND6DNrzrE8g6irm81vnj6VsZn_aMQjN{5}gjr_b!31Pdd8i@j(EDl*?@%iw*^8L7^ z78B+@9u5`WI^DKH6UiG@U8w(L$mGV!Vz$6$m*{q{H*3^YTP+RqVb)*+a6|0(hgFp?#IU!f3hNHDoM5gQ zIkH?G4mA>r23zN5^qWCT2Rm?E=yW|DN>=gwEUb~ZAj2AhSU-zZUMNKf*O%itW%l@e zIrt@&iwf;_m0>bD(!7DxyxC%f>3oUBI>KzZ!Oe1wgf>17v6Dgvfl;$&5zUo0B8wEZ zO)eQ(*=N__S?n*{_Qk0#WSwTfE5xJ8Youw-EB@ zph7qBaMTag9vzQ|5_KY*rr;c-ahsA6rab}7Na82rv#CY=L zIda?6OSrwA0hT8UGr<}bGu+WXKb=S}mMY|rA72Z_^V$FUf$|f9AHH;I{fY5bRYvDO zO*Q>uJ4SsyV&-XD35p(uEwt!@#U+cnMoijNZfMSA<4k(Q^({m98aX%~_R*%qyzNNw zjKvXJ)ZBBmL{U_^7CS4eLdb)W0sd+=E2_ey*ZV@u&Y(^Jy!D>u0DT?bK-yvqGI1yCI^vGOV_sLQvvR z%_Ns?tOim=E{Ke*Y^6|c8Q=c&f7IO5OSsr5AG;m0G?s55r+mcrIk{5hzdK+)onf{* z;N!|oQVCUi^WlYVM5u>gdf~%9Q7cFJ5=)gxr3o3UYqPMxzWRW> zyM>|7moI zFzmEZ){X!h9)41@$V}$LXYnT&&>|B8DEPc%?BJN*$mM72%v8y`f%6T8Y1>iCV0&IO z>Q!d=#_odM6+1E3TYS!X2UYc&8^#dNNWzYYK25!T&q&XwF-}kJnVAbkIzIfzpUSbS zmeg1&2$t1+r{7WGvfIX5QNCNO)Q&xQIm6u|LXz`A80~snt`xR#=6>5ppR8ZPll0G_ zaItMGpB0rW?R~%192U`}N>$n{dicRP89O^_izUlCf-IK1=^Ozyhq-mhKabRAx?MOf zhT7nDWxaZRJJ;lqq7R)`jXFxSM#c8E-5+UxfCXhlce58$+|IWu2vtDJQM6LXrygM^ z?4iywjK^c$QkpgsbKvb_Tg5hy(XwSzn>f^=CdflOJZIRIo)U{v;v3vm;NArnWLbIF zdxL3Y@&DRPP!~dG-GsLu)|lB`Je;W}a0$ch!IIAuvv;Ci`z-AWY#BTUHR zgYX)M3w{E=eBX1_{)oR0OHeK0N){>=S}*0ak(1A6 zxyX}P3Yg5n95C@Pv1Q_pf^D(h@DS&uvj-}kmW7Qszxo|)?yj^Ev!WU1V4$2iU95Gp zXR{?N&&SPdWek-m$ZQ)dge@!=TcB2s_o{&7wDKyV#vD;|>agNWt zPs>=YcS$BrtuVa-bIJK}9h@nP5r{}DCzm{2CzBKD1yCE1&+zi{0d8(?;Xb=rsxaUm zTEz*T-)&W#um@-8%K0HAJV1n!EK{q;eFN^x z`yBbohbUGK@3kHE>kMTv%@DXe+D!Crr%Rpw4mV?yy;*L^jUf`jr~N+1ZBpZQeZZiX z!{3&QMCng|ipr;^!496+#o}(GR_boH#B#-!)yC#9)p7*kR{~&G(-#lBZ7kP2oScm? z84gu=^7e6=n&)E|cN%f#QU`$bj?MW$`39k{h!=!`c}{+SB46sI93KtUSseF+CSQBV zsuXcnVY7>|OLJ^(vj+&;#Pj>MeANRa-()%jxtzof+gxL5_V2Q(o1Wts@nRAt~mehln|$U=h_(Wi7*r{T|Qm zW=M$A?e;2`NNOO!L4%3bD$+r-y_TkFncc#m0KCYES7g^KjXHU-BT`l!-nMyXizEu=sy)_Emj2t|W+`(_teap4b>$Fg& zh3s}YS15~xOfQKKuw5fg-;vWwA#lg7Tez7|u}^X_unFf1J|~y`6JY=V1Yb!+K~$rs z-Bm3?k_caHAp=N53~`(QXXoc;pthQco5iWF70~e8m}>F)5Ln{(nJ!iu0&xR6@QzUD zxfWA->8wBc)|czR_cd1JN#afB)Q*dV%6A$T6**l*f9|3i)(EiG0llzOd+j#4c zSML}*HX^3f0g!7u$)IHDqS7G8;b_>L4qIKNpgS8{*n%9(n5bjx6U#YBffCKv6hi4wT!_r zI|?2gei`}(^4CZ+=WXK$6|dcO1^*tR9N8*qhDL=#S5ns4rG;9{JU?K^_6ddt&D=%1 z12Ts>JTVV7d|eQlX{Dp0(2{j51b!sinS(59D3L}rRNhE|CUv0@E#oE247#|kMdJw$ zaJb|_DL7k9Uk-c>%P4CIF0AtTyridmNX5b-m$6dCZeh8I6v|};73HdXcxd>tI4(|0 zOL{<+TtSSHlgPLz6=B#atGyF@%5Rne4Ly85n<|o$jLK)s7E$gl#}m1*bIN);xxi|@ zlM7sC7slwSFs$#O-GNI1VxmU8<%iUSbqW^H)r*@x%yXRXb3VWn5GT$2*>er~v8g(9 zsZ$ydNquK&nJrho9Lq!wj&FHTcCs}!u&!zgs*iU%W?bsFEtGX3dpH)h)c<9~YIOpomAd6(vz(!2RjQMy zDAo^1#2w@6`W7orRbdP7SS;6YttPzjUyy8(q@|oYUzrOPT2d^;s--`$*)6kVQ*PQu zPyZ}Rc%8%Y%w&+m7Tq#}HCe6~U@J_ziXa-@a;!2Cxpf;Ibi)WC z6Aa=FQAqY$Chd4WoGL>rbTOUHb*NjiUNMwxVi>v*R literal 0 HcmV?d00001 diff --git a/discord-export/Code4rena - Archive-2021 - swivel-sep30 [892486622401159260].html_Files/cec17fe3825e83ddf170d7e8c98ece3e-B6D17.png b/discord-export/Code4rena - Archive-2021 - swivel-sep30 [892486622401159260].html_Files/cec17fe3825e83ddf170d7e8c98ece3e-B6D17.png new file mode 100644 index 0000000000000000000000000000000000000000..c55870b3567e5fbf04d559a554c7cefd5b1f0956 GIT binary patch literal 27797 zcmV)6K*+y|P)W!(*E?ZEb)>>z4on)(-*t zX9ND@ABF`%@Fv3|sKul}QIZLW)_BaBo}QVW-m1H6efyUCewPU2oQSyh=3A<&$CBwg z^SY|udzpD}#EG+f=R4u6^SRHz~|LD1Ht7ioL%$2_YN>DI+|2`Z-Qc5BNQ$j4_?g;5r5D+`Nyw zx8Hz(2PqZ5_EqooU+<+L>2u9T3wj2n%o=CwEH15q{u%8J|4U_SZU3a#IF7@=L(iDK zkD^b7_l0j&*+13KywNYa=>CM`*mu>RqplDD{z>kkl!8noKd|cvMDY~eUJIwE2XLGO zj;ntj1U>{@1ilZ)2%Y1)>C^n-2!Xwn{l9rG2gpC8{jJ;q)xU%EAiV7U?O~zI)Bm_E zS$cEzFV1U%^wuuD@#Xiq`h)5B?8(i)PyWV9K7}%W!oEhOe`cR2(;HMmu|P!8481`M z`v=d^>6{}dI1uz^NLVZQKAm_6k`|F(Pa1|6F83VzGnBbQkz0q$f}d@d-VELZzV8>W z$K0#!f6}$detMqQQ9xQS>8A&-F#AGR?w8x8%}E7_2|7Ny4^Mo z5BG6;b_~}A0^i9#Te<1N(AQ`@7omx$u7U|)t6TL zW}SpxvllJ4Gbecb=|)T1&yrHi32a^vthq=9fHwU2Y!8EBH@7MFq`7D|ma($90hdmW%I-U0_sDpW#g4H3>Jc)t4x zr)P(V;~6|pzm67G#k8mngzJKC#c>pb>tHw-U^bhgRIEYCgcn69hc}#rlx?QKrG>tH zS-XpD!9^wnud-acJ`Qr5^|Du8`~{I7P<{@fQhzMdxFXfScFjHd$1I%S`Tl1Jqwvay zQYt~KbAst~jO~p(@Vu9~4uWss@pCnc@NJzxV48B)j-;g#? zCJ_q-{d>@BVXH$K_Q!SC%q#)lvM2w^mW<47b)1mAa{WQ=a_91lPH0F!ACj!PyZL7`AUrBY_i zQ>|6`@5NF9j;j~Jb7^5DJWt@^!;f%&egd%Rp?e_VNYX!{V*RJ_HOTDb{RLW3+IW{$ zc*6HazbjR2%%FM&b#As$T_0UtUh}K=AeGJR=fb|P)eK@zD>>bMi%&LPJ3BYo`ba#V7i+M;{}KCwgN&7ryVJQYo<`SgTc0EEf2^NYFXlN)k3D ze7dDXA@ESEl>rfB7WQz~+QqZoPw?=wAK}T<4{_Gs#dOwzQd0;K!4V06mg~6bX(FxS zx&p2b3`T8y{^%1HOqs+i9NG_f#U(SlsKYjC%;*2RsDyp0+~;c_On<}c4ce*UI5|B- zqfy7N{U`qc{_fxXUr;KQ@Ynv@U%|6yyO_;p`qq>Jy{25MzT{)=hpNm8GtS+Wzipf| zG6S@+ZU98lluxNrAw18=`S~%zTX#_i%B(4lk54fkcM${*3dI7#Xv(KQif6od<#GY- zR*OTtC{p}A+7Klqk~rbN7XlxX$pCwM&(Q6jBT8mk3!0N6k0g9Qz(RcmOG_)L*PAF5 zt40$DHbZbCgy9s2NBh{_dk)_VaQpTSJY#nFGrzzds>}e-Id(tm#lmh3#Krp%f9#L_ zS*1^hzUajK#lQHgZ1Zx|aX(+|1$p)e;oum0Ru zaBdQ^-A;^WyN~er*{3KL1)?a1N?d&7Yv0D=!ZN~Hi1$DEF$TjEKK1o_jWrVqz-Tmt z7mm(MX}^*X9o_VP(mg%HV@K?S;do6DYWdT zAQ3%yIGgbzlE4U&!0{ZtKq|X;R_}C6qt-mEx697XUwAEjcEZ8tfS+TqjQ zK81piWUjPt;yE6lVsh;0%jY17-fxUJnZR}F9+Ytc6O2a_tgfu{Yhkp=^(R)P>tLVX z`b~Bntq;W})Df4o?TfDTHO^&6l%eyyEhjblSAYF4;p2}##c%%RKgQqrJO2}W-^YLa zYu|zAXM$2G*K#49c%he@#_I;&Rjz<^%$K0EtkO^`Q85x3Fr>

kXIcz>?6KK`13>h553$tR$U^dp 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 literal 0 HcmV?d00001 diff --git a/discord-export/Code4rena - Archive-2021 - swivel-sep30 [892486622401159260].html_Files/df4391e9033659fcd5fd4c01aae14551-7F4A0.png b/discord-export/Code4rena - Archive-2021 - swivel-sep30 [892486622401159260].html_Files/df4391e9033659fcd5fd4c01aae14551-7F4A0.png new file mode 100644 index 0000000000000000000000000000000000000000..6c11c752dae14f71b0138a913dd8546a9ad6adfb GIT binary patch literal 9079 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 X0}a7KtiK!600000NkvXXu0mjfCw_1q literal 0 HcmV?d00001 diff --git a/discord-export/Code4rena - Archive-2021 - swivel-sep30 [892486622401159260].html_Files/gost-0F62A b/discord-export/Code4rena - Archive-2021 - swivel-sep30 [892486622401159260].html_Files/gost-0F62A new file mode 100644 index 0000000000000000000000000000000000000000..86288d27683947d3b35bc17b9a3ea24f4a120936 GIT binary patch literal 56977 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 literal 0 HcmV?d00001 diff --git a/discord-export/Code4rena - Archive-2021 - swivel-sep30 [892486622401159260].html_Files/unknown-D8713.png b/discord-export/Code4rena - Archive-2021 - swivel-sep30 [892486622401159260].html_Files/unknown-D8713.png new file mode 100644 index 0000000000000000000000000000000000000000..2c0f563c595d57034ff46c32bd97790645cd5f4c GIT binary patch literal 12082 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 C#t@+Z literal 0 HcmV?d00001 diff --git a/discord-export/Code4rena - Archive-2021 - swivel-sep30 [892486622401159260].txt b/discord-export/Code4rena - Archive-2021 - swivel-sep30 [892486622401159260].txt new file mode 100644 index 0000000..ee5149c --- /dev/null +++ b/discord-export/Code4rena - Archive-2021 - swivel-sep30 [892486622401159260].txt @@ -0,0 +1,154 @@ +============================================================== +Guild: Code4rena +Channel: Archive-2021 / swivel-sep30 +============================================================== + +[28-Sep-21 02:01 PM] itsmetechjay | C4#5294 +👋 Hello and welcome to the contest channel for the $75K worth of ETH **Swivel** contest! + +📆 Contest opens Sep 30, 2021 at 0:00 UTC and runs through October 6, 2021 at 23:59 UTC (one week). + +Please give a warm welcome to @Julian | Swivel and @jankisa who will be available during the contest to answer questions either here in channel or via DM. + +We'll be posting relevant links, documentation, etc. here, so if you intend to participate in this contest, you might want to enable notifications. 🐺 ⏰ + +{Reactions} +🎉 (6) 👋 (6) swivelSpin (2) + +[28-Sep-21 02:03 PM] Julian | Swivel#6740 +:peepoParty: + + +[29-Sep-21 05:04 PM] Julian | Swivel#6740 +Hey hey guys! Julian founder/CEO of Swivel here! + +{Reactions} +TE_PeepoGoosee 👋 (2) + +[29-Sep-21 05:06 PM] Julian | Swivel#6740 +Our 7 days in the arena have just begun, feel free to reach out to myself for any questions (logic, intended effects, etc.,) or @jankisa if im not around! + +For quick reference our docs can be found at: https://docs.swivel.finance + +{Embed} +https://docs.swivel.finance/ +Swivel Finance Documentation +Documentation for all things Swivel Finance. +Code4rena - Archive-2021 - swivel-sep30 [892486622401159260].txt_Files/-MUa9tmyPufyVGMmAkKT-437CE.png + + +[29-Sep-21 05:08 PM] Julian | Swivel#6740 +Excited to see what sort of disgusting things we did / missed :2708fingergunz: + +{Reactions} +😋 (2) + +[29-Sep-21 05:52 PM] t11s#4397 +all these links are ded 😅 + +{Attachments} +Code4rena - Archive-2021 - swivel-sep30 [892486622401159260].txt_Files/Screen_Shot_2021-09-29_at_5.52.46_PM-DA8FF.png + + +[29-Sep-21 05:52 PM] Julian | Swivel#6740 +que pasa + + +[29-Sep-21 05:53 PM] Julian | Swivel#6740 +ill check on that, should be public, just checked a few hrs ago + + +[29-Sep-21 05:54 PM] t11s#4397 +links to a "gost" repo + + +[29-Sep-21 05:54 PM] t11s#4397 +https://github.com/Swivel-Finance/gost/blob/v2/test/swivel/Swivel.sol + +{Embed} +https://github.com/Swivel-Finance/gost/blob/v2/test/swivel/Swivel.sol +gost/Swivel.sol at v2 · Swivel-Finance/gost +Smart contract testing with Geth via the Golang ABIGEN - gost/Swivel.sol at v2 · Swivel-Finance/gost +Code4rena - Archive-2021 - swivel-sep30 [892486622401159260].txt_Files/gost-0F62A + + +[29-Sep-21 05:54 PM] Julian | Swivel#6740 +try... now 🙂 + + +[29-Sep-21 05:54 PM] Julian | Swivel#6740 +gost is our custom testing framework written in go / directly interacting with geth + + +[29-Sep-21 05:55 PM] Julian | Swivel#6740 +We decided to link to it instead of a general project repo so folks could check out the tests if they wanted + + +[29-Sep-21 05:55 PM] t11s#4397 +coolio all good now + + +[29-Sep-21 05:55 PM] t11s#4397 +:CatJam: + +{Reactions} +chadJam 👍 + +[29-Sep-21 06:11 PM] 0xleastwood#1463 +excited to jump into the code! + +{Reactions} +swivelHeat 👍 + +[29-Sep-21 08:24 PM] Julian | Swivel#6740 +@t11s + +{Attachments} +Code4rena - Archive-2021 - swivel-sep30 [892486622401159260].txt_Files/unknown-D8713.png + +{Reactions} +😆 + +[29-Sep-21 08:46 PM] t11s#4397 +😂 + + +[01-Oct-21 06:52 AM] Julian | Swivel#6740 +Hey guys, two folks asked for more info on exactly the interaction between the methods `exit` or `initiate`, and the `exit` and `vault` params in the orders these methods might fill. (its the most needlessly confusing part of our protocol lol) + + +[01-Oct-21 07:04 AM] Julian | Swivel#6740 +That said, @itsmeSTYJ was kind enough to put together a quick sheet that organizes / explicitly explains each 🙂 + +If anyone is interested: https://docs.google.com/spreadsheets/d/1EhHHbfNNv9VC55yPDnR52vZDToOTp3nEBh9-N53yClY/edit?usp=sharing + +{Reactions} +😄 👍 (2) 😆 + +[01-Oct-21 08:11 AM] csanuragjain#5772 +Bit confused, why code is calculating interest everytime any user adds ntokens on same vault and not when user exits the ntoken position via redeem? (considering exchange rate can be fluctuating) + + +[01-Oct-21 10:30 AM] Julian | Swivel#6740 +The interest should be recalculated during the redeem + + +[01-Oct-21 10:30 AM] Julian | Swivel#6740 +https://github.com/Swivel-Finance/gost/blob/v2/test/vaulttracker/VaultTracker.sol#L102 + + +[01-Oct-21 10:31 AM] Julian | Swivel#6740 +If redeemed pre-maturity, it calculates since the last interaction exchangeRate -> current exchangeRate + + +[01-Oct-21 10:31 AM] Julian | Swivel#6740 +if redeemed post-maturity, it calculates the last interaction exchangeRate -> the rate when the market matured + + +[03-Oct-21 11:21 PM] csanuragjain#5772 +got it thanks + + +============================================================== +Exported 26 message(s) +============================================================== diff --git a/discord-export/Code4rena - Archive-2021 - swivel-sep30 [892486622401159260].txt_Files/-MUa9tmyPufyVGMmAkKT-437CE.png b/discord-export/Code4rena - Archive-2021 - swivel-sep30 [892486622401159260].txt_Files/-MUa9tmyPufyVGMmAkKT-437CE.png new file mode 100644 index 0000000..e69de29 diff --git a/discord-export/Code4rena - Archive-2021 - swivel-sep30 [892486622401159260].txt_Files/Screen_Shot_2021-09-29_at_5.52.46_PM-DA8FF.png b/discord-export/Code4rena - Archive-2021 - swivel-sep30 [892486622401159260].txt_Files/Screen_Shot_2021-09-29_at_5.52.46_PM-DA8FF.png new file mode 100644 index 0000000000000000000000000000000000000000..0f68f5acdd594d8806bab982159c4e6560d19afd GIT binary patch literal 101230 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�!6$l-**BY0B13PvGEBL`f^%O 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 literal 0 HcmV?d00001 diff --git a/discord-export/Code4rena - Archive-2021 - swivel-sep30 [892486622401159260].txt_Files/unknown-D8713.png b/discord-export/Code4rena - Archive-2021 - swivel-sep30 [892486622401159260].txt_Files/unknown-D8713.png new file mode 100644 index 0000000000000000000000000000000000000000..2c0f563c595d57034ff46c32bd97790645cd5f4c GIT binary patch literal 12082 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 C#t@+Z literal 0 HcmV?d00001 diff --git a/gost/.DS_Store b/gost/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..15d9a6d7f282b35d69d36da37bc2658540e63d2f GIT binary patch literal 6148 zcmeHKJ5Iwu5S>koVn9L>RZ5q%xq*pH0UgQ(LJ|lO4vrw{UDI<9PC!S4!~qaO+#@u+ z*;yPf4$vV4Gt%y}=d&|@mUp~FWIFRZ@url+MH zV!elOY%XIurx_j71@MSce-{aFSNW7{87+!hDr-%$Wkp~4d3D+Skm@w0Ga7l-)E3vM z##zcW+`JyV^HErrnX6VWUyx%_3M>bgH1jfUJ>8dW<($38!<`p-2Ssf8c~{xJyxaWx zRsJah=-Djcrl8KsfHI&A6b$hG5MeOJ4s$`fbzrhb0AK*M6EMxEZ>>BW_u2@fhrz;rxu6Zfl;8xtiumW4e7r@wIE(i@o Oe*`QIIw=D`%D@|PUWShV literal 0 HcmV?d00001 diff --git a/gost/.travis.yml b/gost/.travis.yml new file mode 100644 index 0000000..3af854c --- /dev/null +++ b/gost/.travis.yml @@ -0,0 +1,4 @@ +language: go +go: + - 1.15.x +script: go test -v ./... diff --git a/gost/Makefile b/gost/Makefile new file mode 100644 index 0000000..75374b5 --- /dev/null +++ b/gost/Makefile @@ -0,0 +1,229 @@ +.PHONY: compile_solidity_mock_erc compile_go_mock_erc compile_mock_erc +.PHONY: compile_solidity_mock_cerc compile_go_mock_cerc compile_mock_cerc +.PHONY: compile_solidity_mock_marketplace compile_go_mock_marketplace +.PHONY: compile_go_mock_vaulttracker compile_go_mock_zctoken +.PHONY: compile_mocks + +# TODO under? api-specific sol? + +.PHONY: compile_solidity_zct compile_go_zct compile_zct +.PHONY: compile_tokens + +.PHONY: compile_solidity_sig_fake compile_go_sig_fake compile_sig_fake +.PHONY: compile_solidity_hash_fake compile_go_hash_fake compile_hash_fake +.PHONY: compile_fakes + +.PHONY: compile_solidity_swivel_test compile_go_swivel_test compile_swivel_test +.PHONY: compile_solidity_marketplace_test compile_go_marketplace_test compile_marketplace_test +.PHONY: compile_solidity_vaulttracker_test compile_go_vaulttracker_test compile_vaulttracker_test +.PHONY: compile_test + +.PHONY: clean_test_abi clean_test_bin clean_test_go +.PHONY: clean_test + +.PHONY: clean_build_sol clean_build_abi clean_build_bin clean_build_go +.PHONY: clean_build + +.PHONY: copy_zctoken_to_build copy_vaulttracker_to_build copy_marketplace_to_build copy_swivel_to_build +.PHONY: copy_to_build +.PHONY: compile_marketplace_build compile_swivel_build compile_build + +.PHONY: all + +# Mocks +compile_solidity_mock_erc: + @echo "compiling Mock ERC20 solidity source into abi and bin files" + solc -o ./test/mocks --abi --bin --overwrite ./test/mocks/Erc20.sol + +compile_go_mock_erc: + @echo "compiling abi and bin files to golang" + abigen --abi ./test/mocks/Erc20.abi --bin ./test/mocks/Erc20.bin -pkg mocks -type Erc20 -out ./test/mocks/erc20.go + +compile_mock_erc: compile_solidity_mock_erc compile_go_mock_erc + +compile_solidity_mock_cerc: + @echo "compiling Mock CERC20 solidity source into abi and bin files" + solc -o ./test/mocks --abi --bin --overwrite ./test/mocks/CErc20.sol + +compile_go_mock_cerc: + @echo "compiling abi and bin files to golang" + abigen --abi ./test/mocks/CErc20.abi --bin ./test/mocks/CErc20.bin -pkg mocks -type CErc20 -out ./test/mocks/cerc20.go + +compile_mock_cerc: compile_solidity_mock_cerc compile_go_mock_cerc + +compile_solidity_mock_marketplace: + @echo "compiling Mock MarketPlace solidity source into abi and bin files" + solc -o ./test/mocks --abi --bin --overwrite ./test/mocks/MarketPlace.sol + +compile_go_mock_marketplace: + @echo "compiling abi and bin files to golang" + abigen --abi ./test/mocks/MarketPlace.abi --bin ./test/mocks/MarketPlace.bin -pkg mocks -type MarketPlace -out ./test/mocks/marketplace.go + +compile_mock_marketplace: compile_solidity_mock_marketplace compile_go_mock_marketplace + +# vaulttracker and zctoken do not require a solidity compile step as they are directly imported by another contract which compiles them +compile_go_mock_vaulttracker: + @echo "compiling abi and bin files to golang" + abigen --abi ./test/marketplace/VaultTracker.abi --bin ./test/marketplace/VaultTracker.bin -pkg mocks -type VaultTracker -out ./test/mocks/vaulttracker.go + +compile_go_mock_zctoken: + @echo "compiling abi and bin files to golang" + abigen --abi ./test/marketplace/ZcToken.abi --bin ./test/marketplace/ZcToken.bin -pkg mocks -type ZcToken -out ./test/mocks/zctoken.go + +compile_mocks: compile_mock_erc compile_mock_cerc compile_mock_marketplace compile_go_mock_vaulttracker compile_go_mock_zctoken + +# Real Tokens +compile_solidity_zct: + @echo "compiling ZCT solidity source into abi and bin files" + solc -o ./test/tokens --abi --bin --overwrite ./test/tokens/ZcToken.sol + +compile_go_zct: + @echo "compiling abi and bin files to golang" + abigen --abi ./test/tokens/ZcToken.abi --bin ./test/tokens/ZcToken.bin -pkg tokens -type ZcToken -out ./test/tokens/zctoken.go + +compile_zct: compile_solidity_zct compile_go_zct + +compile_solidity_underlying: + @echo "compiling Underlying solidity source into abi and bin files" + solc -o ./test/tokens --abi --bin --overwrite ./test/tokens/Underlying.sol + +compile_go_underlying: + @echo "compiling abi and bin files to golang" + abigen --abi ./test/tokens/Underlying.abi --bin ./test/tokens/Underlying.bin -pkg tokens -type Underlying -out ./test/tokens/underlying.go + +compile_underlying: compile_solidity_underlying compile_go_underlying + + +compile_tokens: compile_zct compile_underlying + +# Fakes +compile_solidity_sig_fake: + @echo "compiling Sig and Fake source into abi and bin files" + solc -o ./test/fakes --abi --bin --overwrite ./test/fakes/SigFake.sol + +compile_go_sig_fake: + @echo "compiling abi and bin files to golang" + abigen --abi ./test/fakes/SigFake.abi --bin ./test/fakes/SigFake.bin -pkg fakes -type SigFake -out ./test/fakes/sigfake.go + +compile_sig_fake: compile_solidity_sig_fake compile_go_sig_fake + +compile_solidity_hash_fake: + @echo "compiling Hash and Fake solidity source into abi and bin files" + solc -o ./test/fakes --abi --bin --overwrite ./test/fakes/HashFake.sol + +compile_go_hash_fake: + @echo "compiling abi and bin files to golang" + abigen --abi ./test/fakes/HashFake.abi --bin ./test/fakes/HashFake.bin -pkg fakes -type HashFake -out ./test/fakes/hashfake.go + +compile_hash_fake: compile_solidity_hash_fake compile_go_hash_fake + +compile_fakes: compile_sig_fake compile_hash_fake + +# Contracts +compile_solidity_swivel_test: + @echo "compiling Swivel solidity source into abi and bin files" + solc -o ./test/swivel --optimize --optimize-runs=15000 --abi --bin --overwrite ./test/swivel/Swivel.sol + +compile_go_swivel_test: + @echo "compiling abi and bin files to golang" + abigen --abi ./test/swivel/Swivel.abi --bin ./test/swivel/Swivel.bin -pkg swivel -type Swivel -out ./test/swivel/swivel.go + +compile_swivel_test: compile_solidity_swivel_test compile_go_swivel_test + +compile_solidity_marketplace_test: + @echo "compiling MarketPlace solidity source into abi and bin files" + solc -o ./test/marketplace --optimize --optimize-runs=100000 --abi --bin --overwrite ./test/marketplace/MarketPlace.sol + +compile_go_marketplace_test: + @echo "compiling abi and bin files to golang" + abigen --abi ./test/marketplace/MarketPlace.abi --bin ./test/marketplace/MarketPlace.bin -pkg marketplace -type MarketPlace -out ./test/marketplace/marketplace.go + +compile_marketplace_test: compile_solidity_marketplace_test compile_go_marketplace_test + +compile_solidity_vaulttracker_test: + @echo "compiling VaultTracker solidity source into abi and bin files" + solc -o ./test/vaulttracker --abi --bin --overwrite ./test/vaulttracker/VaultTracker.sol + +compile_go_vaulttracker_test: + @echo "compiling abi and bin files to golang" + abigen --abi ./test/vaulttracker/VaultTracker.abi --bin ./test/vaulttracker/VaultTracker.bin -pkg vaulttracker -type VaultTracker -out ./test/vaulttracker/vaulttracker.go + +compile_vaulttracker_test: compile_solidity_vaulttracker_test compile_go_vaulttracker_test + +compile_test: compile_fakes compile_tokens compile_swivel_test compile_marketplace_test compile_vaulttracker_test compile_mocks + +# Cleaning +clean_test_abi: + @echo "removing abi files from test/ dirs" + rm test/**/*.abi + +clean_test_bin: + @echo "removing bin files from test/ dirs" + rm test/**/*.bin + +clean_test_go: + @echo "removing generated go bindings from test/ dirs" + rm test/**/*.go + +clean_test: clean_test_abi clean_test_bin clean_test_go + +clean_build_sol: + @echo "removing sol files from build/ dirs" + rm build/**/*.sol + +clean_build_abi: + @echo "removing abi files from build/ dirs" + rm build/**/*.abi + +clean_build_bin: + @echo "removing bin files from build/ dirs" + rm build/**/*.bin + +clean_build_go: + @echo "removing go files from build/ dirs" + rm build/**/*.go + +clean_build: clean_build_sol clean_build_abi clean_build_bin clean_build_go + +# Copying to build +copy_zctoken_to_build: + @echo "copying ZcToken files to marketplace build" + cp test/tokens/Hash.sol build/marketplace + cp test/tokens/PErc20.sol build/marketplace + cp test/tokens/IPErc20.sol build/marketplace + cp test/tokens/Erc2612.sol build/marketplace + cp test/tokens/IErc2612.sol build/marketplace + cp test/tokens/ZcToken.sol build/marketplace + cp test/tokens/IZcToken.sol build/marketplace + +copy_vaulttracker_to_build: + @echo "copying vaulttracker files to marketplace build" + cp test/vaulttracker/VaultTracker.sol build/marketplace + +copy_marketplace_to_build: + @echo "copying marketplace files to marketplace build" + cp test/marketplace/Abstracts.sol build/marketplace + cp test/marketplace/MarketPlace.sol build/marketplace + +copy_swivel_to_build: + @echo "copying swivel files to marketplace build" + cp test/swivel/Abstracts.sol build/swivel + cp test/swivel/Hash.sol build/swivel + cp test/swivel/Sig.sol build/swivel + cp test/swivel/Swivel.sol build/swivel + +copy_to_build: copy_zctoken_to_build copy_vaulttracker_to_build copy_marketplace_to_build copy_swivel_to_build + +compile_marketplace_build: + @echo "compiling MarketPlace solidity build source into deploy ready files" + solc -o ./build/marketplace --optimize --optimize-runs=15000 --abi --bin --overwrite ./build/marketplace/MarketPlace.sol + abigen --abi ./build/marketplace/MarketPlace.abi --bin ./build/marketplace/MarketPlace.bin -pkg marketplace -type MarketPlace -out ./build/marketplace/marketplace.go + +compile_swivel_build: + @echo "compiling Swivel solidity build source into deploy ready files" + solc -o ./build/swivel --optimize --optimize-runs=15000 --abi --bin --overwrite ./build/swivel/Swivel.sol + abigen --abi ./build/swivel/Swivel.abi --bin ./build/swivel/Swivel.bin -pkg swivel -type Swivel -out ./build/swivel/swivel.go + +compile_build: compile_marketplace_build compile_swivel_build + +all: clean_test compile_test clean_build copy_to_build compile_build diff --git a/gost/README.md b/gost/README.md new file mode 100644 index 0000000..65c2e42 --- /dev/null +++ b/gost/README.md @@ -0,0 +1,83 @@ +[![Build Status](https://travis-ci.com/Swivel-Finance/gost.svg?token=mHzJQzb11WHSPwztZw8B&branch=main)](https://travis-ci.com/Swivel-Finance/gost) +##### Smart contract testing with Geth via the Golang ABIGEN +``` + _______ + /______/\ + \__::::\/ + _______ ______ ______ _________ + /______/\ /_____/\ /_____/\ /________/\ + \::::__\/__ \:::_ \ \ \::::_\/_ \__.::.__\/ ,--. + \:\ /____/\ \:\ \ \ \ \:\/___/\ \::\ \ | oo| + \:\\_ _\/ \:\ \ \ \ \_::._\:\ \::\ \ | ~~| o o o o o o o o o o + \:\_\ \ \ \:\_\ \ \ /____\:\ \::\ \ |/\/\| + \_____\/ \_____\/ \_____\/ \__\/ +``` +## Getting Started +This project contains the Swivel Smart Contracts and Libraries which have been compiled to their `abi` and `bin` components, those then transformed into +golang bindings via the Geth `abigen` tool. You can see the commands used to perform these tasks in the `Makefile`. + +Tests are located in `/pkg/*testing/`. For example, the unit tests for the Swivel.sol contract will be located in `/pkg/swiveltesting`. + +Existing tests, and any newly created, are always run via `go test [-v] ./...` from the project root. + +If you are only here to view the existing tests, and maybe pull this repo and run it you can stop here. If you are a developer writing new tests or simply +an interested party who realizes the *mind blowing* superiority of testing your smart contracts this way - read on! + +#### Notes on /build +The `/build` directory exists to house our 2 deployed contracts (and 2 deployable child contracts) with all of their dependencies and compiled artifacts. Those being not only the `.sol` files but the +`.bin`, `.abi` and `.go` files as well. These compiled artifacts will be different from what is in the `/test` directories, as those are compiled with mocks in place (these are not). + +Note that the files here should be considered "alpha" stage as what is present [here](https://github.com/Swivel-Finance/swivel/tree/main/contracts) should be considered "stable". + +### Geth +Gost only depends on Geth itself. We _do_ list `solc` as being necessary, but that isn't _exactly_ true. +If you are in possesion of the `abi` and `bin` files of any smart contract (regardless of language used) the +Makefile's `compile_*` type steps can be made for them. + +As this Golang project is done with modules, you don't need to specifically `go get` anything. All dependencies will be fetched on your first test run. + +### Solidity Compiler +First, assure that `solc` is in your $PATH. If not, [make it so](https://docs.soliditylang.org/en/v0.8.0/installing-solidity.html). As stated above, +this is assuming your smart contracts are `.sol` and you do not already have the `.abi` and `.bin` files. Add new Makefile rules for other languages +(Vyper for example) and compilers if you are so inclined. + +### Geth ABIGEN +Second, you will need `abigen` in your $PATH. You can, for example, follow the instructions [here](https://github.com/ethereum/go-ethereum). +Note that you only need to use the `devtools` rule from the go-ethereum Makefile. i.e. `make devtools` will suffice. + +### Project Structure +As always we use the [project layout](https://github.com/golang-standards/project-layout) guidelines. This interpretation places the +Solidity files into `test/` with their compiled artifacts going into aptly named subdirectories for ease of use with +golang's package conventions (see Makefile). Some notes on the important residents of `/test/`: + +* swivel/ + * Swivel.sol. The current Swivel smart contract + * Abstracts.sol. The external interfaces declared by Swivel.sol + * Sig.sol. Imbeddable library used by Swivel.sol + * Hash.sol. Imbeddable library used by Swivel.sol + * swivel.go. Autogenerated Geth bindings for use in tests. +* marketplace/ + * MarketPlace.sol The current MarketPlace smart contract + * Abstracts.sol. The external interfaces declared by MarketPlace.sol + * VaultTracker.sol. A mock implementation of the VaultTracker smart contract. Used to build and test MarketPlace in isolation + * ZcToken.sol. A mock implementation of the ZcToken smart contract. + * marketplace.go. Autogenerated Geth bindings. +* vaulttracker/ + * VaultTracker.sol. The current VaultTracker smart contract +* tokens/ + * ZcToken.sol. An Open Zeppelin clone of an extended Erc20 with mint, burn and permit. + +#### The Makefile +This is the way. + +Steps for setting-up, tearnig-down and testing the individual pieces of the repo are here. + +#### Compiling and Testing Your Contracts +* Compiling: + * `make all` + +If you wish to run the steps separately or run into any errors that need debugging, see the Makefile for the entire list of available commands. + +* Testing: + * `go test ./...` from root (as stated). Add the -v flag if you expect to see any logging you may be doing. + * You can of course test at the package level: `go test ./path/to/package` diff --git a/gost/build/.DS_Store b/gost/build/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..1daeca7f24ec1e7e2c5a482daad6902052cd57ef GIT binary patch literal 6148 zcmeHKJ5Izv4E1CK3fh7#x6Bpx24NM7?U42Yupa>;Q6j$W)SQ8 z8$yt15FlIfyotx2IB%qJOhj&awVDu(h$w+FMmrcj5ngBQNTe2CbYYJ*T~bX29nrGm zZHC{-0H58EN}Sj^ozdp`t&8Kyd|8!sNISki==UtEJYN*m0v^fpYZ+6 uint256) public override nonces; + + bytes32 public immutable domain; + + /// @param n name for the token + /// @param s symbol for the token + /// @param d decimals for the token + constructor(string memory n, string memory s, uint8 d) PErc20(n, s, d) { + domain = Hash.domain(n, '1', block.chainid, address(this)); + } + + /** + * @dev See {IERC2612-permit}. + * + * In cases where the free option is not a concern, deadline can simply be + * set to uint(-1), so it should be seen as an optional parameter + * + * @param o Address of the owner + * @param spender Address of the spender + * @param a Amount to be approved + * @param d Deadline at which the permission is no longer valid + * NOTE: Last three args (v, r, s) are the components of a valid ECDSA signature + */ + function permit(address o, address spender, uint256 a, uint256 d, uint8 v, bytes32 r, bytes32 s) public virtual override { + require(d >= block.timestamp, 'erc2612 expired deadline'); + + bytes32 hashStruct = Hash.permit(o, spender, a, nonces[o]++, d); + bytes32 hash = Hash.message(domain, hashStruct); + address signer = ecrecover(hash, v, r, s); + + require(signer != address(0) && signer == o, 'erc2612 invalid signature'); + _approve(o, spender, a); + } +} diff --git a/gost/build/marketplace/Hash.abi b/gost/build/marketplace/Hash.abi new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/gost/build/marketplace/Hash.abi @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/gost/build/marketplace/Hash.bin b/gost/build/marketplace/Hash.bin new file mode 100644 index 0000000..85f1a9d --- /dev/null +++ b/gost/build/marketplace/Hash.bin @@ -0,0 +1 @@ +60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220f52711f8cbb0320b9269fd4ea51b52c0c3c731b4c81a143bb6b1a1b943c4732d64736f6c63430008040033 \ No newline at end of file diff --git a/gost/build/marketplace/Hash.sol b/gost/build/marketplace/Hash.sol new file mode 100644 index 0000000..861dc3f --- /dev/null +++ b/gost/build/marketplace/Hash.sol @@ -0,0 +1,80 @@ +// SPDX-License-Identifier: UNLICENSED + +pragma solidity 0.8.4; + +/** + @notice Encapsulation of the logic to produce EIP712 hashed domain and messages. + Also to produce / verify hashed and signed Permits. +*/ + +library Hash { + // EIP712 Domain Separator typeHash + // keccak256(abi.encodePacked( + // 'EIP712Domain(', + // 'string name,', + // 'string version,', + // 'uint256 chainId,', + // 'address verifyingContract', + // ')' + // )); + bytes32 constant internal DOMAIN_TYPEHASH = 0x8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f; + + // EIP2612 typeHash of a Permit + // keccak256(abi.encodePacked( + // 'Permit(', + // 'address owner,', + // 'address spender,', + // 'uint256 value,', + // 'uint256 nonce,', + // 'uint256 deadline,', + // ')' + // )); + bytes32 constant internal PERMIT_TYPEHASH = 0x80772249b4aef1688b30651778f4249b05cb73b517d98482439b9d8999b30602; + + /// @param n EIP712 domain name + /// @param version EIP712 semantic version string + /// @param i Chain ID + /// @param verifier address of the verifying contract + function domain(string memory n, string memory version, uint256 i, address verifier) internal pure returns (bytes32) { + bytes32 hash; + + assembly { + let nameHash := keccak256(add(n, 32), mload(n)) + let versionHash := keccak256(add(version, 32), mload(version)) + let pointer := mload(64) + mstore(pointer, DOMAIN_TYPEHASH) + mstore(add(pointer, 32), nameHash) + mstore(add(pointer, 64), versionHash) + mstore(add(pointer, 96), i) + mstore(add(pointer, 128), verifier) + hash := keccak256(pointer, 160) + } + + return hash; + } + + /// @param d Type hash of the domain separator (see Hash.domain) + /// @param h EIP712 hash struct (Permit for example) + function message(bytes32 d, bytes32 h) internal pure returns (bytes32) { + bytes32 hash; + + assembly { + let pointer := mload(64) + mstore(pointer, 0x1901000000000000000000000000000000000000000000000000000000000000) + mstore(add(pointer, 2), d) + mstore(add(pointer, 34), h) + hash := keccak256(pointer, 66) + } + + return hash; + } + + /// @param o Address of the owner + /// @param s Address of the spender + /// @param a Amount to be approved + /// @param n Current nonce + /// @param d Deadline at which the permission is no longer valid + function permit(address o, address s, uint256 a, uint256 n, uint256 d) internal pure returns (bytes32) { + return keccak256(abi.encode(PERMIT_TYPEHASH, o, s, a, n, d)); + } +} diff --git a/gost/build/marketplace/IErc2612.abi b/gost/build/marketplace/IErc2612.abi new file mode 100644 index 0000000..5afedea --- /dev/null +++ b/gost/build/marketplace/IErc2612.abi @@ -0,0 +1 @@ +[{"inputs":[{"internalType":"address","name":"o","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"o","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"},{"internalType":"uint256","name":"d","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file diff --git a/gost/build/marketplace/IErc2612.bin b/gost/build/marketplace/IErc2612.bin new file mode 100644 index 0000000..e69de29 diff --git a/gost/build/marketplace/IErc2612.sol b/gost/build/marketplace/IErc2612.sol new file mode 100644 index 0000000..685d994 --- /dev/null +++ b/gost/build/marketplace/IErc2612.sol @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// Code adapted from OpenZeppelin IERCPermit +pragma solidity 0.8.4; + +/** + * @dev Interface of the ERC2612 standard as defined in the EIP. + * + * Adds the {permit} method, which can be used to change one's + * {IERC20-allowance} without having to send a transaction, by signing a + * message. This allows users to spend tokens without having to hold Ether. + * + * See https://eips.ethereum.org/EIPS/eip-2612. + */ +interface IErc2612 { + /** + * @dev Sets `amount` as the allowance of `spender` over `owner`'s tokens, + * given `owner`'s signed approval. + * @param o The owner + * @param spender The spender + * @param a The amount + * @param d The deadline + * @param v v portion of the ECDSA + * @param r r portion of the ECDSA + * @param s s portion of the ECDSA + * + * IMPORTANT: The same issues {IERC20-approve} has related to transaction + * ordering also apply here. + * + * Emits an {Approval} event. + * + * Requirements: + * + * - `owner` cannot be the zero address. + * - `spender` cannot be the zero address. + * - `deadline` must be a timestamp in the future. + * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` + * over the EIP712-formatted function arguments. + * - the signature must use ``owner``'s current nonce (see {nonces}). + * + * For more information on the signature format, see the + * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP + * section]. + */ + function permit(address o, address spender, uint256 a, uint256 d, uint8 v, bytes32 r, bytes32 s) external; + + /** + * @dev Returns the current ERC2612 nonce for `owner`. This value must be + * @param o The owner + * + * included whenever a signature is generated for {permit}. + * + * Every successful call to {permit} increases ``owner``'s nonce by one. This + * prevents a signature from being used multiple times. + */ + function nonces(address o) external view returns (uint256); +} diff --git a/gost/build/marketplace/IPErc20.abi b/gost/build/marketplace/IPErc20.abi new file mode 100644 index 0000000..459a18e --- /dev/null +++ b/gost/build/marketplace/IPErc20.abi @@ -0,0 +1 @@ +[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"address","name":"o","type":"address"},{"internalType":"address","name":"s","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"s","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"a","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"r","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"s","type":"address"},{"internalType":"address","name":"r","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file diff --git a/gost/build/marketplace/IPErc20.bin b/gost/build/marketplace/IPErc20.bin new file mode 100644 index 0000000..e69de29 diff --git a/gost/build/marketplace/IPErc20.sol b/gost/build/marketplace/IPErc20.sol new file mode 100644 index 0000000..8affd0c --- /dev/null +++ b/gost/build/marketplace/IPErc20.sol @@ -0,0 +1,80 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.8.4; + +/** + * @dev Interface of the ERC20 standard as defined in the EIP. + */ +interface IPErc20 { + /** + * @dev Returns the amount of tokens owned by `account`. + * @param a Adress to fetch balance of + */ + function balanceOf(address a) external view returns (uint256); + + /** + * @dev Moves `amount` tokens from the caller's account to `recipient`. + * @param r The recipient + * @param a The amount transferred + * + * Emits a {Transfer} event. + */ + function transfer(address r, uint256 a) external returns (bool); + + /** + * @dev Returns the remaining number of tokens that `spender` will be + * allowed to spend on behalf of `owner` through {transferFrom}. This is + * zero by default. + * @param o The owner + * @param s The spender + * + * This value changes when {approve} or {transferFrom} are called. + */ + function allowance(address o, address s) external view returns (uint256); + + /** + * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * IMPORTANT: Beware that changing an allowance with this method brings the risk + * that someone may use both the old and the new allowance by unfortunate + * transaction ordering. One possible solution to mitigate this race + * condition is to first reduce the spender's allowance to 0 and set the + * desired value afterwards: + * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 + * @param s The spender + * @param a The amount to approve + * + * Emits an {Approval} event. + */ + function approve(address s, uint256 a) external returns (bool); + + /** + * @dev Moves `amount` tokens from `sender` to `recipient` using the + * allowance mechanism. `amount` is then deducted from the caller's + * allowance. + * @param s The sender + * @param r The recipient + * @param a The amount to transfer + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transferFrom(address s, address r, uint256 a) external returns (bool); + + /** + * @dev Emitted when `value` tokens are moved from one account (`from`) to + * another (`to`). + * + * Note that `value` may be zero. + */ + event Transfer(address indexed from, address indexed to, uint256 value); + + /** + * @dev Emitted when the allowance of a `spender` for an `owner` is set by + * a call to {approve}. `value` is the new allowance. + */ + event Approval(address indexed owner, address indexed spender, uint256 value); +} diff --git a/gost/build/marketplace/IZcToken.abi b/gost/build/marketplace/IZcToken.abi new file mode 100644 index 0000000..b2326d1 --- /dev/null +++ b/gost/build/marketplace/IZcToken.abi @@ -0,0 +1 @@ +[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"address","name":"o","type":"address"},{"internalType":"address","name":"s","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"s","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"a","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"burn","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"mint","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"r","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"s","type":"address"},{"internalType":"address","name":"r","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file diff --git a/gost/build/marketplace/IZcToken.bin b/gost/build/marketplace/IZcToken.bin new file mode 100644 index 0000000..e69de29 diff --git a/gost/build/marketplace/IZcToken.sol b/gost/build/marketplace/IZcToken.sol new file mode 100644 index 0000000..8efbda8 --- /dev/null +++ b/gost/build/marketplace/IZcToken.sol @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.8.4; + +import "./IPErc20.sol"; + +/** + * @dev Mint and burn interface for the ZCToken + * + */ +interface IZcToken is IPErc20 { + /** + * @dev Mints... + */ + function mint(address, uint256) external returns(bool); + + /** + * @dev Burns... + */ + function burn(address, uint256) external returns(bool); +} diff --git a/gost/build/marketplace/MarketPlace.abi b/gost/build/marketplace/MarketPlace.abi new file mode 100644 index 0000000..22cc499 --- /dev/null +++ b/gost/build/marketplace/MarketPlace.abi @@ -0,0 +1 @@ +[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"underlying","type":"address"},{"indexed":true,"internalType":"uint256","name":"maturity","type":"uint256"},{"indexed":false,"internalType":"address","name":"cToken","type":"address"},{"indexed":false,"internalType":"address","name":"zcToken","type":"address"},{"indexed":false,"internalType":"address","name":"vaultTracker","type":"address"}],"name":"Create","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"underlying","type":"address"},{"indexed":true,"internalType":"uint256","name":"maturity","type":"uint256"},{"indexed":false,"internalType":"address","name":"zcTarget","type":"address"},{"indexed":false,"internalType":"address","name":"nTarget","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"CustodialExit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"underlying","type":"address"},{"indexed":true,"internalType":"uint256","name":"maturity","type":"uint256"},{"indexed":false,"internalType":"address","name":"zcTarget","type":"address"},{"indexed":false,"internalType":"address","name":"nTarget","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"CustodialInitiate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"underlying","type":"address"},{"indexed":true,"internalType":"uint256","name":"maturity","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"maturityRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"matured","type":"uint256"}],"name":"Mature","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"underlying","type":"address"},{"indexed":true,"internalType":"uint256","name":"maturity","type":"uint256"},{"indexed":false,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"P2pVaultExchange","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"underlying","type":"address"},{"indexed":true,"internalType":"uint256","name":"maturity","type":"uint256"},{"indexed":false,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"P2pZcTokenExchange","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"underlying","type":"address"},{"indexed":true,"internalType":"uint256","name":"maturity","type":"uint256"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RedeemVaultInterest","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"underlying","type":"address"},{"indexed":true,"internalType":"uint256","name":"maturity","type":"uint256"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"RedeemZcToken","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"underlying","type":"address"},{"indexed":true,"internalType":"uint256","name":"maturity","type":"uint256"},{"indexed":false,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"TransferVaultNotional","type":"event"},{"inputs":[],"name":"admin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"u","type":"address"},{"internalType":"uint256","name":"m","type":"uint256"},{"internalType":"address","name":"t","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"burnZcTokenRemovingNotional","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"a","type":"address"},{"internalType":"uint256","name":"m","type":"uint256"}],"name":"cTokenAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"u","type":"address"},{"internalType":"uint256","name":"m","type":"uint256"},{"internalType":"address","name":"c","type":"address"},{"internalType":"string","name":"n","type":"string"},{"internalType":"string","name":"s","type":"string"},{"internalType":"uint8","name":"d","type":"uint8"}],"name":"createMarket","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"u","type":"address"},{"internalType":"uint256","name":"m","type":"uint256"},{"internalType":"address","name":"z","type":"address"},{"internalType":"address","name":"n","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"custodialExit","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"u","type":"address"},{"internalType":"uint256","name":"m","type":"uint256"},{"internalType":"address","name":"z","type":"address"},{"internalType":"address","name":"n","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"custodialInitiate","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"markets","outputs":[{"internalType":"address","name":"cTokenAddr","type":"address"},{"internalType":"address","name":"zcTokenAddr","type":"address"},{"internalType":"address","name":"vaultAddr","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"mature","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"u","type":"address"},{"internalType":"uint256","name":"m","type":"uint256"}],"name":"matureMarket","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"maturityRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"u","type":"address"},{"internalType":"uint256","name":"m","type":"uint256"},{"internalType":"address","name":"t","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"mintZcTokenAddingNotional","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"u","type":"address"},{"internalType":"uint256","name":"m","type":"uint256"},{"internalType":"address","name":"f","type":"address"},{"internalType":"address","name":"t","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"p2pVaultExchange","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"u","type":"address"},{"internalType":"uint256","name":"m","type":"uint256"},{"internalType":"address","name":"f","type":"address"},{"internalType":"address","name":"t","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"p2pZcTokenExchange","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"u","type":"address"},{"internalType":"uint256","name":"m","type":"uint256"},{"internalType":"address","name":"t","type":"address"}],"name":"redeemVaultInterest","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"u","type":"address"},{"internalType":"uint256","name":"m","type":"uint256"},{"internalType":"address","name":"t","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"redeemZcToken","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"s","type":"address"}],"name":"setSwivelAddress","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"swivel","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"u","type":"address"},{"internalType":"uint256","name":"m","type":"uint256"},{"internalType":"address","name":"t","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"transferVaultNotional","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"u","type":"address"},{"internalType":"uint256","name":"m","type":"uint256"},{"internalType":"address","name":"f","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"transferVaultNotionalFee","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file diff --git a/gost/build/marketplace/MarketPlace.bin b/gost/build/marketplace/MarketPlace.bin new file mode 100644 index 0000000..f347e5a --- /dev/null +++ b/gost/build/marketplace/MarketPlace.bin @@ -0,0 +1 @@ +60a060405234801561001057600080fd5b5033606081901b608052615d4e6100406000396000818161042501528181610e470152611dfc0152615d4e6000f3fe60806040523480156200001157600080fd5b50600436106200016c5760003560e01c80638c6b9b4111620000dd578063c86adf7c116200008b578063ef267f2c116200006e578063ef267f2c1462000408578063f851a440146200041f578063f8e51bcb146200044757600080fd5b8063c86adf7c14620003c3578063e5a2aa6214620003f157600080fd5b8063b50a66f711620000c0578063b50a66f7146200037e578063bddbfbe41462000395578063c5ee114d14620003ac57600080fd5b80638c6b9b411462000341578063a11f4856146200035857600080fd5b80633cf9a4e3116200013b5780635db0ae58116200011e5780635db0ae5814620002fc57806365a963aa1462000313578063848f5184146200032a57600080fd5b80633cf9a4e314620002ce5780635292ecf214620002e557600080fd5b8063012b264a146200017157806305e1dc2514620001bc57806317b3bba7146200020057806327ee93be146200028c575b600080fd5b600354620001929073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b62000192620001cd366004620026d0565b73ffffffffffffffffffffffffffffffffffffffff91821660009081526020818152604080832093835292905220541690565b6200025462000211366004620026d0565b600060208181529281526040808220909352908152208054600182015460029092015473ffffffffffffffffffffffffffffffffffffffff918216928216911683565b6040805173ffffffffffffffffffffffffffffffffffffffff94851681529284166020840152921691810191909152606001620001b3565b620002bd6200029d366004620026d0565b600160209081526000928352604080842090915290825290205460ff1681565b6040519015158152602001620001b3565b620002bd620002df36600462002847565b6200045e565b620002bd620002f636600462002847565b620005a9565b620002bd6200030d366004620026d0565b6200072f565b620002bd620003243660046200273c565b62000b38565b620002bd6200033b36600462002797565b62000e43565b620002bd620003523660046200273c565b6200120a565b6200036f62000369366004620026fc565b62001505565b604051908152602001620001b3565b620002bd6200038f36600462002847565b6200169c565b620002bd620003a63660046200273c565b62001947565b6200036f620003bd36600462002847565b62001b31565b6200036f620003d4366004620026d0565b600260209081526000928352604080842090915290825290205481565b620002bd62000402366004620026ac565b62001df8565b620002bd6200041936600462002847565b62001ece565b620001927f000000000000000000000000000000000000000000000000000000000000000081565b620002bd620004583660046200273c565b6200216d565b60035460009073ffffffffffffffffffffffffffffffffffffffff16338114620004cf5760405162461bcd60e51b815260206004820152601e60248201527f73656e646572206d7573742062652053776976656c20636f6e7472616374000060448201526064015b60405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff868116600090815260208181526040808320898452909152908190206002015490517fb326258d00000000000000000000000000000000000000000000000000000000815286831660048201526024810186905291169063b326258d90604401602060405180830381600087803b1580156200055f57600080fd5b505af115801562000574573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200059a91906200288f565b50600191505b50949350505050565b73ffffffffffffffffffffffffffffffffffffffff8481166000908152602081815260408083208784529091528082206002015490517f1779467300000000000000000000000000000000000000000000000000000000815233600482015285841660248201526044810185905291921690631779467390606401602060405180830381600087803b1580156200063f57600080fd5b505af115801562000654573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200067a91906200288f565b620006c85760405162461bcd60e51b815260206004820152601560248201527f7661756c74207472616e73666572206661696c656400000000000000000000006044820152606401620004c6565b6040805133815273ffffffffffffffffffffffffffffffffffffffff858116602083015291810184905285918716907f1d06fe04c445804d7b460d2d5f2fee7c4cc5ba874f3311d2768f849c66cf30989060600160405180910390a3506001949350505050565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260016020908152604080832084845290915281205460ff1615620007b25760405162461bcd60e51b815260206004820152601660248201527f6d61726b657420616c7265616479206d617475726564000000000000000000006044820152606401620004c6565b73ffffffffffffffffffffffffffffffffffffffff8084166000908152602081815260408083208684528252918290206001015482517f204f83f9000000000000000000000000000000000000000000000000000000008152925193169263204f83f9926004808201939291829003018186803b1580156200083357600080fd5b505afa15801562000848573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200086e9190620028b1565b421015620008bf5760405162461bcd60e51b815260206004820152601460248201527f6d61747572697479206e6f7420726561636865640000000000000000000000006044820152606401620004c6565b73ffffffffffffffffffffffffffffffffffffffff80841660009081526020818152604080832086845282528083205481517fbd6d894d00000000000000000000000000000000000000000000000000000000815291519394169263bd6d894d9260048084019391929182900301818787803b1580156200093f57600080fd5b505af115801562000954573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200097a9190620028b1565b73ffffffffffffffffffffffffffffffffffffffff80861660008181526002602081815260408084208a8552825280842087905584845260018083528185208b8652835281852080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016909117905593835282815283832089845281528383209091015483517f6b868d51000000000000000000000000000000000000000000000000000000008152935195965090931693636b868d51936004808501949193918390030190829087803b15801562000a5357600080fd5b505af115801562000a68573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000a8e91906200288f565b62000adc5760405162461bcd60e51b815260206004820152601460248201527f6d61747572697479206e6f7420726561636865640000000000000000000000006044820152606401620004c6565b6040805142815260208101839052849173ffffffffffffffffffffffffffffffffffffffff8716917e80e09d7b4544aa5a923873be1df3e31945593d40cb1c874d99259ec3ac43a4910160405180910390a35060019392505050565b60035460009073ffffffffffffffffffffffffffffffffffffffff1633811462000ba55760405162461bcd60e51b815260206004820152601e60248201527f73656e646572206d7573742062652053776976656c20636f6e747261637400006044820152606401620004c6565b73ffffffffffffffffffffffffffffffffffffffff8781166000908152602081815260408083208a8452909152908190206001015490517f9dc29fac000000000000000000000000000000000000000000000000000000008152878316600482015260248101869052911690639dc29fac90604401602060405180830381600087803b15801562000c3557600080fd5b505af115801562000c4a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000c7091906200288f565b62000cbe5760405162461bcd60e51b815260206004820152601360248201527f7a63546f6b656e206275726e206661696c6564000000000000000000000000006044820152606401620004c6565b73ffffffffffffffffffffffffffffffffffffffff8781166000908152602081815260408083208a8452909152908190206001015490517f40c10f190000000000000000000000000000000000000000000000000000000081528683166004820152602481018690529116906340c10f1990604401602060405180830381600087803b15801562000d4e57600080fd5b505af115801562000d63573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000d8991906200288f565b62000dd75760405162461bcd60e51b815260206004820152601360248201527f7a63546f6b656e206d696e74206661696c6564000000000000000000000000006044820152606401620004c6565b6040805173ffffffffffffffffffffffffffffffffffffffff8781168252868116602083015291810185905287918916907f86ac24e4ee753e21fb51afa847265cb350e500593f3204057e40079c3ef54422906060015b60405180910390a35060019695505050505050565b60007f00000000000000000000000000000000000000000000000000000000000000003373ffffffffffffffffffffffffffffffffffffffff82161462000ecd5760405162461bcd60e51b815260206004820152601460248201527f73656e646572206d7573742062652061646d696e0000000000000000000000006044820152606401620004c6565b60035473ffffffffffffffffffffffffffffffffffffffff1662000f345760405162461bcd60e51b815260206004820152601f60248201527f73776976656c20636f6e74726163742061646472657373206e6f7420736574006044820152606401620004c6565b6000888887878760405162000f4990620025b9565b62000f5995949392919062002936565b604051809103906000f08015801562000f76573d6000803e3d6000fd5b50905060008888600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1660405162000fae90620025c7565b92835273ffffffffffffffffffffffffffffffffffffffff9182166020840152166040820152606001604051809103906000f08015801562000ff4573d6000803e3d6000fd5b50905060405180606001604052808973ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1681526020018273ffffffffffffffffffffffffffffffffffffffff168152506000808c73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008b815260200190815260200160002060008201518160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060208201518160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550905050888a73ffffffffffffffffffffffffffffffffffffffff167f1747a3ed83b35b999b9000df0690f6563f6b016a1cce0c8dfc911866d3b921778a8585604051620011f29392919073ffffffffffffffffffffffffffffffffffffffff93841681529183166020830152909116604082015260600190565b60405180910390a35060019998505050505050505050565b60035460009073ffffffffffffffffffffffffffffffffffffffff16338114620012775760405162461bcd60e51b815260206004820152601e60248201527f73656e646572206d7573742062652053776976656c20636f6e747261637400006044820152606401620004c6565b73ffffffffffffffffffffffffffffffffffffffff8781166000908152602081815260408083208a8452909152908190206001015490517f9dc29fac000000000000000000000000000000000000000000000000000000008152878316600482015260248101869052911690639dc29fac90604401602060405180830381600087803b1580156200130757600080fd5b505af11580156200131c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200134291906200288f565b620013905760405162461bcd60e51b815260206004820152600b60248201527f6275726e206661696c65640000000000000000000000000000000000000000006044820152606401620004c6565b73ffffffffffffffffffffffffffffffffffffffff8781166000908152602081815260408083208a8452909152908190206002015490517f613a28d100000000000000000000000000000000000000000000000000000000815286831660048201526024810186905291169063613a28d190604401602060405180830381600087803b1580156200142057600080fd5b505af115801562001435573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200145b91906200288f565b620014a95760405162461bcd60e51b815260206004820152601660248201527f72656d6f7665206e6f74696f6e616c206661696c6564000000000000000000006044820152606401620004c6565b6040805173ffffffffffffffffffffffffffffffffffffffff8781168252868116602083015291810185905287918916907f219a55ae9a5a1822159d55db6dd594a28be30b02c0d18a71469ef28030b3fb599060600162000e2e565b60035460009073ffffffffffffffffffffffffffffffffffffffff16338114620015725760405162461bcd60e51b815260206004820152601e60248201527f73656e646572206d7573742062652053776976656c20636f6e747261637400006044820152606401620004c6565b73ffffffffffffffffffffffffffffffffffffffff8581166000908152602081815260408083208884529091528082206002015490517f19caf46c0000000000000000000000000000000000000000000000000000000081528684166004820152919216906319caf46c90602401602060405180830381600087803b158015620015fb57600080fd5b505af115801562001610573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620016369190620028b1565b90508373ffffffffffffffffffffffffffffffffffffffff16858773ffffffffffffffffffffffffffffffffffffffff167f646390328280b54978a07e7bd72dd9b3f9515286196024882943a96d5c27987460405160405180910390a495945050505050565b60035460009073ffffffffffffffffffffffffffffffffffffffff16338114620017095760405162461bcd60e51b815260206004820152601e60248201527f73656e646572206d7573742062652053776976656c20636f6e747261637400006044820152606401620004c6565b73ffffffffffffffffffffffffffffffffffffffff868116600090815260208181526040808320898452909152908190206001015490517f9dc29fac000000000000000000000000000000000000000000000000000000008152868316600482015260248101869052911690639dc29fac90604401602060405180830381600087803b1580156200179957600080fd5b505af1158015620017ae573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620017d491906200288f565b620018225760405162461bcd60e51b815260206004820152600b60248201527f6275726e206661696c65640000000000000000000000000000000000000000006044820152606401620004c6565b73ffffffffffffffffffffffffffffffffffffffff868116600090815260208181526040808320898452909152908190206002015490517f613a28d100000000000000000000000000000000000000000000000000000000815286831660048201526024810186905291169063613a28d190604401602060405180830381600087803b158015620018b257600080fd5b505af1158015620018c7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620018ed91906200288f565b6200193b5760405162461bcd60e51b815260206004820152601660248201527f72656d6f7665206e6f74696f6e616c206661696c6564000000000000000000006044820152606401620004c6565b50600195945050505050565b60035460009073ffffffffffffffffffffffffffffffffffffffff16338114620019b45760405162461bcd60e51b815260206004820152601e60248201527f73656e646572206d7573742062652053776976656c20636f6e747261637400006044820152606401620004c6565b73ffffffffffffffffffffffffffffffffffffffff8781166000908152602081815260408083208a8452909152908190206002015490517f177946730000000000000000000000000000000000000000000000000000000081528783166004820152868316602482015260448101869052911690631779467390606401602060405180830381600087803b15801562001a4c57600080fd5b505af115801562001a61573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001a8791906200288f565b62001ad55760405162461bcd60e51b815260206004820152601860248201527f7472616e73666572206e6f74696f6e616c206661696c656400000000000000006044820152606401620004c6565b6040805173ffffffffffffffffffffffffffffffffffffffff8781168252868116602083015291810185905287918916907f31d266c2b6075063717026bd27ba8bb527366457893dc211091b2e1d9713f1529060600162000e2e565b60035460009073ffffffffffffffffffffffffffffffffffffffff1633811462001b9e5760405162461bcd60e51b815260206004820152601e60248201527f73656e646572206d7573742062652053776976656c20636f6e747261637400006044820152606401620004c6565b73ffffffffffffffffffffffffffffffffffffffff8087166000818152602081815260408083208a845282528083208151606081018352815487168152600180830154881682860152600290920154909616868301529383529281528282208983529052205460ff168062001c675762001c1988886200072f565b62001c675760405162461bcd60e51b815260206004820152601b60248201527f6661696c656420746f206d617475726520746865206d61726b657400000000006044820152606401620004c6565b60208201516040517f9dc29fac00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff88811660048301526024820188905290911690639dc29fac90604401602060405180830381600087803b15801562001cde57600080fd5b505af115801562001cf3573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001d1991906200288f565b62001d675760405162461bcd60e51b815260206004820152600e60248201527f636f756c64206e6f74206275726e0000000000000000000000000000000000006044820152606401620004c6565b8573ffffffffffffffffffffffffffffffffffffffff16878973ffffffffffffffffffffffffffffffffffffffff167f49dc20daa9f95793b82245100affbf87ad23d1761bdef94975542564f4023e458860405162001dc891815260200190565b60405180910390a48062001de1578493505050620005a0565b62001dee88888762002468565b93505050620005a0565b60007f00000000000000000000000000000000000000000000000000000000000000003373ffffffffffffffffffffffffffffffffffffffff82161462001e825760405162461bcd60e51b815260206004820152601460248201527f73656e646572206d7573742062652061646d696e0000000000000000000000006044820152606401620004c6565b6003805473ffffffffffffffffffffffffffffffffffffffff85167fffffffffffffffffffffffff00000000000000000000000000000000000000009091161790556001915050919050565b60035460009073ffffffffffffffffffffffffffffffffffffffff1633811462001f3b5760405162461bcd60e51b815260206004820152601e60248201527f73656e646572206d7573742062652053776976656c20636f6e747261637400006044820152606401620004c6565b73ffffffffffffffffffffffffffffffffffffffff868116600090815260208181526040808320898452909152908190206001015490517f40c10f190000000000000000000000000000000000000000000000000000000081528683166004820152602481018690529116906340c10f1990604401602060405180830381600087803b15801562001fcb57600080fd5b505af115801562001fe0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200200691906200288f565b620020545760405162461bcd60e51b815260206004820152601360248201527f6d696e74207a63546f6b656e206661696c6564000000000000000000000000006044820152606401620004c6565b73ffffffffffffffffffffffffffffffffffffffff868116600090815260208181526040808320898452909152908190206002015490517fa01cfffb00000000000000000000000000000000000000000000000000000000815286831660048201526024810186905291169063a01cfffb90604401602060405180830381600087803b158015620020e457600080fd5b505af1158015620020f9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200211f91906200288f565b6200193b5760405162461bcd60e51b815260206004820152601360248201527f616464206e6f74696f6e616c206661696c6564000000000000000000000000006044820152606401620004c6565b60035460009073ffffffffffffffffffffffffffffffffffffffff16338114620021da5760405162461bcd60e51b815260206004820152601e60248201527f73656e646572206d7573742062652053776976656c20636f6e747261637400006044820152606401620004c6565b73ffffffffffffffffffffffffffffffffffffffff8781166000908152602081815260408083208a8452909152908190206001015490517f40c10f190000000000000000000000000000000000000000000000000000000081528783166004820152602481018690529116906340c10f1990604401602060405180830381600087803b1580156200226a57600080fd5b505af11580156200227f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620022a591906200288f565b620022f35760405162461bcd60e51b815260206004820152600b60248201527f6d696e74206661696c65640000000000000000000000000000000000000000006044820152606401620004c6565b73ffffffffffffffffffffffffffffffffffffffff8781166000908152602081815260408083208a8452909152908190206002015490517fa01cfffb00000000000000000000000000000000000000000000000000000000815286831660048201526024810186905291169063a01cfffb90604401602060405180830381600087803b1580156200238357600080fd5b505af115801562002398573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620023be91906200288f565b6200240c5760405162461bcd60e51b815260206004820152601360248201527f616464206e6f74696f6e616c206661696c6564000000000000000000000000006044820152606401620004c6565b6040805173ffffffffffffffffffffffffffffffffffffffff8781168252868116602083015291810185905287918916907f8dad4d03bd4209aa6dc2bea238510998bf39bb034bc9c20d52f0bd241fc0c5169060600162000e2e565b73ffffffffffffffffffffffffffffffffffffffff808416600081815260026020908152604080832087845282528083205493835282825280832087845282528083205481517fbd6d894d0000000000000000000000000000000000000000000000000000000081529151939586956a52b7d2dcc80cd2e4000000959094929091169263bd6d894d92600480830193919282900301818987803b1580156200250f57600080fd5b505af115801562002524573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200254a9190620028b1565b62002561906a52b7d2dcc80cd2e4000000620029ec565b6200256d9190620029b2565b62002579919062002a2c565b905060006a52b7d2dcc80cd2e4000000620025958584620029ec565b620025a19190620029b2565b9050620025af818562002997565b9695505050505050565b6119328062002aa583390190565b61194280620043d783390190565b803573ffffffffffffffffffffffffffffffffffffffff81168114620025fa57600080fd5b919050565b600082601f83011262002610578081fd5b813567ffffffffffffffff808211156200262e576200262e62002a75565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190828211818310171562002677576200267762002a75565b8160405283815286602085880101111562002690578485fd5b8360208701602083013792830160200193909352509392505050565b600060208284031215620026be578081fd5b620026c982620025d5565b9392505050565b60008060408385031215620026e3578081fd5b620026ee83620025d5565b946020939093013593505050565b60008060006060848603121562002711578081fd5b6200271c84620025d5565b9250602084013591506200273360408501620025d5565b90509250925092565b600080600080600060a0868803121562002754578081fd5b6200275f86620025d5565b9450602086013593506200277660408701620025d5565b92506200278660608701620025d5565b949793965091946080013592915050565b60008060008060008060c08789031215620027b0578081fd5b620027bb87620025d5565b955060208701359450620027d260408801620025d5565b9350606087013567ffffffffffffffff80821115620027ef578283fd5b620027fd8a838b01620025ff565b9450608089013591508082111562002813578283fd5b506200282289828a01620025ff565b92505060a087013560ff8116811462002839578182fd5b809150509295509295509295565b600080600080608085870312156200285d578384fd5b6200286885620025d5565b9350602085013592506200287f60408601620025d5565b9396929550929360600135925050565b600060208284031215620028a1578081fd5b81518015158114620026c9578182fd5b600060208284031215620028c3578081fd5b5051919050565b60008151808452815b81811015620028f157602081850181015186830182015201620028d3565b81811115620029035782602083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b73ffffffffffffffffffffffffffffffffffffffff8616815284602082015260a0604082015260006200296d60a0830186620028ca565b8281036060840152620029818186620028ca565b91505060ff831660808301529695505050505050565b60008219821115620029ad57620029ad62002a46565b500190565b600082620029e7577f4e487b710000000000000000000000000000000000000000000000000000000081526012600452602481fd5b500490565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048311821515161562002a275762002a2762002a46565b500290565b60008282101562002a415762002a4162002a46565b500390565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fdfe6101006040523480156200001257600080fd5b506040516200193238038062001932833981016040819052620000359162000296565b8282828282828260049080519060200190620000539291906200013d565b508151620000699060059060208501906200013d565b5080600260006101000a81548160ff021916908360ff160217905550505050620000ba83604051806040016040528060018152602001603160f81b8152504630620000e660201b62000ab61760201c565b60805250505033606090811b60a0529490941b6001600160601b03191660c052505060e0525062000394565b8351602094850120835193850193909320604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f815295860194909452928401929092526060830152608082015260a0902090565b8280546200014b9062000341565b90600052602060002090601f0160209004810192826200016f5760008555620001ba565b82601f106200018a57805160ff1916838001178555620001ba565b82800160010185558215620001ba579182015b82811115620001ba5782518255916020019190600101906200019d565b50620001c8929150620001cc565b5090565b5b80821115620001c85760008155600101620001cd565b600082601f830112620001f4578081fd5b81516001600160401b03808211156200021157620002116200037e565b604051601f8301601f19908116603f011681019082821181831017156200023c576200023c6200037e565b8160405283815260209250868385880101111562000258578485fd5b8491505b838210156200027b57858201830151818301840152908201906200025c565b838211156200028c57848385830101525b9695505050505050565b600080600080600060a08688031215620002ae578081fd5b85516001600160a01b0381168114620002c5578182fd5b6020870151604088015191965094506001600160401b0380821115620002e9578283fd5b620002f789838a01620001e3565b945060608801519150808211156200030d578283fd5b506200031c88828901620001e3565b925050608086015160ff8116811462000333578182fd5b809150509295509295909350565b600181811c908216806200035657607f821691505b602082108114156200037857634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052604160045260246000fd5b60805160a05160601c60c05160601c60e051611549620003e960003960006101b30152600061023201526000818161039701528181610597015261065a015260008181610315015261093101526115496000f3fe608060405234801561001057600080fd5b50600436106101515760003560e01c806370a08231116100cd578063a9059cbb11610081578063d505accf11610066578063d505accf14610337578063dd62ed3e1461034c578063f851a4401461039257600080fd5b8063a9059cbb146102fd578063c2fb26a61461031057600080fd5b806395d89b41116100b257806395d89b41146102cf5780639dc29fac146102d7578063a457c2d7146102ea57600080fd5b806370a08231146102795780637ecebe00146102af57600080fd5b806323b872dd116101245780633950935111610109578063395093511461020757806340c10f191461021a5780636f307dc31461022d57600080fd5b806323b872dd146101d5578063313ce567146101e857600080fd5b806306fdde0314610156578063095ea7b31461017457806318160ddd14610197578063204f83f9146101ae575b600080fd5b61015e6103b9565b60405161016b91906113b7565b60405180910390f35b61018761018236600461138e565b610447565b604051901515815260200161016b565b6101a060035481565b60405190815260200161016b565b6101a07f000000000000000000000000000000000000000000000000000000000000000081565b6101876101e33660046112e2565b61045d565b6002546101f59060ff1681565b60405160ff909116815260200161016b565b61018761021536600461138e565b61054f565b61018761022836600461138e565b610593565b6102547f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161016b565b6101a061028736600461128f565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020819052604090205490565b6101a06102bd36600461128f565b60066020526000908152604090205481565b61015e610649565b6101876102e536600461138e565b610656565b6101876102f836600461138e565b610702565b61018761030b36600461138e565b6107d1565b6101a07f000000000000000000000000000000000000000000000000000000000000000081565b61034a61034536600461131d565b6107de565b005b6101a061035a3660046112b0565b73ffffffffffffffffffffffffffffffffffffffff918216600090815260016020908152604080832093909416825291909152205490565b6102547f000000000000000000000000000000000000000000000000000000000000000081565b600480546103c690611457565b80601f01602080910402602001604051908101604052809291908181526020018280546103f290611457565b801561043f5780601f106104145761010080835404028352916020019161043f565b820191906000526020600020905b81548152906001019060200180831161042257829003601f168201915b505050505081565b6000610454338484610b0d565b50600192915050565b600061046a848484610cc2565b73ffffffffffffffffffffffffffffffffffffffff8416600090815260016020908152604080832033845290915290205482811015610530576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602760248201527f6572633230207472616e7366657220616d6f756e74206578636565647320616c60448201527f6c6f77616e63650000000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b610544853361053f8685611440565b610b0d565b506001949350505050565b33600081815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff87168452909152812054909161045491859061053f908690611428565b60007f00000000000000000000000000000000000000000000000000000000000000003373ffffffffffffffffffffffffffffffffffffffff821614610635576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f73656e646572206d7573742062652061646d696e0000000000000000000000006044820152606401610527565b61063f8484610f7e565b5060019392505050565b600580546103c690611457565b60007f00000000000000000000000000000000000000000000000000000000000000003373ffffffffffffffffffffffffffffffffffffffff8216146106f8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f73656e646572206d7573742062652061646d696e0000000000000000000000006044820152606401610527565b61063f848461109e565b33600090815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff86168452909152812054828110156107c2576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f65726332302064656372656173656420616c6c6f77616e63652062656c6f772060448201527f7a65726f000000000000000000000000000000000000000000000000000000006064820152608401610527565b61063f338561053f8685611440565b6000610454338484610cc2565b42841015610848576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f65726332363132206578706972656420646561646c696e6500000000000000006044820152606401610527565b73ffffffffffffffffffffffffffffffffffffffff871660009081526006602052604081208054610909918a918a918a919086610884836114ab565b90915550604080517f80772249b4aef1688b30651778f4249b05cb73b517d98482439b9d8999b3060260208083019190915273ffffffffffffffffffffffffffffffffffffffff96871682840152949095166060860152608085019290925260a084015260c08084018a90528151808503909101815260e09093019052815191012090565b6040517f190100000000000000000000000000000000000000000000000000000000000081527f0000000000000000000000000000000000000000000000000000000000000000600282015260228101829052604290209091506000906040805160008082526020820180845284905260ff89169282019290925260608101879052608081018690529192509060019060a0016020604051602081039080840390855afa1580156109be573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff811615801590610a3957508973ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16145b610a9f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f6572633236313220696e76616c6964207369676e6174757265000000000000006044820152606401610527565b610aaa8a8a8a610b0d565b50505050505050505050565b8351602094850120835193850193909320604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f815295860194909452928401929092526060830152608082015260a0902090565b73ffffffffffffffffffffffffffffffffffffffff8316610bb0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f657263323020617070726f76652066726f6d20746865207a65726f206164647260448201527f65737300000000000000000000000000000000000000000000000000000000006064820152608401610527565b73ffffffffffffffffffffffffffffffffffffffff8216610c53576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f657263323020617070726f766520746f20746865207a65726f2061646472657360448201527f73000000000000000000000000000000000000000000000000000000000000006064820152608401610527565b73ffffffffffffffffffffffffffffffffffffffff83811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591015b60405180910390a3505050565b73ffffffffffffffffffffffffffffffffffffffff8316610d64576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f6572633230207472616e736665722066726f6d20746865207a65726f2061646460448201527f72657373000000000000000000000000000000000000000000000000000000006064820152608401610527565b73ffffffffffffffffffffffffffffffffffffffff8216610e07576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f6572633230207472616e7366657220746f20746865207a65726f20616464726560448201527f73730000000000000000000000000000000000000000000000000000000000006064820152608401610527565b73ffffffffffffffffffffffffffffffffffffffff831660009081526020819052604090205481811015610ebd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f6572633230207472616e7366657220616d6f756e74206578636565647320626160448201527f6c616e63650000000000000000000000000000000000000000000000000000006064820152608401610527565b610ec78282611440565b73ffffffffffffffffffffffffffffffffffffffff8086166000908152602081905260408082209390935590851681529081208054849290610f0a908490611428565b925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84604051610f7091815260200190565b60405180910390a350505050565b73ffffffffffffffffffffffffffffffffffffffff8216610ffb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f6572633230206d696e7420746f20746865207a65726f206164647265737300006044820152606401610527565b806003600082825461100d9190611428565b909155505073ffffffffffffffffffffffffffffffffffffffff821660009081526020819052604081208054839290611047908490611428565b909155505060405181815273ffffffffffffffffffffffffffffffffffffffff8316906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a35050565b73ffffffffffffffffffffffffffffffffffffffff821661111b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f6572633230206275726e2066726f6d20746865207a65726f20616464726573736044820152606401610527565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260208190526040902054818110156111d1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f6572633230206275726e20616d6f756e7420657863656564732062616c616e6360448201527f65000000000000000000000000000000000000000000000000000000000000006064820152608401610527565b6111db8282611440565b73ffffffffffffffffffffffffffffffffffffffff841660009081526020819052604081209190915560038054849290611216908490611440565b909155505060405182815260009073ffffffffffffffffffffffffffffffffffffffff8516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90602001610cb5565b803573ffffffffffffffffffffffffffffffffffffffff8116811461128a57600080fd5b919050565b6000602082840312156112a0578081fd5b6112a982611266565b9392505050565b600080604083850312156112c2578081fd5b6112cb83611266565b91506112d960208401611266565b90509250929050565b6000806000606084860312156112f6578081fd5b6112ff84611266565b925061130d60208501611266565b9150604084013590509250925092565b600080600080600080600060e0888a031215611337578283fd5b61134088611266565b965061134e60208901611266565b95506040880135945060608801359350608088013560ff81168114611371578384fd5b9699959850939692959460a0840135945060c09093013592915050565b600080604083850312156113a0578182fd5b6113a983611266565b946020939093013593505050565b6000602080835283518082850152825b818110156113e3578581018301518582016040015282016113c7565b818111156113f45783604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016929092016040019392505050565b6000821982111561143b5761143b6114e4565b500190565b600082821015611452576114526114e4565b500390565b600181811c9082168061146b57607f821691505b602082108114156114a5577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8214156114dd576114dd6114e4565b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fdfea2646970667358221220d800b92df8c6048dd793473ca8313793ca1656ca285d3b8deb63563c217aa06564736f6c634300080400336101006040523480156200001257600080fd5b50604051620019423803806200194283398101604081905262000035916200007f565b33606090811b60805260e0939093526001600160601b031991831b821660a05290911b1660c052620000bf565b80516001600160a01b03811681146200007a57600080fd5b919050565b60008060006060848603121562000094578283fd5b83519250620000a66020850162000062565b9150620000b66040850162000062565b90509250925092565b60805160601c60a05160601c60c05160601c60e0516117d86200016a600039600081816101920152610e4e01526000818160f40152818161138001526115950152600081816102a40152818161047c0152818161089701528181610b7801528181610f400152818161107101526113e90152600081816102cb015281816102f10152818161077f01528181610a1d01528181610d4101528181610fcf015261129801526117d86000f3fe608060405234801561001057600080fd5b50600436106100ea5760003560e01c80636392a51f1161008c578063a622ee7c11610066578063a622ee7c14610242578063b326258d1461028c578063b7dd34831461029f578063f851a440146102c657600080fd5b80636392a51f146101d45780636b868d5114610227578063a01cfffb1461022f57600080fd5b806319caf46c116100c857806319caf46c1461017a578063204f83f91461018d578063454c87b3146101b4578063613a28d1146101c157600080fd5b8063012b264a146100ef57806311554c43146101405780631779467314610157575b600080fd5b6101167f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b61014960025481565b604051908152602001610137565b61016a610165366004611652565b6102ed565b6040519015158152602001610137565b610149610188366004611631565b61077b565b6101497f000000000000000000000000000000000000000000000000000000000000000081565b60015461016a9060ff1681565b61016a6101cf36600461168d565b610a19565b6102126101e2366004611631565b73ffffffffffffffffffffffffffffffffffffffff16600090815260208190526040902080546001909101549091565b60408051928352602083019190915201610137565b61016a610d3d565b61016a61023d36600461168d565b610fcb565b610271610250366004611631565b60006020819052908152604090208054600182015460029092015490919083565b60408051938452602084019290925290820152606001610137565b61016a61029a36600461168d565b611294565b6101167f000000000000000000000000000000000000000000000000000000000000000081565b6101167f000000000000000000000000000000000000000000000000000000000000000081565b60007f00000000000000000000000000000000000000000000000000000000000000003373ffffffffffffffffffffffffffffffffffffffff821614610394576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f73656e646572206d7573742062652061646d696e00000000000000000000000060448201526064015b60405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff808616600090815260208181526040808320815160608082018452825482526001808401548387015260029384015483860152968b16865285855294839020835195860184528054865295860154938501939093529390930154928201929092528151851115610475576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f616d6f756e74206578636565647320617661696c61626c652062616c616e6365604482015260640161038b565b60008060007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663bd6d894d6040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156104e257600080fd5b505af11580156104f6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061051a91906116b6565b60015490915060ff161561056d576a52b7d2dcc80cd2e400000085604001516002546a52b7d2dcc80cd2e4000000610552919061171f565b61055c91906116e6565b610566919061175c565b92506105a0565b60408501516a52b7d2dcc80cd2e400000090610589838361171f565b61059391906116e6565b61059d919061175c565b92505b84516a52b7d2dcc80cd2e4000000906105b9908561171f565b6105c391906116e6565b915081856020018181516105d791906116ce565b9052508451889086906105eb90839061175c565b905250604080860182815273ffffffffffffffffffffffffffffffffffffffff8c166000908152602081815292902087518155918701516001830155516002909101558351156107105760015460009060ff1615610688576a52b7d2dcc80cd2e400000085604001516002546a52b7d2dcc80cd2e400000061066d919061171f565b61067791906116e6565b610681919061175c565b93506106bb565b60408501516a52b7d2dcc80cd2e4000000906106a4848361171f565b6106ae91906116e6565b6106b8919061175c565b93505b84516a52b7d2dcc80cd2e4000000906106d4908661171f565b6106de91906116e6565b905080856020018181516106f291906116ce565b9052508451899086906107069083906116ce565b9052506107269050565b878460000181815161072291906116ce565b9052505b604080850191825273ffffffffffffffffffffffffffffffffffffffff8a1660009081526020818152919020855181559401516001808601919091559051600290940193909355509093505050509392505050565b60007f00000000000000000000000000000000000000000000000000000000000000003373ffffffffffffffffffffffffffffffffffffffff82161461081d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f73656e646572206d7573742062652061646d696e000000000000000000000000604482015260640161038b565b73ffffffffffffffffffffffffffffffffffffffff80841660009081526020818152604080832081516060810183528154815260018201548185018190526002909201548184015282517fbd6d894d00000000000000000000000000000000000000000000000000000000815292519095919493849384937f0000000000000000000000000000000000000000000000000000000000000000169263bd6d894d9260048084019391929182900301818787803b1580156108dc57600080fd5b505af11580156108f0573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061091491906116b6565b60015490915060ff1615610967576a52b7d2dcc80cd2e400000085604001516002546a52b7d2dcc80cd2e400000061094c919061171f565b61095691906116e6565b610960919061175c565b925061099a565b60408501516a52b7d2dcc80cd2e400000090610983838361171f565b61098d91906116e6565b610997919061175c565b92505b84516a52b7d2dcc80cd2e4000000906109b3908561171f565b6109bd91906116e6565b604080870183815260006020808a0182815273ffffffffffffffffffffffffffffffffffffffff8e168352908290529290208851815591516001830155516002909101559150610a0d82856116ce565b98975050505050505050565b60007f00000000000000000000000000000000000000000000000000000000000000003373ffffffffffffffffffffffffffffffffffffffff821614610abb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f73656e646572206d7573742062652061646d696e000000000000000000000000604482015260640161038b565b73ffffffffffffffffffffffffffffffffffffffff8416600090815260208181526040918290208251606081018452815480825260018301549382019390935260029091015492810192909252841115610b71576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f616d6f756e742065786365656473207661756c742062616c616e636500000000604482015260640161038b565b60008060007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663bd6d894d6040518163ffffffff1660e01b8152600401602060405180830381600087803b158015610bde57600080fd5b505af1158015610bf2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c1691906116b6565b60015490915060ff1615610c69576a52b7d2dcc80cd2e400000084604001516002546a52b7d2dcc80cd2e4000000610c4e919061171f565b610c5891906116e6565b610c62919061175c565b9250610c9c565b60408401516a52b7d2dcc80cd2e400000090610c85838361171f565b610c8f91906116e6565b610c99919061175c565b92505b83516a52b7d2dcc80cd2e400000090610cb5908561171f565b610cbf91906116e6565b91508184602001818151610cd391906116ce565b905250835187908590610ce790839061175c565b905250604080850191825273ffffffffffffffffffffffffffffffffffffffff89166000908152602081815291902085518155940151600180860191909155905160029094019390935550909250505092915050565b60007f00000000000000000000000000000000000000000000000000000000000000003373ffffffffffffffffffffffffffffffffffffffff821614610ddf576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f73656e646572206d7573742062652061646d696e000000000000000000000000604482015260640161038b565b60015460ff1615610e4c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f616c7265616479206d6174757265640000000000000000000000000000000000604482015260640161038b565b7f0000000000000000000000000000000000000000000000000000000000000000421015610ed6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f6d6174757269747920686173206e6f74206265656e2072656163686564000000604482015260640161038b565b600180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001681179055604080517fbd6d894d000000000000000000000000000000000000000000000000000000008152905173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169163bd6d894d9160048083019260209291908290030181600087803b158015610f8857600080fd5b505af1158015610f9c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fc091906116b6565b600255600191505090565b60007f00000000000000000000000000000000000000000000000000000000000000003373ffffffffffffffffffffffffffffffffffffffff82161461106d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f73656e646572206d7573742062652061646d696e000000000000000000000000604482015260640161038b565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663bd6d894d6040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156110d757600080fd5b505af11580156110eb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061110f91906116b6565b73ffffffffffffffffffffffffffffffffffffffff8616600090815260208181526040918290208251606081018452815480825260018301549382019390935260029091015492810192909252919250901561124357600154600090819060ff16156111ba576a52b7d2dcc80cd2e400000083604001516002546a52b7d2dcc80cd2e400000061119f919061171f565b6111a991906116e6565b6111b3919061175c565b91506111ed565b60408301516a52b7d2dcc80cd2e4000000906111d6868361171f565b6111e091906116e6565b6111ea919061175c565b91505b82516a52b7d2dcc80cd2e400000090611206908461171f565b61121091906116e6565b9050808360200181815161122491906116ce565b9052508251879084906112389083906116ce565b905250611247915050565b8481525b604080820192835273ffffffffffffffffffffffffffffffffffffffff87166000908152602081815291902082518155910151600180830191909155915160029091015591505092915050565b60007f00000000000000000000000000000000000000000000000000000000000000003373ffffffffffffffffffffffffffffffffffffffff821614611336576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f73656e646572206d7573742062652061646d696e000000000000000000000000604482015260640161038b565b73ffffffffffffffffffffffffffffffffffffffff8085166000908152602081815260408083208151606080820184528254825260018084015483870152600293840154838601527f0000000000000000000000000000000000000000000000000000000000000000909716865285855294839020835195860184528054865295860154938501939093529390930154928201929092528151859083906113de90839061175c565b9150818152505060007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663bd6d894d6040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561144f57600080fd5b505af1158015611463573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061148791906116b6565b9050600080828460400151146115675760408401511561155f5760015460ff16156114f1576a52b7d2dcc80cd2e400000084604001516002546a52b7d2dcc80cd2e40000006114d6919061171f565b6114e091906116e6565b6114ea919061175c565b9150611524565b60408401516a52b7d2dcc80cd2e40000009061150d858361171f565b61151791906116e6565b611521919061175c565b91505b83516a52b7d2dcc80cd2e40000009061153d908461171f565b61154791906116e6565b9050808460200181815161155b91906116ce565b9052505b604084018390525b878460000181815161157991906116ce565b905250505073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000008116600090815260208181526040808320865181558287015160018083019190915596820151600291820155938b168352918290208651815590860151818601559401519301929092559250505092915050565b803573ffffffffffffffffffffffffffffffffffffffff8116811461162c57600080fd5b919050565b600060208284031215611642578081fd5b61164b82611608565b9392505050565b600080600060608486031215611666578182fd5b61166f84611608565b925061167d60208501611608565b9150604084013590509250925092565b6000806040838503121561169f578182fd5b6116a883611608565b946020939093013593505050565b6000602082840312156116c7578081fd5b5051919050565b600082198211156116e1576116e1611773565b500190565b60008261171a577f4e487b710000000000000000000000000000000000000000000000000000000081526012600452602481fd5b500490565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048311821515161561175757611757611773565b500290565b60008282101561176e5761176e611773565b500390565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fdfea264697066735822122095fdafb69b51d8f2b50aa69920ca732a455288c23d96942686f7fdabba389c0364736f6c63430008040033a264697066735822122068ace4fc5b89030958360053e93d080af1c25bc657bcbc3707cf8f9a5e915ffa64736f6c63430008040033 \ No newline at end of file diff --git a/gost/build/marketplace/MarketPlace.sol b/gost/build/marketplace/MarketPlace.sol new file mode 100644 index 0000000..41311a5 --- /dev/null +++ b/gost/build/marketplace/MarketPlace.sol @@ -0,0 +1,259 @@ +// SPDX-License-Identifier: UNLICENSED + +// TODO update to 0.8.4 (or whatever latest is...) + +// NOTE the pattern [underlying, maturity*, cToken, ...] + +pragma solidity 0.8.4; + +import './Abstracts.sol'; +import './ZcToken.sol'; +import './VaultTracker.sol'; + +contract MarketPlace { + struct Market { + address cTokenAddr; + address zcTokenAddr; + address vaultAddr; + } + + mapping (address => mapping (uint256 => Market)) public markets; + mapping (address => mapping (uint256 => bool)) public mature; + mapping (address => mapping (uint256 => uint256)) public maturityRate; + + address public immutable admin; + address public swivel; + + event Create(address indexed underlying, uint256 indexed maturity, address cToken, address zcToken, address vaultTracker); + event Mature(address indexed underlying, uint256 indexed maturity, uint256 maturityRate, uint256 matured); + event RedeemZcToken(address indexed underlying, uint256 indexed maturity, address indexed sender, uint256 amount); + event RedeemVaultInterest(address indexed underlying, uint256 indexed maturity, address indexed sender); + event CustodialInitiate(address indexed underlying, uint256 indexed maturity, address zcTarget, address nTarget, uint256 amount); + event CustodialExit(address indexed underlying, uint256 indexed maturity, address zcTarget, address nTarget, uint256 amount); + event P2pZcTokenExchange(address indexed underlying, uint256 indexed maturity, address from, address to, uint256 amount); + event P2pVaultExchange(address indexed underlying, uint256 indexed maturity, address from, address to, uint256 amount); + event TransferVaultNotional(address indexed underlying, uint256 indexed maturity, address from, address to, uint256 amount); + + constructor() { + admin = msg.sender; + } + + /// @param s Address of the deployed swivel contract + function setSwivelAddress(address s) external onlyAdmin(admin) returns (bool) { + swivel = s; + return true; + } + + /// @notice Allows the owner to create new markets + /// @param u Underlying token address associated with the new market + /// @param m Maturity timestamp of the new market + /// @param c cToken address associated with underlying for the new market + /// @param n Name of the new zcToken market + /// @param s Symbol of the new zcToken market + function createMarket( + address u, + uint256 m, + address c, + string memory n, + string memory s, + uint8 d + ) public onlyAdmin(admin) returns (bool) { + require(swivel != address(0), 'swivel contract address not set'); + // TODO can we live with the factory pattern here both bytecode size wise and CREATE opcode cost wise? + address zctAddr = address(new ZcToken(u, m, n, s, d)); + address vAddr = address(new VaultTracker(m, c, swivel)); + markets[u][m] = Market(c, zctAddr, vAddr); + + emit Create(u, m, c, zctAddr, vAddr); + + return true; + } + + /// @notice Can be called after maturity, allowing all of the zcTokens to earn floating interest on Compound until they release their funds + /// @param u Underlying token address associated with the market + /// @param m Maturity timestamp of the market + function matureMarket(address u, uint256 m) public returns (bool) { + require(!mature[u][m], 'market already matured'); + require(block.timestamp >= ZcToken(markets[u][m].zcTokenAddr).maturity(), "maturity not reached"); + + // set the base maturity cToken exchange rate at maturity to the current cToken exchange rate + uint256 currentExchangeRate = CErc20(markets[u][m].cTokenAddr).exchangeRateCurrent(); + maturityRate[u][m] = currentExchangeRate; + // set the maturity state to true (for zcb market) + mature[u][m] = true; + + // set vault "matured" to true + require(VaultTracker(markets[u][m].vaultAddr).matureVault(), 'maturity not reached'); + + emit Mature(u, m, block.timestamp, currentExchangeRate); + + return true; + } + + /// @notice Allows Swivel caller to deposit their underlying, in the process splitting it - minting both zcTokens and vault notional. + /// @param u Underlying token address associated with the market + /// @param m Maturity timestamp of the market + /// @param t Address of the depositing user + /// @param a Amount of notional being added + function mintZcTokenAddingNotional(address u, uint256 m, address t, uint256 a) external onlySwivel(swivel) returns (bool) { + require(ZcToken(markets[u][m].zcTokenAddr).mint(t, a), 'mint zcToken failed'); + require(VaultTracker(markets[u][m].vaultAddr).addNotional(t, a), 'add notional failed'); + + return true; + } + + /// @notice Allows Swivel caller to deposit/burn both zcTokens + vault notional. This process is "combining" the two and redeeming underlying. + /// @param u Underlying token address associated with the market + /// @param m Maturity timestamp of the market + /// @param t Address of the combining/redeeming user + /// @param a Amount of zcTokens being burned + function burnZcTokenRemovingNotional(address u, uint256 m, address t, uint256 a) external onlySwivel(swivel) returns(bool) { + require(ZcToken(markets[u][m].zcTokenAddr).burn(t, a), 'burn failed'); + require(VaultTracker(markets[u][m].vaultAddr).removeNotional(t, a), 'remove notional failed'); + + return true; + } + + /// @notice Allows (via swivel) zcToken holders to redeem their tokens for underlying tokens after maturity has been reached. + /// @param u Underlying token address associated with the market + /// @param m Maturity timestamp of the market + /// @param t Address of the redeeming user + /// @param a Amount of zcTokens being redeemed + function redeemZcToken(address u, uint256 m, address t, uint256 a) external onlySwivel(swivel) returns (uint256) { + Market memory mkt = markets[u][m]; + bool matured = mature[u][m]; + + if (!matured) { + require(matureMarket(u, m), 'failed to mature the market'); + } + + // burn user's zcTokens + require(ZcToken(mkt.zcTokenAddr).burn(t, a), 'could not burn'); + + emit RedeemZcToken(u, m, t, a); + + if (!matured) { + return a; + } else { + // if the market was already mature the return should include the amount + marginal floating interest generated on Compound since maturity + return calculateReturn(u, m, a); + } + } + + /// @notice Allows Vault owners (via Swivel) to redeem any currently accrued interest + /// @param u Underlying token address associated with the market + /// @param m Maturity timestamp of the market + /// @param t Address of the redeeming user + function redeemVaultInterest(address u, uint256 m, address t) external onlySwivel(swivel) returns (uint256) { + // call to the floating market contract to release the position and calculate the interest generated + uint256 interest = VaultTracker(markets[u][m].vaultAddr).redeemInterest(t); + + emit RedeemVaultInterest(u, m, t); + + return interest; + } + + /// @notice Calculates the total amount of underlying returned including interest generated since the `matureMarket` function has been called + /// @param u Underlying token address associated with the market + /// @param m Maturity timestamp of the market + /// @param a Amount of zcTokens being redeemed + function calculateReturn(address u, uint256 m, uint256 a) internal returns (uint256) { + // calculate difference between the cToken exchange rate @ maturity and the current cToken exchange rate + uint256 yield = ((CErc20(markets[u][m].cTokenAddr).exchangeRateCurrent() * 1e26) / maturityRate[u][m]) - 1e26; + uint256 interest = (yield * a) / 1e26; + + // calculate the total amount of underlying principle to return + return a + interest; + } + + function cTokenAddress(address a, uint256 m) external view returns (address) { + return markets[a][m].cTokenAddr; + } + + /// @notice called by swivel IVFZI && IZFVI + /// @dev call with underlying, maturity, mint-target, add-notional-target and an amount + /// @param u Underlying token address associated with the market + /// @param m Maturity timestamp of the market + /// @param z Recipient of the minted zcToken + /// @param n Recipient of the added notional + /// @param a Amount of zcToken minted and notional added + function custodialInitiate(address u, uint256 m, address z, address n, uint256 a) external onlySwivel(swivel) returns (bool) { + require(ZcToken(markets[u][m].zcTokenAddr).mint(z, a), 'mint failed'); + require(VaultTracker(markets[u][m].vaultAddr).addNotional(n, a), 'add notional failed'); + emit CustodialInitiate(u, m, z, n, a); + return true; + } + + /// @notice called by swivel EVFZE FF EZFVE + /// @dev call with underlying, maturity, burn-target, remove-notional-target and an amount + /// @param u Underlying token address associated with the market + /// @param m Maturity timestamp of the market + /// @param z Owner of the zcToken to be burned + /// @param n Target to remove notional from + /// @param a Amount of zcToken burned and notional removed + function custodialExit(address u, uint256 m, address z, address n, uint256 a) external onlySwivel(swivel) returns (bool) { + require(ZcToken(markets[u][m].zcTokenAddr).burn(z, a), 'burn failed'); + require(VaultTracker(markets[u][m].vaultAddr).removeNotional(n, a), 'remove notional failed'); + emit CustodialExit(u, m, z, n, a); + return true; + } + + /// @notice called by swivel IZFZE, EZFZI + /// @dev call with underlying, maturity, transfer-from, transfer-to, amount + /// @param u Underlying token address associated with the market + /// @param m Maturity timestamp of the market + /// @param f Owner of the zcToken to be burned + /// @param t Target to be minted to + /// @param a Amount of zcToken transfer + function p2pZcTokenExchange(address u, uint256 m, address f, address t, uint256 a) external onlySwivel(swivel) returns (bool) { + require(ZcToken(markets[u][m].zcTokenAddr).burn(f, a), 'zcToken burn failed'); + require(ZcToken(markets[u][m].zcTokenAddr).mint(t, a), 'zcToken mint failed'); + emit P2pZcTokenExchange(u, m, f, t, a); + return true; + } + + /// @notice called by swivel IVFVE, EVFVI + /// @dev call with underlying, maturity, remove-from, add-to, amount + /// @param u Underlying token address associated with the market + /// @param m Maturity timestamp of the market + /// @param f Owner of the notional to be transferred + /// @param t Target to be transferred to + /// @param a Amount of notional transfer + function p2pVaultExchange(address u, uint256 m, address f, address t, uint256 a) external onlySwivel(swivel) returns (bool) { + require(VaultTracker(markets[u][m].vaultAddr).transferNotionalFrom(f, t, a), 'transfer notional failed'); + emit P2pVaultExchange(u, m, f, t, a); + return true; + } + + /// @notice External method giving access to this functionality within a given vault + /// @dev Note that this method calculates yield and interest as well + /// @param u Underlying token address associated with the market + /// @param m Maturity timestamp of the market + /// @param t Target to be transferred to + /// @param a Amount of notional to be transferred + function transferVaultNotional(address u, uint256 m, address t, uint256 a) public returns (bool) { + require(VaultTracker(markets[u][m].vaultAddr).transferNotionalFrom(msg.sender, t, a), 'vault transfer failed'); + emit TransferVaultNotional(u, m, msg.sender, t, a); + return true; + } + + /// @notice transfers notional fee to the Swivel contract without recalculating marginal interest for from + /// @param u Underlying token address associated with the market + /// @param m Maturity timestamp of the market + /// @param f Owner of the amount + /// @param a Amount to transfer + function transferVaultNotionalFee(address u, uint256 m, address f, uint256 a) public onlySwivel(swivel) returns (bool) { + VaultTracker(markets[u][m].vaultAddr).transferNotionalFee(f, a); + return true; + } + + modifier onlyAdmin(address a) { + require(msg.sender == a, 'sender must be admin'); + _; + } + + modifier onlySwivel(address s) { + require(msg.sender == s, 'sender must be Swivel contract'); + _; + } +} diff --git a/gost/build/marketplace/PErc20.abi b/gost/build/marketplace/PErc20.abi new file mode 100644 index 0000000..c8ceec3 --- /dev/null +++ b/gost/build/marketplace/PErc20.abi @@ -0,0 +1 @@ +[{"inputs":[{"internalType":"string","name":"n","type":"string"},{"internalType":"string","name":"s","type":"string"},{"internalType":"uint8","name":"d","type":"uint8"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"address","name":"o","type":"address"},{"internalType":"address","name":"s","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"s","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"a","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"s","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"s","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"r","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"s","type":"address"},{"internalType":"address","name":"r","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file diff --git a/gost/build/marketplace/PErc20.bin b/gost/build/marketplace/PErc20.bin new file mode 100644 index 0000000..0c80802 --- /dev/null +++ b/gost/build/marketplace/PErc20.bin @@ -0,0 +1 @@ +60806040523480156200001157600080fd5b5060405162000e4538038062000e458339810160408190526200003491620001d6565b8251620000499060049060208601906200007d565b5081516200005f9060059060208501906200007d565b506002805460ff191660ff9290921691909117905550620002aa9050565b8280546200008b9062000257565b90600052602060002090601f016020900481019282620000af5760008555620000fa565b82601f10620000ca57805160ff1916838001178555620000fa565b82800160010185558215620000fa579182015b82811115620000fa578251825591602001919060010190620000dd565b50620001089291506200010c565b5090565b5b808211156200010857600081556001016200010d565b600082601f83011262000134578081fd5b81516001600160401b038082111562000151576200015162000294565b604051601f8301601f19908116603f011681019082821181831017156200017c576200017c62000294565b8160405283815260209250868385880101111562000198578485fd5b8491505b83821015620001bb57858201830151818301840152908201906200019c565b83821115620001cc57848385830101525b9695505050505050565b600080600060608486031215620001eb578283fd5b83516001600160401b038082111562000202578485fd5b620002108783880162000123565b9450602086015191508082111562000226578384fd5b50620002358682870162000123565b925050604084015160ff811681146200024c578182fd5b809150509250925092565b600181811c908216806200026c57607f821691505b602082108114156200028e57634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052604160045260246000fd5b610b8b80620002ba6000396000f3fe608060405234801561001057600080fd5b50600436106100c95760003560e01c80633950935111610081578063a457c2d71161005b578063a457c2d7146101a9578063a9059cbb146101bc578063dd62ed3e146101cf57600080fd5b8063395093511461015857806370a082311461016b57806395d89b41146101a157600080fd5b806318160ddd116100b257806318160ddd1461010f57806323b872dd14610126578063313ce5671461013957600080fd5b806306fdde03146100ce578063095ea7b3146100ec575b600080fd5b6100d6610215565b6040516100e39190610a32565b60405180910390f35b6100ff6100fa366004610a09565b6102a3565b60405190151581526020016100e3565b61011860035481565b6040519081526020016100e3565b6100ff6101343660046109ce565b6102b9565b6002546101469060ff1681565b60405160ff90911681526020016100e3565b6100ff610166366004610a09565b6103ab565b61011861017936600461097b565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020819052604090205490565b6100d66103ef565b6100ff6101b7366004610a09565b6103fc565b6100ff6101ca366004610a09565b6104d5565b6101186101dd36600461099c565b73ffffffffffffffffffffffffffffffffffffffff918216600090815260016020908152604080832093909416825291909152205490565b6004805461022290610ad2565b80601f016020809104026020016040519081016040528092919081815260200182805461024e90610ad2565b801561029b5780601f106102705761010080835404028352916020019161029b565b820191906000526020600020905b81548152906001019060200180831161027e57829003601f168201915b505050505081565b60006102b03384846104e2565b50600192915050565b60006102c6848484610696565b73ffffffffffffffffffffffffffffffffffffffff841660009081526001602090815260408083203384529091529020548281101561038c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602760248201527f6572633230207472616e7366657220616d6f756e74206578636565647320616c60448201527f6c6f77616e63650000000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b6103a0853361039b8685610abb565b6104e2565b506001949350505050565b33600081815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716845290915281205490916102b091859061039b908690610aa3565b6005805461022290610ad2565b33600090815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff86168452909152812054828110156104bc576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f65726332302064656372656173656420616c6c6f77616e63652062656c6f772060448201527f7a65726f000000000000000000000000000000000000000000000000000000006064820152608401610383565b6104cb338561039b8685610abb565b5060019392505050565b60006102b0338484610696565b73ffffffffffffffffffffffffffffffffffffffff8316610585576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f657263323020617070726f76652066726f6d20746865207a65726f206164647260448201527f65737300000000000000000000000000000000000000000000000000000000006064820152608401610383565b73ffffffffffffffffffffffffffffffffffffffff8216610628576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f657263323020617070726f766520746f20746865207a65726f2061646472657360448201527f73000000000000000000000000000000000000000000000000000000000000006064820152608401610383565b73ffffffffffffffffffffffffffffffffffffffff83811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b73ffffffffffffffffffffffffffffffffffffffff8316610738576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f6572633230207472616e736665722066726f6d20746865207a65726f2061646460448201527f72657373000000000000000000000000000000000000000000000000000000006064820152608401610383565b73ffffffffffffffffffffffffffffffffffffffff82166107db576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f6572633230207472616e7366657220746f20746865207a65726f20616464726560448201527f73730000000000000000000000000000000000000000000000000000000000006064820152608401610383565b73ffffffffffffffffffffffffffffffffffffffff831660009081526020819052604090205481811015610891576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f6572633230207472616e7366657220616d6f756e74206578636565647320626160448201527f6c616e63650000000000000000000000000000000000000000000000000000006064820152608401610383565b61089b8282610abb565b73ffffffffffffffffffffffffffffffffffffffff80861660009081526020819052604080822093909355908516815290812080548492906108de908490610aa3565b925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8460405161094491815260200190565b60405180910390a350505050565b803573ffffffffffffffffffffffffffffffffffffffff8116811461097657600080fd5b919050565b60006020828403121561098c578081fd5b61099582610952565b9392505050565b600080604083850312156109ae578081fd5b6109b783610952565b91506109c560208401610952565b90509250929050565b6000806000606084860312156109e2578081fd5b6109eb84610952565b92506109f960208501610952565b9150604084013590509250925092565b60008060408385031215610a1b578182fd5b610a2483610952565b946020939093013593505050565b6000602080835283518082850152825b81811015610a5e57858101830151858201604001528201610a42565b81811115610a6f5783604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016929092016040019392505050565b60008219821115610ab657610ab6610b26565b500190565b600082821015610acd57610acd610b26565b500390565b600181811c90821680610ae657607f821691505b60208210811415610b20577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fdfea26469706673582212201369b4f042729674c3e6d5bd7808b03295921386dc0d4f876af213915f40221664736f6c63430008040033 \ No newline at end of file diff --git a/gost/build/marketplace/PErc20.sol b/gost/build/marketplace/PErc20.sol new file mode 100644 index 0000000..b129724 --- /dev/null +++ b/gost/build/marketplace/PErc20.sol @@ -0,0 +1,278 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.8.4; + +import "./IPErc20.sol"; + +/** + * @dev Implementation of the {IERC20} interface. + * + * NOTES: This is an adaptation of the Open Zeppelin ERC20, with changes made per audit + * requests, and to fit overall Swivel Style. We use it specifically as the base for + * the Erc2612 hence the `Perc` (Permissioned erc20) naming. + * + * Dangling underscores are generally not allowed within swivel style but the + * internal, abstracted implementation methods inherted from the O.Z contract are maintained here. + * Hence, when you see a dangling underscore prefix, you know it is *only* allowed for + * one of these method calls. It is not allowed for any other purpose. These are: + _approve + _transfer + _mint + _burn + * + * This implementation is agnostic to the way tokens are created. This means + * that a supply mechanism has to be added in a derived contract using {_mint}. + * For a generic mechanism see {ERC20PresetMinterPauser}. + * + * TIP: For a detailed writeup see our guide + * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How + * to implement supply mechanisms]. + * + * We have followed general OpenZeppelin guidelines: functions revert instead + * of returning `false` on failure. This behavior is nonetheless conventional + * and does not conflict with the expectations of ERC20 applications. + * + * Additionally, an {Approval} event is emitted on calls to {transferFrom}. + * This allows applications to reconstruct the allowance for all accounts just + * by listening to said events. Other implementations of the EIP may not emit + * these events, as it isn't required by the specification. + * + * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} + * functions have been added to mitigate the well-known issues around setting + * allowances. See {IERC20-approve}. + + + */ +contract PErc20 is IPErc20 { + mapping (address => uint256) private balances; + mapping (address => mapping (address => uint256)) private allowances; + + uint8 public decimals; + uint256 public totalSupply; + string public name; // NOTE: cannot make strings immutable + string public symbol; // NOTE: see above + + /** + * @dev Sets the values for {name} and {symbol}. + * @param n Name of the token + * @param s Symbol of the token + * @param d Decimals of the token + */ + constructor (string memory n, string memory s, uint8 d) { + name = n; + symbol = s; + decimals = d; + } + + /** + * @dev See {IERC20-balanceOf}. + * @param a Adress to fetch balance of + */ + function balanceOf(address a) public view virtual override returns (uint256) { + return balances[a]; + } + + /** + * @dev See {IERC20-transfer}. + * @param r The recipient + * @param a The amount transferred + * + * Requirements: + * + * - `recipient` cannot be the zero address. + * - the caller must have a balance of at least `amount`. + */ + function transfer(address r, uint256 a) public virtual override returns (bool) { + _transfer(msg.sender, r, a); + return true; + } + + /** + * @dev See {IERC20-allowance}. + * @param o The owner + * @param s The spender + */ + function allowance(address o, address s) public view virtual override returns (uint256) { + return allowances[o][s]; + } + + /** + * @dev See {IERC20-approve}. + * @param s The spender + * @param a The amount to approve + * + * Requirements: + * + * - `spender` cannot be the zero address. + */ + function approve(address s, uint256 a) public virtual override returns (bool) { + _approve(msg.sender, s, a); + return true; + } + + /** + * @dev See {IERC20-transferFrom}. + * + * @param s The sender + * @param r The recipient + * @param a The amount to transfer + * + * Emits an {Approval} event indicating the updated allowance. This is not + * required by the EIP. See the note at the beginning of {ERC20}. + * + * Requirements: + * + * - `sender` and `recipient` cannot be the zero address. + * - `sender` must have a balance of at least `amount`. + * - the caller must have allowance for ``sender``'s tokens of at least + * `amount`. + */ + function transferFrom(address s, address r, uint256 a) public virtual override returns (bool) { + _transfer(s, r, a); + + uint256 currentAllowance = allowances[s][msg.sender]; + require(currentAllowance >= a, "erc20 transfer amount exceeds allowance"); + _approve(s, msg.sender, currentAllowance - a); + + return true; + } + + /** + * @dev Atomically increases the allowance granted to `spender` by the caller. + * @param s The spender + * @param a The amount increased + * + * This is an alternative to {approve} that can be used as a mitigation for + * problems described in {IERC20-approve}. + * + * Emits an {Approval} event indicating the updated allowance. + * + * Requirements: + * + * - `spender` cannot be the zero address. + */ + function increaseAllowance(address s, uint256 a) public virtual returns (bool) { + _approve(msg.sender, s, allowances[msg.sender][s] + a); + return true; + } + + /** + * @dev Atomically decreases the allowance granted to `spender` by the caller. + * @param s The spender + * @param a The amount subtracted + * + * This is an alternative to {approve} that can be used as a mitigation for + * problems described in {IERC20-approve}. + * + * Emits an {Approval} event indicating the updated allowance. + * + * Requirements: + * + * - `spender` cannot be the zero address. + * - `spender` must have allowance for the caller of at least + * `subtractedValue`. + */ + function decreaseAllowance(address s, uint256 a) public virtual returns (bool) { + uint256 currentAllowance = allowances[msg.sender][s]; + require(currentAllowance >= a, "erc20 decreased allowance below zero"); + _approve(msg.sender, s, currentAllowance - a); + + return true; + } + + /** + * @dev Moves tokens `amount` from `sender` to `recipient`. + * @param s The sender + * @param r The recipient + * @param a The amount to transfer + * + * This is internal function is equivalent to {transfer}, and can be used to + * e.g. implement automatic token fees, slashing mechanisms, etc. + * + * Emits a {Transfer} event. + * + * Requirements: + * + * - `sender` cannot be the zero address. + * - `recipient` cannot be the zero address. + * - `sender` must have a balance of at least `amount`. + */ + function _transfer(address s, address r, uint256 a) internal virtual { + require(s != address(0), "erc20 transfer from the zero address"); + require(r != address(0), "erc20 transfer to the zero address"); + + uint256 senderBalance = balances[s]; + require(senderBalance >= a, "erc20 transfer amount exceeds balance"); + balances[s] = senderBalance - a; + balances[r] += a; + + emit Transfer(s, r, a); + } + + /** @dev Creates `amount` tokens and assigns them to `account`, increasing + * the total supply. + * @param r The recipient + * @param a The amount to mint + * + * Emits a {Transfer} event with `from` set to the zero address. + * + * Requirements: + * + * - `recipient` cannot be the zero address. + */ + function _mint(address r, uint256 a) internal virtual { + require(r != address(0), "erc20 mint to the zero address"); + + totalSupply += a; + balances[r] += a; + emit Transfer(address(0), r, a); + } + + /** + * @dev Destroys `amount` tokens from `owner`, reducing the + * total supply. + * @param o The owner of the amount being burned + * @param a The amount to burn + * + * Emits a {Transfer} event with `to` set to the zero address. + * + * Requirements: + * + * - `owner` cannot be the zero address. + * - `owner` must have at least `amount` tokens. + */ + function _burn(address o, uint256 a) internal virtual { + require(o != address(0), "erc20 burn from the zero address"); + + uint256 accountBalance = balances[o]; + require(accountBalance >= a, "erc20 burn amount exceeds balance"); + balances[o] = accountBalance - a; + totalSupply -= a; + + emit Transfer(o, address(0), a); + } + + /** + * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens. + * @param o The owner + * @param s The spender + * @param a The amount + * + * This internal function is equivalent to `approve`, and can be used to + * e.g. set automatic allowances for certain subsystems, etc. + * + * Emits an {Approval} event. + * + * Requirements: + * + * - `owner` cannot be the zero address. + * - `spender` cannot be the zero address. + */ + function _approve(address o, address s, uint256 a) internal virtual { + require(o != address(0), "erc20 approve from the zero address"); + require(s != address(0), "erc20 approve to the zero address"); + + allowances[o][s] = a; + emit Approval(o, s, a); + } +} diff --git a/gost/build/marketplace/VaultTracker.abi b/gost/build/marketplace/VaultTracker.abi new file mode 100644 index 0000000..3fe5f20 --- /dev/null +++ b/gost/build/marketplace/VaultTracker.abi @@ -0,0 +1 @@ +[{"inputs":[{"internalType":"uint256","name":"m","type":"uint256"},{"internalType":"address","name":"c","type":"address"},{"internalType":"address","name":"s","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"o","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"addNotional","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"admin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"o","type":"address"}],"name":"balancesOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cTokenAddr","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"matureVault","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"matured","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maturity","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maturityRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"o","type":"address"}],"name":"redeemInterest","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"o","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"removeNotional","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"swivel","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"f","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"transferNotionalFee","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"f","type":"address"},{"internalType":"address","name":"t","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"transferNotionalFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"vaults","outputs":[{"internalType":"uint256","name":"notional","type":"uint256"},{"internalType":"uint256","name":"redeemable","type":"uint256"},{"internalType":"uint256","name":"exchangeRate","type":"uint256"}],"stateMutability":"view","type":"function"}] \ No newline at end of file diff --git a/gost/build/marketplace/VaultTracker.bin b/gost/build/marketplace/VaultTracker.bin new file mode 100644 index 0000000..b99eb80 --- /dev/null +++ b/gost/build/marketplace/VaultTracker.bin @@ -0,0 +1 @@ +6101006040523480156200001257600080fd5b50604051620019423803806200194283398101604081905262000035916200007f565b33606090811b60805260e0939093526001600160601b031991831b821660a05290911b1660c052620000bf565b80516001600160a01b03811681146200007a57600080fd5b919050565b60008060006060848603121562000094578283fd5b83519250620000a66020850162000062565b9150620000b66040850162000062565b90509250925092565b60805160601c60a05160601c60c05160601c60e0516117d86200016a600039600081816101920152610e4e01526000818160f40152818161138001526115950152600081816102a40152818161047c0152818161089701528181610b7801528181610f400152818161107101526113e90152600081816102cb015281816102f10152818161077f01528181610a1d01528181610d4101528181610fcf015261129801526117d86000f3fe608060405234801561001057600080fd5b50600436106100ea5760003560e01c80636392a51f1161008c578063a622ee7c11610066578063a622ee7c14610242578063b326258d1461028c578063b7dd34831461029f578063f851a440146102c657600080fd5b80636392a51f146101d45780636b868d5114610227578063a01cfffb1461022f57600080fd5b806319caf46c116100c857806319caf46c1461017a578063204f83f91461018d578063454c87b3146101b4578063613a28d1146101c157600080fd5b8063012b264a146100ef57806311554c43146101405780631779467314610157575b600080fd5b6101167f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b61014960025481565b604051908152602001610137565b61016a610165366004611652565b6102ed565b6040519015158152602001610137565b610149610188366004611631565b61077b565b6101497f000000000000000000000000000000000000000000000000000000000000000081565b60015461016a9060ff1681565b61016a6101cf36600461168d565b610a19565b6102126101e2366004611631565b73ffffffffffffffffffffffffffffffffffffffff16600090815260208190526040902080546001909101549091565b60408051928352602083019190915201610137565b61016a610d3d565b61016a61023d36600461168d565b610fcb565b610271610250366004611631565b60006020819052908152604090208054600182015460029092015490919083565b60408051938452602084019290925290820152606001610137565b61016a61029a36600461168d565b611294565b6101167f000000000000000000000000000000000000000000000000000000000000000081565b6101167f000000000000000000000000000000000000000000000000000000000000000081565b60007f00000000000000000000000000000000000000000000000000000000000000003373ffffffffffffffffffffffffffffffffffffffff821614610394576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f73656e646572206d7573742062652061646d696e00000000000000000000000060448201526064015b60405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff808616600090815260208181526040808320815160608082018452825482526001808401548387015260029384015483860152968b16865285855294839020835195860184528054865295860154938501939093529390930154928201929092528151851115610475576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f616d6f756e74206578636565647320617661696c61626c652062616c616e6365604482015260640161038b565b60008060007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663bd6d894d6040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156104e257600080fd5b505af11580156104f6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061051a91906116b6565b60015490915060ff161561056d576a52b7d2dcc80cd2e400000085604001516002546a52b7d2dcc80cd2e4000000610552919061171f565b61055c91906116e6565b610566919061175c565b92506105a0565b60408501516a52b7d2dcc80cd2e400000090610589838361171f565b61059391906116e6565b61059d919061175c565b92505b84516a52b7d2dcc80cd2e4000000906105b9908561171f565b6105c391906116e6565b915081856020018181516105d791906116ce565b9052508451889086906105eb90839061175c565b905250604080860182815273ffffffffffffffffffffffffffffffffffffffff8c166000908152602081815292902087518155918701516001830155516002909101558351156107105760015460009060ff1615610688576a52b7d2dcc80cd2e400000085604001516002546a52b7d2dcc80cd2e400000061066d919061171f565b61067791906116e6565b610681919061175c565b93506106bb565b60408501516a52b7d2dcc80cd2e4000000906106a4848361171f565b6106ae91906116e6565b6106b8919061175c565b93505b84516a52b7d2dcc80cd2e4000000906106d4908661171f565b6106de91906116e6565b905080856020018181516106f291906116ce565b9052508451899086906107069083906116ce565b9052506107269050565b878460000181815161072291906116ce565b9052505b604080850191825273ffffffffffffffffffffffffffffffffffffffff8a1660009081526020818152919020855181559401516001808601919091559051600290940193909355509093505050509392505050565b60007f00000000000000000000000000000000000000000000000000000000000000003373ffffffffffffffffffffffffffffffffffffffff82161461081d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f73656e646572206d7573742062652061646d696e000000000000000000000000604482015260640161038b565b73ffffffffffffffffffffffffffffffffffffffff80841660009081526020818152604080832081516060810183528154815260018201548185018190526002909201548184015282517fbd6d894d00000000000000000000000000000000000000000000000000000000815292519095919493849384937f0000000000000000000000000000000000000000000000000000000000000000169263bd6d894d9260048084019391929182900301818787803b1580156108dc57600080fd5b505af11580156108f0573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061091491906116b6565b60015490915060ff1615610967576a52b7d2dcc80cd2e400000085604001516002546a52b7d2dcc80cd2e400000061094c919061171f565b61095691906116e6565b610960919061175c565b925061099a565b60408501516a52b7d2dcc80cd2e400000090610983838361171f565b61098d91906116e6565b610997919061175c565b92505b84516a52b7d2dcc80cd2e4000000906109b3908561171f565b6109bd91906116e6565b604080870183815260006020808a0182815273ffffffffffffffffffffffffffffffffffffffff8e168352908290529290208851815591516001830155516002909101559150610a0d82856116ce565b98975050505050505050565b60007f00000000000000000000000000000000000000000000000000000000000000003373ffffffffffffffffffffffffffffffffffffffff821614610abb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f73656e646572206d7573742062652061646d696e000000000000000000000000604482015260640161038b565b73ffffffffffffffffffffffffffffffffffffffff8416600090815260208181526040918290208251606081018452815480825260018301549382019390935260029091015492810192909252841115610b71576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f616d6f756e742065786365656473207661756c742062616c616e636500000000604482015260640161038b565b60008060007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663bd6d894d6040518163ffffffff1660e01b8152600401602060405180830381600087803b158015610bde57600080fd5b505af1158015610bf2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c1691906116b6565b60015490915060ff1615610c69576a52b7d2dcc80cd2e400000084604001516002546a52b7d2dcc80cd2e4000000610c4e919061171f565b610c5891906116e6565b610c62919061175c565b9250610c9c565b60408401516a52b7d2dcc80cd2e400000090610c85838361171f565b610c8f91906116e6565b610c99919061175c565b92505b83516a52b7d2dcc80cd2e400000090610cb5908561171f565b610cbf91906116e6565b91508184602001818151610cd391906116ce565b905250835187908590610ce790839061175c565b905250604080850191825273ffffffffffffffffffffffffffffffffffffffff89166000908152602081815291902085518155940151600180860191909155905160029094019390935550909250505092915050565b60007f00000000000000000000000000000000000000000000000000000000000000003373ffffffffffffffffffffffffffffffffffffffff821614610ddf576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f73656e646572206d7573742062652061646d696e000000000000000000000000604482015260640161038b565b60015460ff1615610e4c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f616c7265616479206d6174757265640000000000000000000000000000000000604482015260640161038b565b7f0000000000000000000000000000000000000000000000000000000000000000421015610ed6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f6d6174757269747920686173206e6f74206265656e2072656163686564000000604482015260640161038b565b600180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001681179055604080517fbd6d894d000000000000000000000000000000000000000000000000000000008152905173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169163bd6d894d9160048083019260209291908290030181600087803b158015610f8857600080fd5b505af1158015610f9c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fc091906116b6565b600255600191505090565b60007f00000000000000000000000000000000000000000000000000000000000000003373ffffffffffffffffffffffffffffffffffffffff82161461106d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f73656e646572206d7573742062652061646d696e000000000000000000000000604482015260640161038b565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663bd6d894d6040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156110d757600080fd5b505af11580156110eb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061110f91906116b6565b73ffffffffffffffffffffffffffffffffffffffff8616600090815260208181526040918290208251606081018452815480825260018301549382019390935260029091015492810192909252919250901561124357600154600090819060ff16156111ba576a52b7d2dcc80cd2e400000083604001516002546a52b7d2dcc80cd2e400000061119f919061171f565b6111a991906116e6565b6111b3919061175c565b91506111ed565b60408301516a52b7d2dcc80cd2e4000000906111d6868361171f565b6111e091906116e6565b6111ea919061175c565b91505b82516a52b7d2dcc80cd2e400000090611206908461171f565b61121091906116e6565b9050808360200181815161122491906116ce565b9052508251879084906112389083906116ce565b905250611247915050565b8481525b604080820192835273ffffffffffffffffffffffffffffffffffffffff87166000908152602081815291902082518155910151600180830191909155915160029091015591505092915050565b60007f00000000000000000000000000000000000000000000000000000000000000003373ffffffffffffffffffffffffffffffffffffffff821614611336576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f73656e646572206d7573742062652061646d696e000000000000000000000000604482015260640161038b565b73ffffffffffffffffffffffffffffffffffffffff8085166000908152602081815260408083208151606080820184528254825260018084015483870152600293840154838601527f0000000000000000000000000000000000000000000000000000000000000000909716865285855294839020835195860184528054865295860154938501939093529390930154928201929092528151859083906113de90839061175c565b9150818152505060007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663bd6d894d6040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561144f57600080fd5b505af1158015611463573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061148791906116b6565b9050600080828460400151146115675760408401511561155f5760015460ff16156114f1576a52b7d2dcc80cd2e400000084604001516002546a52b7d2dcc80cd2e40000006114d6919061171f565b6114e091906116e6565b6114ea919061175c565b9150611524565b60408401516a52b7d2dcc80cd2e40000009061150d858361171f565b61151791906116e6565b611521919061175c565b91505b83516a52b7d2dcc80cd2e40000009061153d908461171f565b61154791906116e6565b9050808460200181815161155b91906116ce565b9052505b604084018390525b878460000181815161157991906116ce565b905250505073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000008116600090815260208181526040808320865181558287015160018083019190915596820151600291820155938b168352918290208651815590860151818601559401519301929092559250505092915050565b803573ffffffffffffffffffffffffffffffffffffffff8116811461162c57600080fd5b919050565b600060208284031215611642578081fd5b61164b82611608565b9392505050565b600080600060608486031215611666578182fd5b61166f84611608565b925061167d60208501611608565b9150604084013590509250925092565b6000806040838503121561169f578182fd5b6116a883611608565b946020939093013593505050565b6000602082840312156116c7578081fd5b5051919050565b600082198211156116e1576116e1611773565b500190565b60008261171a577f4e487b710000000000000000000000000000000000000000000000000000000081526012600452602481fd5b500490565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048311821515161561175757611757611773565b500290565b60008282101561176e5761176e611773565b500390565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fdfea264697066735822122095fdafb69b51d8f2b50aa69920ca732a455288c23d96942686f7fdabba389c0364736f6c63430008040033 \ No newline at end of file diff --git a/gost/build/marketplace/VaultTracker.sol b/gost/build/marketplace/VaultTracker.sol new file mode 100644 index 0000000..8128773 --- /dev/null +++ b/gost/build/marketplace/VaultTracker.sol @@ -0,0 +1,251 @@ +// SPDX-License-Identifier: UNLICENSED + +pragma solidity 0.8.4; + +import "./Abstracts.sol"; + +contract VaultTracker { + struct Vault { + uint256 notional; + uint256 redeemable; + uint256 exchangeRate; + } + + mapping(address => Vault) public vaults; + + address public immutable admin; + address public immutable cTokenAddr; + address public immutable swivel; + bool public matured; + uint256 public immutable maturity; + uint256 public maturityRate; + + /// @param m Maturity timestamp of the new market + /// @param c cToken address associated with underlying for the new market + /// @param s address of the deployed swivel contract + constructor(uint256 m, address c, address s) { + admin = msg.sender; + maturity = m; + cTokenAddr = c; + swivel = s; + } + + /// @notice Adds notional (nTokens) to a given user's vault + /// @param o Address that owns a vault + /// @param a Amount of notional added + function addNotional(address o, uint256 a) public onlyAdmin(admin) returns (bool) { + uint256 exchangeRate = CErc20(cTokenAddr).exchangeRateCurrent(); + + Vault memory vlt = vaults[o]; + + if (vlt.notional > 0) { + uint256 yield; + uint256 interest; + + // if market has matured, calculate marginal interest between the maturity rate and previous position exchange rate + // otherwise, calculate marginal exchange rate between current and previous exchange rate. + if (matured) { // Calculate marginal interest + yield = ((maturityRate * 1e26) / vlt.exchangeRate) - 1e26; + } else { + yield = ((exchangeRate * 1e26) / vlt.exchangeRate) - 1e26; + } + + interest = (yield * vlt.notional) / 1e26; + // add interest and amount to position, reset cToken exchange rate + vlt.redeemable += interest; + vlt.notional += a; + } else { + vlt.notional = a; + } + + vlt.exchangeRate = exchangeRate; + vaults[o] = vlt; + + return true; + } + + /// @notice Removes notional (nTokens) from a given user's vault + /// @param o Address that owns a vault + /// @param a Amount of notional to remove + function removeNotional(address o, uint256 a) public onlyAdmin(admin) returns (bool) { + + Vault memory vlt = vaults[o]; + + require(vlt.notional >= a, "amount exceeds vault balance"); + + uint256 yield; + uint256 interest; + uint256 exchangeRate = CErc20(cTokenAddr).exchangeRateCurrent(); + + // if market has matured, calculate marginal interest between the maturity rate and previous position exchange rate + // otherwise, calculate marginal exchange rate between current and previous exchange rate. + if (matured) { // Calculate marginal interest + yield = ((maturityRate * 1e26) / vlt.exchangeRate) - 1e26; + } else { + // calculate marginal interest + yield = ((exchangeRate * 1e26) / vlt.exchangeRate) - 1e26; + } + + interest = (yield * vlt.notional) / 1e26; + // remove amount from position, Add interest to position, reset cToken exchange rate + vlt.redeemable += interest; + vlt.notional -= a; + vlt.exchangeRate = exchangeRate; + + vaults[o] = vlt; + + return true; + } + + /// @notice Redeem's the `redeemable` + marginal interest from a given user's vault + /// @param o Address that owns a vault + function redeemInterest(address o) external onlyAdmin(admin) returns (uint256) { + + Vault memory vlt = vaults[o]; + + uint256 redeemable = vlt.redeemable; + uint256 yield; + uint256 interest; + uint256 exchangeRate = CErc20(cTokenAddr).exchangeRateCurrent(); + + // if market has matured, calculate marginal interest between the maturity rate and previous position exchange rate + // otherwise, calculate marginal exchange rate between current and previous exchange rate. + if (matured) { // Calculate marginal interest + yield = ((maturityRate * 1e26) / vlt.exchangeRate) - 1e26; + } else { + // calculate marginal interest + yield = ((exchangeRate * 1e26) / vlt.exchangeRate) - 1e26; + } + + interest = (yield * vlt.notional) / 1e26; + + vlt.exchangeRate = exchangeRate; + vlt.redeemable = 0; + + vaults[o] = vlt; + + // return adds marginal interest to previously accrued redeemable interest + return (redeemable + interest); + } + + /// @notice Matures the vault and sets the market's maturityRate + function matureVault() external onlyAdmin(admin) returns (bool) { + require(!matured, 'already matured'); + require(block.timestamp >= maturity, 'maturity has not been reached'); + matured = true; + maturityRate = CErc20(cTokenAddr).exchangeRateCurrent(); + return true; + } + + /// @notice Transfers notional (nTokens) from one user to another + /// @param f Owner of the amount + /// @param t Recipient of the amount + /// @param a Amount to transfer + function transferNotionalFrom(address f, address t, uint256 a) external onlyAdmin(admin) returns (bool) { + Vault memory from = vaults[f]; + Vault memory to = vaults[t]; + + require(from.notional >= a, "amount exceeds available balance"); + + uint256 yield; + uint256 interest; + uint256 exchangeRate = CErc20(cTokenAddr).exchangeRateCurrent(); + + // if market has matured, calculate marginal interest between the maturity rate and previous position exchange rate + // otherwise, calculate marginal exchange rate between current and previous exchange rate. + if (matured) { + // calculate marginal interest + yield = ((maturityRate * 1e26) / from.exchangeRate) - 1e26; + } else { + yield = ((exchangeRate * 1e26) / from.exchangeRate) - 1e26; + } + + interest = (yield * from.notional) / 1e26; + // remove amount from position, Add interest to position, reset cToken exchange rate + from.redeemable += interest; + from.notional -= a; + from.exchangeRate = exchangeRate; + + vaults[f] = from; + + // transfer notional to address "t", calculate interest if necessary + if (to.notional > 0) { + uint256 newVaultInterest; + + // if market has matured, calculate marginal interest between the maturity rate and previous position exchange rate + // otherwise, calculate marginal exchange rate between current and previous exchange rate. + if (matured) { + // calculate marginal interest + yield = ((maturityRate * 1e26) / to.exchangeRate) - 1e26; + } else { + yield = ((exchangeRate * 1e26) / to.exchangeRate) - 1e26; + } + + newVaultInterest = (yield * to.notional) / 1e26; + // add interest and amount to position, reset cToken exchange rate + to.redeemable += newVaultInterest; + to.notional += a; + } else { + to.notional += a; + } + + to.exchangeRate = exchangeRate; + vaults[t] = to; + + return true; + } + + /// @notice transfers, in notional, a fee payment to the Swivel contract without recalculating marginal interest for the owner + /// @param f Owner of the amount + /// @param a Amount to transfer + function transferNotionalFee(address f, uint256 a) external onlyAdmin(admin) returns(bool) { + Vault memory oVault = vaults[f]; + Vault memory sVault = vaults[swivel]; + + // remove notional from its owner + oVault.notional -= a; + + uint256 exchangeRate = CErc20(cTokenAddr).exchangeRateCurrent(); + uint256 yield; + uint256 interest; + + // check if exchangeRate has been stored already this block. If not, calculate marginal interest + store exchangeRate + if (sVault.exchangeRate != exchangeRate) { + // the rate will be 0 if swivel did not already have a vault + if (sVault.exchangeRate != 0) { + // if market has matured, calculate marginal interest between the maturity rate and previous position exchange rate + // otherwise, calculate marginal exchange rate between current and previous exchange rate. + if (matured) { + // calculate marginal interest + yield = ((maturityRate * 1e26) / sVault.exchangeRate) - 1e26; + } else { + yield = ((exchangeRate * 1e26) / sVault.exchangeRate) - 1e26; + } + + interest = (yield * sVault.notional) / 1e26; + // add interest and amount, reset cToken exchange rate + sVault.redeemable += interest; + } + sVault.exchangeRate = exchangeRate; + } + + // add notional to swivel's vault + sVault.notional += a; + + // store the adjusted vaults + vaults[swivel] = sVault; + vaults[f] = oVault; + return true; + } + + /// @notice Returns both relevant balances for a given user's vault + /// @param o Address that owns a vault + function balancesOf(address o) public view returns (uint256, uint256) { + return (vaults[o].notional, vaults[o].redeemable); + } + + modifier onlyAdmin(address a) { + require(msg.sender == a, 'sender must be admin'); + _; + } +} diff --git a/gost/build/marketplace/ZcToken.abi b/gost/build/marketplace/ZcToken.abi new file mode 100644 index 0000000..84cb9cb --- /dev/null +++ b/gost/build/marketplace/ZcToken.abi @@ -0,0 +1 @@ +[{"inputs":[{"internalType":"address","name":"u","type":"address"},{"internalType":"uint256","name":"m","type":"uint256"},{"internalType":"string","name":"n","type":"string"},{"internalType":"string","name":"s","type":"string"},{"internalType":"uint8","name":"d","type":"uint8"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"admin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"o","type":"address"},{"internalType":"address","name":"s","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"s","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"a","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"f","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"burn","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"s","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"domain","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"s","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"maturity","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"t","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"mint","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"o","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"},{"internalType":"uint256","name":"d","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"r","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"s","type":"address"},{"internalType":"address","name":"r","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"underlying","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}] \ No newline at end of file diff --git a/gost/build/marketplace/ZcToken.bin b/gost/build/marketplace/ZcToken.bin new file mode 100644 index 0000000..8832d27 --- /dev/null +++ b/gost/build/marketplace/ZcToken.bin @@ -0,0 +1 @@ +6101006040523480156200001257600080fd5b506040516200193238038062001932833981016040819052620000359162000296565b8282828282828260049080519060200190620000539291906200013d565b508151620000699060059060208501906200013d565b5080600260006101000a81548160ff021916908360ff160217905550505050620000ba83604051806040016040528060018152602001603160f81b8152504630620000e660201b62000ab61760201c565b60805250505033606090811b60a0529490941b6001600160601b03191660c052505060e0525062000394565b8351602094850120835193850193909320604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f815295860194909452928401929092526060830152608082015260a0902090565b8280546200014b9062000341565b90600052602060002090601f0160209004810192826200016f5760008555620001ba565b82601f106200018a57805160ff1916838001178555620001ba565b82800160010185558215620001ba579182015b82811115620001ba5782518255916020019190600101906200019d565b50620001c8929150620001cc565b5090565b5b80821115620001c85760008155600101620001cd565b600082601f830112620001f4578081fd5b81516001600160401b03808211156200021157620002116200037e565b604051601f8301601f19908116603f011681019082821181831017156200023c576200023c6200037e565b8160405283815260209250868385880101111562000258578485fd5b8491505b838210156200027b57858201830151818301840152908201906200025c565b838211156200028c57848385830101525b9695505050505050565b600080600080600060a08688031215620002ae578081fd5b85516001600160a01b0381168114620002c5578182fd5b6020870151604088015191965094506001600160401b0380821115620002e9578283fd5b620002f789838a01620001e3565b945060608801519150808211156200030d578283fd5b506200031c88828901620001e3565b925050608086015160ff8116811462000333578182fd5b809150509295509295909350565b600181811c908216806200035657607f821691505b602082108114156200037857634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052604160045260246000fd5b60805160a05160601c60c05160601c60e051611549620003e960003960006101b30152600061023201526000818161039701528181610597015261065a015260008181610315015261093101526115496000f3fe608060405234801561001057600080fd5b50600436106101515760003560e01c806370a08231116100cd578063a9059cbb11610081578063d505accf11610066578063d505accf14610337578063dd62ed3e1461034c578063f851a4401461039257600080fd5b8063a9059cbb146102fd578063c2fb26a61461031057600080fd5b806395d89b41116100b257806395d89b41146102cf5780639dc29fac146102d7578063a457c2d7146102ea57600080fd5b806370a08231146102795780637ecebe00146102af57600080fd5b806323b872dd116101245780633950935111610109578063395093511461020757806340c10f191461021a5780636f307dc31461022d57600080fd5b806323b872dd146101d5578063313ce567146101e857600080fd5b806306fdde0314610156578063095ea7b31461017457806318160ddd14610197578063204f83f9146101ae575b600080fd5b61015e6103b9565b60405161016b91906113b7565b60405180910390f35b61018761018236600461138e565b610447565b604051901515815260200161016b565b6101a060035481565b60405190815260200161016b565b6101a07f000000000000000000000000000000000000000000000000000000000000000081565b6101876101e33660046112e2565b61045d565b6002546101f59060ff1681565b60405160ff909116815260200161016b565b61018761021536600461138e565b61054f565b61018761022836600461138e565b610593565b6102547f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161016b565b6101a061028736600461128f565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020819052604090205490565b6101a06102bd36600461128f565b60066020526000908152604090205481565b61015e610649565b6101876102e536600461138e565b610656565b6101876102f836600461138e565b610702565b61018761030b36600461138e565b6107d1565b6101a07f000000000000000000000000000000000000000000000000000000000000000081565b61034a61034536600461131d565b6107de565b005b6101a061035a3660046112b0565b73ffffffffffffffffffffffffffffffffffffffff918216600090815260016020908152604080832093909416825291909152205490565b6102547f000000000000000000000000000000000000000000000000000000000000000081565b600480546103c690611457565b80601f01602080910402602001604051908101604052809291908181526020018280546103f290611457565b801561043f5780601f106104145761010080835404028352916020019161043f565b820191906000526020600020905b81548152906001019060200180831161042257829003601f168201915b505050505081565b6000610454338484610b0d565b50600192915050565b600061046a848484610cc2565b73ffffffffffffffffffffffffffffffffffffffff8416600090815260016020908152604080832033845290915290205482811015610530576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602760248201527f6572633230207472616e7366657220616d6f756e74206578636565647320616c60448201527f6c6f77616e63650000000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b610544853361053f8685611440565b610b0d565b506001949350505050565b33600081815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff87168452909152812054909161045491859061053f908690611428565b60007f00000000000000000000000000000000000000000000000000000000000000003373ffffffffffffffffffffffffffffffffffffffff821614610635576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f73656e646572206d7573742062652061646d696e0000000000000000000000006044820152606401610527565b61063f8484610f7e565b5060019392505050565b600580546103c690611457565b60007f00000000000000000000000000000000000000000000000000000000000000003373ffffffffffffffffffffffffffffffffffffffff8216146106f8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f73656e646572206d7573742062652061646d696e0000000000000000000000006044820152606401610527565b61063f848461109e565b33600090815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff86168452909152812054828110156107c2576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f65726332302064656372656173656420616c6c6f77616e63652062656c6f772060448201527f7a65726f000000000000000000000000000000000000000000000000000000006064820152608401610527565b61063f338561053f8685611440565b6000610454338484610cc2565b42841015610848576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f65726332363132206578706972656420646561646c696e6500000000000000006044820152606401610527565b73ffffffffffffffffffffffffffffffffffffffff871660009081526006602052604081208054610909918a918a918a919086610884836114ab565b90915550604080517f80772249b4aef1688b30651778f4249b05cb73b517d98482439b9d8999b3060260208083019190915273ffffffffffffffffffffffffffffffffffffffff96871682840152949095166060860152608085019290925260a084015260c08084018a90528151808503909101815260e09093019052815191012090565b6040517f190100000000000000000000000000000000000000000000000000000000000081527f0000000000000000000000000000000000000000000000000000000000000000600282015260228101829052604290209091506000906040805160008082526020820180845284905260ff89169282019290925260608101879052608081018690529192509060019060a0016020604051602081039080840390855afa1580156109be573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff811615801590610a3957508973ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16145b610a9f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f6572633236313220696e76616c6964207369676e6174757265000000000000006044820152606401610527565b610aaa8a8a8a610b0d565b50505050505050505050565b8351602094850120835193850193909320604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f815295860194909452928401929092526060830152608082015260a0902090565b73ffffffffffffffffffffffffffffffffffffffff8316610bb0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f657263323020617070726f76652066726f6d20746865207a65726f206164647260448201527f65737300000000000000000000000000000000000000000000000000000000006064820152608401610527565b73ffffffffffffffffffffffffffffffffffffffff8216610c53576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f657263323020617070726f766520746f20746865207a65726f2061646472657360448201527f73000000000000000000000000000000000000000000000000000000000000006064820152608401610527565b73ffffffffffffffffffffffffffffffffffffffff83811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591015b60405180910390a3505050565b73ffffffffffffffffffffffffffffffffffffffff8316610d64576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f6572633230207472616e736665722066726f6d20746865207a65726f2061646460448201527f72657373000000000000000000000000000000000000000000000000000000006064820152608401610527565b73ffffffffffffffffffffffffffffffffffffffff8216610e07576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f6572633230207472616e7366657220746f20746865207a65726f20616464726560448201527f73730000000000000000000000000000000000000000000000000000000000006064820152608401610527565b73ffffffffffffffffffffffffffffffffffffffff831660009081526020819052604090205481811015610ebd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f6572633230207472616e7366657220616d6f756e74206578636565647320626160448201527f6c616e63650000000000000000000000000000000000000000000000000000006064820152608401610527565b610ec78282611440565b73ffffffffffffffffffffffffffffffffffffffff8086166000908152602081905260408082209390935590851681529081208054849290610f0a908490611428565b925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84604051610f7091815260200190565b60405180910390a350505050565b73ffffffffffffffffffffffffffffffffffffffff8216610ffb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f6572633230206d696e7420746f20746865207a65726f206164647265737300006044820152606401610527565b806003600082825461100d9190611428565b909155505073ffffffffffffffffffffffffffffffffffffffff821660009081526020819052604081208054839290611047908490611428565b909155505060405181815273ffffffffffffffffffffffffffffffffffffffff8316906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a35050565b73ffffffffffffffffffffffffffffffffffffffff821661111b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f6572633230206275726e2066726f6d20746865207a65726f20616464726573736044820152606401610527565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260208190526040902054818110156111d1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f6572633230206275726e20616d6f756e7420657863656564732062616c616e6360448201527f65000000000000000000000000000000000000000000000000000000000000006064820152608401610527565b6111db8282611440565b73ffffffffffffffffffffffffffffffffffffffff841660009081526020819052604081209190915560038054849290611216908490611440565b909155505060405182815260009073ffffffffffffffffffffffffffffffffffffffff8516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90602001610cb5565b803573ffffffffffffffffffffffffffffffffffffffff8116811461128a57600080fd5b919050565b6000602082840312156112a0578081fd5b6112a982611266565b9392505050565b600080604083850312156112c2578081fd5b6112cb83611266565b91506112d960208401611266565b90509250929050565b6000806000606084860312156112f6578081fd5b6112ff84611266565b925061130d60208501611266565b9150604084013590509250925092565b600080600080600080600060e0888a031215611337578283fd5b61134088611266565b965061134e60208901611266565b95506040880135945060608801359350608088013560ff81168114611371578384fd5b9699959850939692959460a0840135945060c09093013592915050565b600080604083850312156113a0578182fd5b6113a983611266565b946020939093013593505050565b6000602080835283518082850152825b818110156113e3578581018301518582016040015282016113c7565b818111156113f45783604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016929092016040019392505050565b6000821982111561143b5761143b6114e4565b500190565b600082821015611452576114526114e4565b500390565b600181811c9082168061146b57607f821691505b602082108114156114a5577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8214156114dd576114dd6114e4565b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fdfea2646970667358221220d800b92df8c6048dd793473ca8313793ca1656ca285d3b8deb63563c217aa06564736f6c63430008040033 \ No newline at end of file diff --git a/gost/build/marketplace/ZcToken.sol b/gost/build/marketplace/ZcToken.sol new file mode 100644 index 0000000..897c05b --- /dev/null +++ b/gost/build/marketplace/ZcToken.sol @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: MIT + +// NOTE: whomever decided methods which are the implementation of a stated interface +// need to be labeled 'override' should to be publicly flogged. + +pragma solidity 0.8.4; + +import './Erc2612.sol'; +import './IZcToken.sol'; + +/// NOTE the OZStlye naming conventions are kept for the internal methods +/// _burn and _mint as dangling underscores are generally not allowed. +contract ZcToken is Erc2612, IZcToken { + address public immutable admin; + address public immutable underlying; + uint256 public immutable maturity; + + /// @param u Underlying + /// @param m Maturity + /// @param n Name + /// @param s Symbol + /// @param d Decimals + constructor(address u, uint256 m, string memory n, string memory s, uint8 d) Erc2612(n, s, d) { + admin = msg.sender; + underlying = u; + maturity = m; + } + + /// @param f Address to burn from + /// @param a Amount to burn + function burn(address f, uint256 a) external onlyAdmin(admin) override returns(bool) { + _burn(f, a); + return true; + } + + /// @param t Address recieving the minted amount + /// @param a The amount to mint + function mint(address t, uint256 a) external onlyAdmin(admin) override returns(bool) { + _mint(t, a); + return true; + } + + /// @param a Admin address + modifier onlyAdmin(address a) { + require(msg.sender == a, 'sender must be admin'); + _; + } +} diff --git a/gost/build/marketplace/marketplace.go b/gost/build/marketplace/marketplace.go new file mode 100644 index 0000000..154a28a --- /dev/null +++ b/gost/build/marketplace/marketplace.go @@ -0,0 +1,2083 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package marketplace + +import ( + "math/big" + "strings" + + ethereum "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/event" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription +) + +// MarketPlaceABI is the input ABI used to generate the binding from. +const MarketPlaceABI = "[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"underlying\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"maturity\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"cToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"zcToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"vaultTracker\",\"type\":\"address\"}],\"name\":\"Create\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"underlying\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"maturity\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"zcTarget\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"nTarget\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"CustodialExit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"underlying\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"maturity\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"zcTarget\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"nTarget\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"CustodialInitiate\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"underlying\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"maturity\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"maturityRate\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"matured\",\"type\":\"uint256\"}],\"name\":\"Mature\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"underlying\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"maturity\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"P2pVaultExchange\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"underlying\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"maturity\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"P2pZcTokenExchange\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"underlying\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"maturity\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RedeemVaultInterest\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"underlying\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"maturity\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"RedeemZcToken\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"underlying\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"maturity\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"TransferVaultNotional\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"admin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"u\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"m\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"t\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"a\",\"type\":\"uint256\"}],\"name\":\"burnZcTokenRemovingNotional\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"a\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"m\",\"type\":\"uint256\"}],\"name\":\"cTokenAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"u\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"m\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"c\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"n\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"s\",\"type\":\"string\"},{\"internalType\":\"uint8\",\"name\":\"d\",\"type\":\"uint8\"}],\"name\":\"createMarket\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"u\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"m\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"z\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"n\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"a\",\"type\":\"uint256\"}],\"name\":\"custodialExit\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"u\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"m\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"z\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"n\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"a\",\"type\":\"uint256\"}],\"name\":\"custodialInitiate\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"markets\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"cTokenAddr\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"zcTokenAddr\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"vaultAddr\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"mature\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"u\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"m\",\"type\":\"uint256\"}],\"name\":\"matureMarket\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"maturityRate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"u\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"m\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"t\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"a\",\"type\":\"uint256\"}],\"name\":\"mintZcTokenAddingNotional\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"u\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"m\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"f\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"t\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"a\",\"type\":\"uint256\"}],\"name\":\"p2pVaultExchange\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"u\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"m\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"f\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"t\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"a\",\"type\":\"uint256\"}],\"name\":\"p2pZcTokenExchange\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"u\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"m\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"t\",\"type\":\"address\"}],\"name\":\"redeemVaultInterest\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"u\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"m\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"t\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"a\",\"type\":\"uint256\"}],\"name\":\"redeemZcToken\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"s\",\"type\":\"address\"}],\"name\":\"setSwivelAddress\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"swivel\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"u\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"m\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"t\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"a\",\"type\":\"uint256\"}],\"name\":\"transferVaultNotional\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"u\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"m\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"f\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"a\",\"type\":\"uint256\"}],\"name\":\"transferVaultNotionalFee\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]" + +// MarketPlaceBin is the compiled bytecode used for deploying new contracts. +var MarketPlaceBin = "0x60a060405234801561001057600080fd5b5033606081901b608052615d4e6100406000396000818161042501528181610e470152611dfc0152615d4e6000f3fe60806040523480156200001157600080fd5b50600436106200016c5760003560e01c80638c6b9b4111620000dd578063c86adf7c116200008b578063ef267f2c116200006e578063ef267f2c1462000408578063f851a440146200041f578063f8e51bcb146200044757600080fd5b8063c86adf7c14620003c3578063e5a2aa6214620003f157600080fd5b8063b50a66f711620000c0578063b50a66f7146200037e578063bddbfbe41462000395578063c5ee114d14620003ac57600080fd5b80638c6b9b411462000341578063a11f4856146200035857600080fd5b80633cf9a4e3116200013b5780635db0ae58116200011e5780635db0ae5814620002fc57806365a963aa1462000313578063848f5184146200032a57600080fd5b80633cf9a4e314620002ce5780635292ecf214620002e557600080fd5b8063012b264a146200017157806305e1dc2514620001bc57806317b3bba7146200020057806327ee93be146200028c575b600080fd5b600354620001929073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b62000192620001cd366004620026d0565b73ffffffffffffffffffffffffffffffffffffffff91821660009081526020818152604080832093835292905220541690565b6200025462000211366004620026d0565b600060208181529281526040808220909352908152208054600182015460029092015473ffffffffffffffffffffffffffffffffffffffff918216928216911683565b6040805173ffffffffffffffffffffffffffffffffffffffff94851681529284166020840152921691810191909152606001620001b3565b620002bd6200029d366004620026d0565b600160209081526000928352604080842090915290825290205460ff1681565b6040519015158152602001620001b3565b620002bd620002df36600462002847565b6200045e565b620002bd620002f636600462002847565b620005a9565b620002bd6200030d366004620026d0565b6200072f565b620002bd620003243660046200273c565b62000b38565b620002bd6200033b36600462002797565b62000e43565b620002bd620003523660046200273c565b6200120a565b6200036f62000369366004620026fc565b62001505565b604051908152602001620001b3565b620002bd6200038f36600462002847565b6200169c565b620002bd620003a63660046200273c565b62001947565b6200036f620003bd36600462002847565b62001b31565b6200036f620003d4366004620026d0565b600260209081526000928352604080842090915290825290205481565b620002bd62000402366004620026ac565b62001df8565b620002bd6200041936600462002847565b62001ece565b620001927f000000000000000000000000000000000000000000000000000000000000000081565b620002bd620004583660046200273c565b6200216d565b60035460009073ffffffffffffffffffffffffffffffffffffffff16338114620004cf5760405162461bcd60e51b815260206004820152601e60248201527f73656e646572206d7573742062652053776976656c20636f6e7472616374000060448201526064015b60405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff868116600090815260208181526040808320898452909152908190206002015490517fb326258d00000000000000000000000000000000000000000000000000000000815286831660048201526024810186905291169063b326258d90604401602060405180830381600087803b1580156200055f57600080fd5b505af115801562000574573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200059a91906200288f565b50600191505b50949350505050565b73ffffffffffffffffffffffffffffffffffffffff8481166000908152602081815260408083208784529091528082206002015490517f1779467300000000000000000000000000000000000000000000000000000000815233600482015285841660248201526044810185905291921690631779467390606401602060405180830381600087803b1580156200063f57600080fd5b505af115801562000654573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200067a91906200288f565b620006c85760405162461bcd60e51b815260206004820152601560248201527f7661756c74207472616e73666572206661696c656400000000000000000000006044820152606401620004c6565b6040805133815273ffffffffffffffffffffffffffffffffffffffff858116602083015291810184905285918716907f1d06fe04c445804d7b460d2d5f2fee7c4cc5ba874f3311d2768f849c66cf30989060600160405180910390a3506001949350505050565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260016020908152604080832084845290915281205460ff1615620007b25760405162461bcd60e51b815260206004820152601660248201527f6d61726b657420616c7265616479206d617475726564000000000000000000006044820152606401620004c6565b73ffffffffffffffffffffffffffffffffffffffff8084166000908152602081815260408083208684528252918290206001015482517f204f83f9000000000000000000000000000000000000000000000000000000008152925193169263204f83f9926004808201939291829003018186803b1580156200083357600080fd5b505afa15801562000848573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200086e9190620028b1565b421015620008bf5760405162461bcd60e51b815260206004820152601460248201527f6d61747572697479206e6f7420726561636865640000000000000000000000006044820152606401620004c6565b73ffffffffffffffffffffffffffffffffffffffff80841660009081526020818152604080832086845282528083205481517fbd6d894d00000000000000000000000000000000000000000000000000000000815291519394169263bd6d894d9260048084019391929182900301818787803b1580156200093f57600080fd5b505af115801562000954573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200097a9190620028b1565b73ffffffffffffffffffffffffffffffffffffffff80861660008181526002602081815260408084208a8552825280842087905584845260018083528185208b8652835281852080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016909117905593835282815283832089845281528383209091015483517f6b868d51000000000000000000000000000000000000000000000000000000008152935195965090931693636b868d51936004808501949193918390030190829087803b15801562000a5357600080fd5b505af115801562000a68573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000a8e91906200288f565b62000adc5760405162461bcd60e51b815260206004820152601460248201527f6d61747572697479206e6f7420726561636865640000000000000000000000006044820152606401620004c6565b6040805142815260208101839052849173ffffffffffffffffffffffffffffffffffffffff8716917e80e09d7b4544aa5a923873be1df3e31945593d40cb1c874d99259ec3ac43a4910160405180910390a35060019392505050565b60035460009073ffffffffffffffffffffffffffffffffffffffff1633811462000ba55760405162461bcd60e51b815260206004820152601e60248201527f73656e646572206d7573742062652053776976656c20636f6e747261637400006044820152606401620004c6565b73ffffffffffffffffffffffffffffffffffffffff8781166000908152602081815260408083208a8452909152908190206001015490517f9dc29fac000000000000000000000000000000000000000000000000000000008152878316600482015260248101869052911690639dc29fac90604401602060405180830381600087803b15801562000c3557600080fd5b505af115801562000c4a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000c7091906200288f565b62000cbe5760405162461bcd60e51b815260206004820152601360248201527f7a63546f6b656e206275726e206661696c6564000000000000000000000000006044820152606401620004c6565b73ffffffffffffffffffffffffffffffffffffffff8781166000908152602081815260408083208a8452909152908190206001015490517f40c10f190000000000000000000000000000000000000000000000000000000081528683166004820152602481018690529116906340c10f1990604401602060405180830381600087803b15801562000d4e57600080fd5b505af115801562000d63573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000d8991906200288f565b62000dd75760405162461bcd60e51b815260206004820152601360248201527f7a63546f6b656e206d696e74206661696c6564000000000000000000000000006044820152606401620004c6565b6040805173ffffffffffffffffffffffffffffffffffffffff8781168252868116602083015291810185905287918916907f86ac24e4ee753e21fb51afa847265cb350e500593f3204057e40079c3ef54422906060015b60405180910390a35060019695505050505050565b60007f00000000000000000000000000000000000000000000000000000000000000003373ffffffffffffffffffffffffffffffffffffffff82161462000ecd5760405162461bcd60e51b815260206004820152601460248201527f73656e646572206d7573742062652061646d696e0000000000000000000000006044820152606401620004c6565b60035473ffffffffffffffffffffffffffffffffffffffff1662000f345760405162461bcd60e51b815260206004820152601f60248201527f73776976656c20636f6e74726163742061646472657373206e6f7420736574006044820152606401620004c6565b6000888887878760405162000f4990620025b9565b62000f5995949392919062002936565b604051809103906000f08015801562000f76573d6000803e3d6000fd5b50905060008888600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1660405162000fae90620025c7565b92835273ffffffffffffffffffffffffffffffffffffffff9182166020840152166040820152606001604051809103906000f08015801562000ff4573d6000803e3d6000fd5b50905060405180606001604052808973ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1681526020018273ffffffffffffffffffffffffffffffffffffffff168152506000808c73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008b815260200190815260200160002060008201518160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060208201518160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550905050888a73ffffffffffffffffffffffffffffffffffffffff167f1747a3ed83b35b999b9000df0690f6563f6b016a1cce0c8dfc911866d3b921778a8585604051620011f29392919073ffffffffffffffffffffffffffffffffffffffff93841681529183166020830152909116604082015260600190565b60405180910390a35060019998505050505050505050565b60035460009073ffffffffffffffffffffffffffffffffffffffff16338114620012775760405162461bcd60e51b815260206004820152601e60248201527f73656e646572206d7573742062652053776976656c20636f6e747261637400006044820152606401620004c6565b73ffffffffffffffffffffffffffffffffffffffff8781166000908152602081815260408083208a8452909152908190206001015490517f9dc29fac000000000000000000000000000000000000000000000000000000008152878316600482015260248101869052911690639dc29fac90604401602060405180830381600087803b1580156200130757600080fd5b505af11580156200131c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200134291906200288f565b620013905760405162461bcd60e51b815260206004820152600b60248201527f6275726e206661696c65640000000000000000000000000000000000000000006044820152606401620004c6565b73ffffffffffffffffffffffffffffffffffffffff8781166000908152602081815260408083208a8452909152908190206002015490517f613a28d100000000000000000000000000000000000000000000000000000000815286831660048201526024810186905291169063613a28d190604401602060405180830381600087803b1580156200142057600080fd5b505af115801562001435573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200145b91906200288f565b620014a95760405162461bcd60e51b815260206004820152601660248201527f72656d6f7665206e6f74696f6e616c206661696c6564000000000000000000006044820152606401620004c6565b6040805173ffffffffffffffffffffffffffffffffffffffff8781168252868116602083015291810185905287918916907f219a55ae9a5a1822159d55db6dd594a28be30b02c0d18a71469ef28030b3fb599060600162000e2e565b60035460009073ffffffffffffffffffffffffffffffffffffffff16338114620015725760405162461bcd60e51b815260206004820152601e60248201527f73656e646572206d7573742062652053776976656c20636f6e747261637400006044820152606401620004c6565b73ffffffffffffffffffffffffffffffffffffffff8581166000908152602081815260408083208884529091528082206002015490517f19caf46c0000000000000000000000000000000000000000000000000000000081528684166004820152919216906319caf46c90602401602060405180830381600087803b158015620015fb57600080fd5b505af115801562001610573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620016369190620028b1565b90508373ffffffffffffffffffffffffffffffffffffffff16858773ffffffffffffffffffffffffffffffffffffffff167f646390328280b54978a07e7bd72dd9b3f9515286196024882943a96d5c27987460405160405180910390a495945050505050565b60035460009073ffffffffffffffffffffffffffffffffffffffff16338114620017095760405162461bcd60e51b815260206004820152601e60248201527f73656e646572206d7573742062652053776976656c20636f6e747261637400006044820152606401620004c6565b73ffffffffffffffffffffffffffffffffffffffff868116600090815260208181526040808320898452909152908190206001015490517f9dc29fac000000000000000000000000000000000000000000000000000000008152868316600482015260248101869052911690639dc29fac90604401602060405180830381600087803b1580156200179957600080fd5b505af1158015620017ae573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620017d491906200288f565b620018225760405162461bcd60e51b815260206004820152600b60248201527f6275726e206661696c65640000000000000000000000000000000000000000006044820152606401620004c6565b73ffffffffffffffffffffffffffffffffffffffff868116600090815260208181526040808320898452909152908190206002015490517f613a28d100000000000000000000000000000000000000000000000000000000815286831660048201526024810186905291169063613a28d190604401602060405180830381600087803b158015620018b257600080fd5b505af1158015620018c7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620018ed91906200288f565b6200193b5760405162461bcd60e51b815260206004820152601660248201527f72656d6f7665206e6f74696f6e616c206661696c6564000000000000000000006044820152606401620004c6565b50600195945050505050565b60035460009073ffffffffffffffffffffffffffffffffffffffff16338114620019b45760405162461bcd60e51b815260206004820152601e60248201527f73656e646572206d7573742062652053776976656c20636f6e747261637400006044820152606401620004c6565b73ffffffffffffffffffffffffffffffffffffffff8781166000908152602081815260408083208a8452909152908190206002015490517f177946730000000000000000000000000000000000000000000000000000000081528783166004820152868316602482015260448101869052911690631779467390606401602060405180830381600087803b15801562001a4c57600080fd5b505af115801562001a61573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001a8791906200288f565b62001ad55760405162461bcd60e51b815260206004820152601860248201527f7472616e73666572206e6f74696f6e616c206661696c656400000000000000006044820152606401620004c6565b6040805173ffffffffffffffffffffffffffffffffffffffff8781168252868116602083015291810185905287918916907f31d266c2b6075063717026bd27ba8bb527366457893dc211091b2e1d9713f1529060600162000e2e565b60035460009073ffffffffffffffffffffffffffffffffffffffff1633811462001b9e5760405162461bcd60e51b815260206004820152601e60248201527f73656e646572206d7573742062652053776976656c20636f6e747261637400006044820152606401620004c6565b73ffffffffffffffffffffffffffffffffffffffff8087166000818152602081815260408083208a845282528083208151606081018352815487168152600180830154881682860152600290920154909616868301529383529281528282208983529052205460ff168062001c675762001c1988886200072f565b62001c675760405162461bcd60e51b815260206004820152601b60248201527f6661696c656420746f206d617475726520746865206d61726b657400000000006044820152606401620004c6565b60208201516040517f9dc29fac00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff88811660048301526024820188905290911690639dc29fac90604401602060405180830381600087803b15801562001cde57600080fd5b505af115801562001cf3573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001d1991906200288f565b62001d675760405162461bcd60e51b815260206004820152600e60248201527f636f756c64206e6f74206275726e0000000000000000000000000000000000006044820152606401620004c6565b8573ffffffffffffffffffffffffffffffffffffffff16878973ffffffffffffffffffffffffffffffffffffffff167f49dc20daa9f95793b82245100affbf87ad23d1761bdef94975542564f4023e458860405162001dc891815260200190565b60405180910390a48062001de1578493505050620005a0565b62001dee88888762002468565b93505050620005a0565b60007f00000000000000000000000000000000000000000000000000000000000000003373ffffffffffffffffffffffffffffffffffffffff82161462001e825760405162461bcd60e51b815260206004820152601460248201527f73656e646572206d7573742062652061646d696e0000000000000000000000006044820152606401620004c6565b6003805473ffffffffffffffffffffffffffffffffffffffff85167fffffffffffffffffffffffff00000000000000000000000000000000000000009091161790556001915050919050565b60035460009073ffffffffffffffffffffffffffffffffffffffff1633811462001f3b5760405162461bcd60e51b815260206004820152601e60248201527f73656e646572206d7573742062652053776976656c20636f6e747261637400006044820152606401620004c6565b73ffffffffffffffffffffffffffffffffffffffff868116600090815260208181526040808320898452909152908190206001015490517f40c10f190000000000000000000000000000000000000000000000000000000081528683166004820152602481018690529116906340c10f1990604401602060405180830381600087803b15801562001fcb57600080fd5b505af115801562001fe0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200200691906200288f565b620020545760405162461bcd60e51b815260206004820152601360248201527f6d696e74207a63546f6b656e206661696c6564000000000000000000000000006044820152606401620004c6565b73ffffffffffffffffffffffffffffffffffffffff868116600090815260208181526040808320898452909152908190206002015490517fa01cfffb00000000000000000000000000000000000000000000000000000000815286831660048201526024810186905291169063a01cfffb90604401602060405180830381600087803b158015620020e457600080fd5b505af1158015620020f9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200211f91906200288f565b6200193b5760405162461bcd60e51b815260206004820152601360248201527f616464206e6f74696f6e616c206661696c6564000000000000000000000000006044820152606401620004c6565b60035460009073ffffffffffffffffffffffffffffffffffffffff16338114620021da5760405162461bcd60e51b815260206004820152601e60248201527f73656e646572206d7573742062652053776976656c20636f6e747261637400006044820152606401620004c6565b73ffffffffffffffffffffffffffffffffffffffff8781166000908152602081815260408083208a8452909152908190206001015490517f40c10f190000000000000000000000000000000000000000000000000000000081528783166004820152602481018690529116906340c10f1990604401602060405180830381600087803b1580156200226a57600080fd5b505af11580156200227f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620022a591906200288f565b620022f35760405162461bcd60e51b815260206004820152600b60248201527f6d696e74206661696c65640000000000000000000000000000000000000000006044820152606401620004c6565b73ffffffffffffffffffffffffffffffffffffffff8781166000908152602081815260408083208a8452909152908190206002015490517fa01cfffb00000000000000000000000000000000000000000000000000000000815286831660048201526024810186905291169063a01cfffb90604401602060405180830381600087803b1580156200238357600080fd5b505af115801562002398573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620023be91906200288f565b6200240c5760405162461bcd60e51b815260206004820152601360248201527f616464206e6f74696f6e616c206661696c6564000000000000000000000000006044820152606401620004c6565b6040805173ffffffffffffffffffffffffffffffffffffffff8781168252868116602083015291810185905287918916907f8dad4d03bd4209aa6dc2bea238510998bf39bb034bc9c20d52f0bd241fc0c5169060600162000e2e565b73ffffffffffffffffffffffffffffffffffffffff808416600081815260026020908152604080832087845282528083205493835282825280832087845282528083205481517fbd6d894d0000000000000000000000000000000000000000000000000000000081529151939586956a52b7d2dcc80cd2e4000000959094929091169263bd6d894d92600480830193919282900301818987803b1580156200250f57600080fd5b505af115801562002524573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200254a9190620028b1565b62002561906a52b7d2dcc80cd2e4000000620029ec565b6200256d9190620029b2565b62002579919062002a2c565b905060006a52b7d2dcc80cd2e4000000620025958584620029ec565b620025a19190620029b2565b9050620025af818562002997565b9695505050505050565b6119328062002aa583390190565b61194280620043d783390190565b803573ffffffffffffffffffffffffffffffffffffffff81168114620025fa57600080fd5b919050565b600082601f83011262002610578081fd5b813567ffffffffffffffff808211156200262e576200262e62002a75565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190828211818310171562002677576200267762002a75565b8160405283815286602085880101111562002690578485fd5b8360208701602083013792830160200193909352509392505050565b600060208284031215620026be578081fd5b620026c982620025d5565b9392505050565b60008060408385031215620026e3578081fd5b620026ee83620025d5565b946020939093013593505050565b60008060006060848603121562002711578081fd5b6200271c84620025d5565b9250602084013591506200273360408501620025d5565b90509250925092565b600080600080600060a0868803121562002754578081fd5b6200275f86620025d5565b9450602086013593506200277660408701620025d5565b92506200278660608701620025d5565b949793965091946080013592915050565b60008060008060008060c08789031215620027b0578081fd5b620027bb87620025d5565b955060208701359450620027d260408801620025d5565b9350606087013567ffffffffffffffff80821115620027ef578283fd5b620027fd8a838b01620025ff565b9450608089013591508082111562002813578283fd5b506200282289828a01620025ff565b92505060a087013560ff8116811462002839578182fd5b809150509295509295509295565b600080600080608085870312156200285d578384fd5b6200286885620025d5565b9350602085013592506200287f60408601620025d5565b9396929550929360600135925050565b600060208284031215620028a1578081fd5b81518015158114620026c9578182fd5b600060208284031215620028c3578081fd5b5051919050565b60008151808452815b81811015620028f157602081850181015186830182015201620028d3565b81811115620029035782602083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b73ffffffffffffffffffffffffffffffffffffffff8616815284602082015260a0604082015260006200296d60a0830186620028ca565b8281036060840152620029818186620028ca565b91505060ff831660808301529695505050505050565b60008219821115620029ad57620029ad62002a46565b500190565b600082620029e7577f4e487b710000000000000000000000000000000000000000000000000000000081526012600452602481fd5b500490565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048311821515161562002a275762002a2762002a46565b500290565b60008282101562002a415762002a4162002a46565b500390565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fdfe6101006040523480156200001257600080fd5b506040516200193238038062001932833981016040819052620000359162000296565b8282828282828260049080519060200190620000539291906200013d565b508151620000699060059060208501906200013d565b5080600260006101000a81548160ff021916908360ff160217905550505050620000ba83604051806040016040528060018152602001603160f81b8152504630620000e660201b62000ab61760201c565b60805250505033606090811b60a0529490941b6001600160601b03191660c052505060e0525062000394565b8351602094850120835193850193909320604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f815295860194909452928401929092526060830152608082015260a0902090565b8280546200014b9062000341565b90600052602060002090601f0160209004810192826200016f5760008555620001ba565b82601f106200018a57805160ff1916838001178555620001ba565b82800160010185558215620001ba579182015b82811115620001ba5782518255916020019190600101906200019d565b50620001c8929150620001cc565b5090565b5b80821115620001c85760008155600101620001cd565b600082601f830112620001f4578081fd5b81516001600160401b03808211156200021157620002116200037e565b604051601f8301601f19908116603f011681019082821181831017156200023c576200023c6200037e565b8160405283815260209250868385880101111562000258578485fd5b8491505b838210156200027b57858201830151818301840152908201906200025c565b838211156200028c57848385830101525b9695505050505050565b600080600080600060a08688031215620002ae578081fd5b85516001600160a01b0381168114620002c5578182fd5b6020870151604088015191965094506001600160401b0380821115620002e9578283fd5b620002f789838a01620001e3565b945060608801519150808211156200030d578283fd5b506200031c88828901620001e3565b925050608086015160ff8116811462000333578182fd5b809150509295509295909350565b600181811c908216806200035657607f821691505b602082108114156200037857634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052604160045260246000fd5b60805160a05160601c60c05160601c60e051611549620003e960003960006101b30152600061023201526000818161039701528181610597015261065a015260008181610315015261093101526115496000f3fe608060405234801561001057600080fd5b50600436106101515760003560e01c806370a08231116100cd578063a9059cbb11610081578063d505accf11610066578063d505accf14610337578063dd62ed3e1461034c578063f851a4401461039257600080fd5b8063a9059cbb146102fd578063c2fb26a61461031057600080fd5b806395d89b41116100b257806395d89b41146102cf5780639dc29fac146102d7578063a457c2d7146102ea57600080fd5b806370a08231146102795780637ecebe00146102af57600080fd5b806323b872dd116101245780633950935111610109578063395093511461020757806340c10f191461021a5780636f307dc31461022d57600080fd5b806323b872dd146101d5578063313ce567146101e857600080fd5b806306fdde0314610156578063095ea7b31461017457806318160ddd14610197578063204f83f9146101ae575b600080fd5b61015e6103b9565b60405161016b91906113b7565b60405180910390f35b61018761018236600461138e565b610447565b604051901515815260200161016b565b6101a060035481565b60405190815260200161016b565b6101a07f000000000000000000000000000000000000000000000000000000000000000081565b6101876101e33660046112e2565b61045d565b6002546101f59060ff1681565b60405160ff909116815260200161016b565b61018761021536600461138e565b61054f565b61018761022836600461138e565b610593565b6102547f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161016b565b6101a061028736600461128f565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020819052604090205490565b6101a06102bd36600461128f565b60066020526000908152604090205481565b61015e610649565b6101876102e536600461138e565b610656565b6101876102f836600461138e565b610702565b61018761030b36600461138e565b6107d1565b6101a07f000000000000000000000000000000000000000000000000000000000000000081565b61034a61034536600461131d565b6107de565b005b6101a061035a3660046112b0565b73ffffffffffffffffffffffffffffffffffffffff918216600090815260016020908152604080832093909416825291909152205490565b6102547f000000000000000000000000000000000000000000000000000000000000000081565b600480546103c690611457565b80601f01602080910402602001604051908101604052809291908181526020018280546103f290611457565b801561043f5780601f106104145761010080835404028352916020019161043f565b820191906000526020600020905b81548152906001019060200180831161042257829003601f168201915b505050505081565b6000610454338484610b0d565b50600192915050565b600061046a848484610cc2565b73ffffffffffffffffffffffffffffffffffffffff8416600090815260016020908152604080832033845290915290205482811015610530576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602760248201527f6572633230207472616e7366657220616d6f756e74206578636565647320616c60448201527f6c6f77616e63650000000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b610544853361053f8685611440565b610b0d565b506001949350505050565b33600081815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff87168452909152812054909161045491859061053f908690611428565b60007f00000000000000000000000000000000000000000000000000000000000000003373ffffffffffffffffffffffffffffffffffffffff821614610635576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f73656e646572206d7573742062652061646d696e0000000000000000000000006044820152606401610527565b61063f8484610f7e565b5060019392505050565b600580546103c690611457565b60007f00000000000000000000000000000000000000000000000000000000000000003373ffffffffffffffffffffffffffffffffffffffff8216146106f8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f73656e646572206d7573742062652061646d696e0000000000000000000000006044820152606401610527565b61063f848461109e565b33600090815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff86168452909152812054828110156107c2576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f65726332302064656372656173656420616c6c6f77616e63652062656c6f772060448201527f7a65726f000000000000000000000000000000000000000000000000000000006064820152608401610527565b61063f338561053f8685611440565b6000610454338484610cc2565b42841015610848576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f65726332363132206578706972656420646561646c696e6500000000000000006044820152606401610527565b73ffffffffffffffffffffffffffffffffffffffff871660009081526006602052604081208054610909918a918a918a919086610884836114ab565b90915550604080517f80772249b4aef1688b30651778f4249b05cb73b517d98482439b9d8999b3060260208083019190915273ffffffffffffffffffffffffffffffffffffffff96871682840152949095166060860152608085019290925260a084015260c08084018a90528151808503909101815260e09093019052815191012090565b6040517f190100000000000000000000000000000000000000000000000000000000000081527f0000000000000000000000000000000000000000000000000000000000000000600282015260228101829052604290209091506000906040805160008082526020820180845284905260ff89169282019290925260608101879052608081018690529192509060019060a0016020604051602081039080840390855afa1580156109be573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff811615801590610a3957508973ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16145b610a9f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f6572633236313220696e76616c6964207369676e6174757265000000000000006044820152606401610527565b610aaa8a8a8a610b0d565b50505050505050505050565b8351602094850120835193850193909320604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f815295860194909452928401929092526060830152608082015260a0902090565b73ffffffffffffffffffffffffffffffffffffffff8316610bb0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f657263323020617070726f76652066726f6d20746865207a65726f206164647260448201527f65737300000000000000000000000000000000000000000000000000000000006064820152608401610527565b73ffffffffffffffffffffffffffffffffffffffff8216610c53576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f657263323020617070726f766520746f20746865207a65726f2061646472657360448201527f73000000000000000000000000000000000000000000000000000000000000006064820152608401610527565b73ffffffffffffffffffffffffffffffffffffffff83811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591015b60405180910390a3505050565b73ffffffffffffffffffffffffffffffffffffffff8316610d64576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f6572633230207472616e736665722066726f6d20746865207a65726f2061646460448201527f72657373000000000000000000000000000000000000000000000000000000006064820152608401610527565b73ffffffffffffffffffffffffffffffffffffffff8216610e07576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f6572633230207472616e7366657220746f20746865207a65726f20616464726560448201527f73730000000000000000000000000000000000000000000000000000000000006064820152608401610527565b73ffffffffffffffffffffffffffffffffffffffff831660009081526020819052604090205481811015610ebd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f6572633230207472616e7366657220616d6f756e74206578636565647320626160448201527f6c616e63650000000000000000000000000000000000000000000000000000006064820152608401610527565b610ec78282611440565b73ffffffffffffffffffffffffffffffffffffffff8086166000908152602081905260408082209390935590851681529081208054849290610f0a908490611428565b925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84604051610f7091815260200190565b60405180910390a350505050565b73ffffffffffffffffffffffffffffffffffffffff8216610ffb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f6572633230206d696e7420746f20746865207a65726f206164647265737300006044820152606401610527565b806003600082825461100d9190611428565b909155505073ffffffffffffffffffffffffffffffffffffffff821660009081526020819052604081208054839290611047908490611428565b909155505060405181815273ffffffffffffffffffffffffffffffffffffffff8316906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a35050565b73ffffffffffffffffffffffffffffffffffffffff821661111b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f6572633230206275726e2066726f6d20746865207a65726f20616464726573736044820152606401610527565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260208190526040902054818110156111d1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f6572633230206275726e20616d6f756e7420657863656564732062616c616e6360448201527f65000000000000000000000000000000000000000000000000000000000000006064820152608401610527565b6111db8282611440565b73ffffffffffffffffffffffffffffffffffffffff841660009081526020819052604081209190915560038054849290611216908490611440565b909155505060405182815260009073ffffffffffffffffffffffffffffffffffffffff8516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90602001610cb5565b803573ffffffffffffffffffffffffffffffffffffffff8116811461128a57600080fd5b919050565b6000602082840312156112a0578081fd5b6112a982611266565b9392505050565b600080604083850312156112c2578081fd5b6112cb83611266565b91506112d960208401611266565b90509250929050565b6000806000606084860312156112f6578081fd5b6112ff84611266565b925061130d60208501611266565b9150604084013590509250925092565b600080600080600080600060e0888a031215611337578283fd5b61134088611266565b965061134e60208901611266565b95506040880135945060608801359350608088013560ff81168114611371578384fd5b9699959850939692959460a0840135945060c09093013592915050565b600080604083850312156113a0578182fd5b6113a983611266565b946020939093013593505050565b6000602080835283518082850152825b818110156113e3578581018301518582016040015282016113c7565b818111156113f45783604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016929092016040019392505050565b6000821982111561143b5761143b6114e4565b500190565b600082821015611452576114526114e4565b500390565b600181811c9082168061146b57607f821691505b602082108114156114a5577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8214156114dd576114dd6114e4565b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fdfea2646970667358221220d800b92df8c6048dd793473ca8313793ca1656ca285d3b8deb63563c217aa06564736f6c634300080400336101006040523480156200001257600080fd5b50604051620019423803806200194283398101604081905262000035916200007f565b33606090811b60805260e0939093526001600160601b031991831b821660a05290911b1660c052620000bf565b80516001600160a01b03811681146200007a57600080fd5b919050565b60008060006060848603121562000094578283fd5b83519250620000a66020850162000062565b9150620000b66040850162000062565b90509250925092565b60805160601c60a05160601c60c05160601c60e0516117d86200016a600039600081816101920152610e4e01526000818160f40152818161138001526115950152600081816102a40152818161047c0152818161089701528181610b7801528181610f400152818161107101526113e90152600081816102cb015281816102f10152818161077f01528181610a1d01528181610d4101528181610fcf015261129801526117d86000f3fe608060405234801561001057600080fd5b50600436106100ea5760003560e01c80636392a51f1161008c578063a622ee7c11610066578063a622ee7c14610242578063b326258d1461028c578063b7dd34831461029f578063f851a440146102c657600080fd5b80636392a51f146101d45780636b868d5114610227578063a01cfffb1461022f57600080fd5b806319caf46c116100c857806319caf46c1461017a578063204f83f91461018d578063454c87b3146101b4578063613a28d1146101c157600080fd5b8063012b264a146100ef57806311554c43146101405780631779467314610157575b600080fd5b6101167f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b61014960025481565b604051908152602001610137565b61016a610165366004611652565b6102ed565b6040519015158152602001610137565b610149610188366004611631565b61077b565b6101497f000000000000000000000000000000000000000000000000000000000000000081565b60015461016a9060ff1681565b61016a6101cf36600461168d565b610a19565b6102126101e2366004611631565b73ffffffffffffffffffffffffffffffffffffffff16600090815260208190526040902080546001909101549091565b60408051928352602083019190915201610137565b61016a610d3d565b61016a61023d36600461168d565b610fcb565b610271610250366004611631565b60006020819052908152604090208054600182015460029092015490919083565b60408051938452602084019290925290820152606001610137565b61016a61029a36600461168d565b611294565b6101167f000000000000000000000000000000000000000000000000000000000000000081565b6101167f000000000000000000000000000000000000000000000000000000000000000081565b60007f00000000000000000000000000000000000000000000000000000000000000003373ffffffffffffffffffffffffffffffffffffffff821614610394576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f73656e646572206d7573742062652061646d696e00000000000000000000000060448201526064015b60405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff808616600090815260208181526040808320815160608082018452825482526001808401548387015260029384015483860152968b16865285855294839020835195860184528054865295860154938501939093529390930154928201929092528151851115610475576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f616d6f756e74206578636565647320617661696c61626c652062616c616e6365604482015260640161038b565b60008060007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663bd6d894d6040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156104e257600080fd5b505af11580156104f6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061051a91906116b6565b60015490915060ff161561056d576a52b7d2dcc80cd2e400000085604001516002546a52b7d2dcc80cd2e4000000610552919061171f565b61055c91906116e6565b610566919061175c565b92506105a0565b60408501516a52b7d2dcc80cd2e400000090610589838361171f565b61059391906116e6565b61059d919061175c565b92505b84516a52b7d2dcc80cd2e4000000906105b9908561171f565b6105c391906116e6565b915081856020018181516105d791906116ce565b9052508451889086906105eb90839061175c565b905250604080860182815273ffffffffffffffffffffffffffffffffffffffff8c166000908152602081815292902087518155918701516001830155516002909101558351156107105760015460009060ff1615610688576a52b7d2dcc80cd2e400000085604001516002546a52b7d2dcc80cd2e400000061066d919061171f565b61067791906116e6565b610681919061175c565b93506106bb565b60408501516a52b7d2dcc80cd2e4000000906106a4848361171f565b6106ae91906116e6565b6106b8919061175c565b93505b84516a52b7d2dcc80cd2e4000000906106d4908661171f565b6106de91906116e6565b905080856020018181516106f291906116ce565b9052508451899086906107069083906116ce565b9052506107269050565b878460000181815161072291906116ce565b9052505b604080850191825273ffffffffffffffffffffffffffffffffffffffff8a1660009081526020818152919020855181559401516001808601919091559051600290940193909355509093505050509392505050565b60007f00000000000000000000000000000000000000000000000000000000000000003373ffffffffffffffffffffffffffffffffffffffff82161461081d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f73656e646572206d7573742062652061646d696e000000000000000000000000604482015260640161038b565b73ffffffffffffffffffffffffffffffffffffffff80841660009081526020818152604080832081516060810183528154815260018201548185018190526002909201548184015282517fbd6d894d00000000000000000000000000000000000000000000000000000000815292519095919493849384937f0000000000000000000000000000000000000000000000000000000000000000169263bd6d894d9260048084019391929182900301818787803b1580156108dc57600080fd5b505af11580156108f0573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061091491906116b6565b60015490915060ff1615610967576a52b7d2dcc80cd2e400000085604001516002546a52b7d2dcc80cd2e400000061094c919061171f565b61095691906116e6565b610960919061175c565b925061099a565b60408501516a52b7d2dcc80cd2e400000090610983838361171f565b61098d91906116e6565b610997919061175c565b92505b84516a52b7d2dcc80cd2e4000000906109b3908561171f565b6109bd91906116e6565b604080870183815260006020808a0182815273ffffffffffffffffffffffffffffffffffffffff8e168352908290529290208851815591516001830155516002909101559150610a0d82856116ce565b98975050505050505050565b60007f00000000000000000000000000000000000000000000000000000000000000003373ffffffffffffffffffffffffffffffffffffffff821614610abb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f73656e646572206d7573742062652061646d696e000000000000000000000000604482015260640161038b565b73ffffffffffffffffffffffffffffffffffffffff8416600090815260208181526040918290208251606081018452815480825260018301549382019390935260029091015492810192909252841115610b71576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f616d6f756e742065786365656473207661756c742062616c616e636500000000604482015260640161038b565b60008060007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663bd6d894d6040518163ffffffff1660e01b8152600401602060405180830381600087803b158015610bde57600080fd5b505af1158015610bf2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c1691906116b6565b60015490915060ff1615610c69576a52b7d2dcc80cd2e400000084604001516002546a52b7d2dcc80cd2e4000000610c4e919061171f565b610c5891906116e6565b610c62919061175c565b9250610c9c565b60408401516a52b7d2dcc80cd2e400000090610c85838361171f565b610c8f91906116e6565b610c99919061175c565b92505b83516a52b7d2dcc80cd2e400000090610cb5908561171f565b610cbf91906116e6565b91508184602001818151610cd391906116ce565b905250835187908590610ce790839061175c565b905250604080850191825273ffffffffffffffffffffffffffffffffffffffff89166000908152602081815291902085518155940151600180860191909155905160029094019390935550909250505092915050565b60007f00000000000000000000000000000000000000000000000000000000000000003373ffffffffffffffffffffffffffffffffffffffff821614610ddf576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f73656e646572206d7573742062652061646d696e000000000000000000000000604482015260640161038b565b60015460ff1615610e4c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f616c7265616479206d6174757265640000000000000000000000000000000000604482015260640161038b565b7f0000000000000000000000000000000000000000000000000000000000000000421015610ed6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f6d6174757269747920686173206e6f74206265656e2072656163686564000000604482015260640161038b565b600180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001681179055604080517fbd6d894d000000000000000000000000000000000000000000000000000000008152905173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169163bd6d894d9160048083019260209291908290030181600087803b158015610f8857600080fd5b505af1158015610f9c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fc091906116b6565b600255600191505090565b60007f00000000000000000000000000000000000000000000000000000000000000003373ffffffffffffffffffffffffffffffffffffffff82161461106d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f73656e646572206d7573742062652061646d696e000000000000000000000000604482015260640161038b565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663bd6d894d6040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156110d757600080fd5b505af11580156110eb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061110f91906116b6565b73ffffffffffffffffffffffffffffffffffffffff8616600090815260208181526040918290208251606081018452815480825260018301549382019390935260029091015492810192909252919250901561124357600154600090819060ff16156111ba576a52b7d2dcc80cd2e400000083604001516002546a52b7d2dcc80cd2e400000061119f919061171f565b6111a991906116e6565b6111b3919061175c565b91506111ed565b60408301516a52b7d2dcc80cd2e4000000906111d6868361171f565b6111e091906116e6565b6111ea919061175c565b91505b82516a52b7d2dcc80cd2e400000090611206908461171f565b61121091906116e6565b9050808360200181815161122491906116ce565b9052508251879084906112389083906116ce565b905250611247915050565b8481525b604080820192835273ffffffffffffffffffffffffffffffffffffffff87166000908152602081815291902082518155910151600180830191909155915160029091015591505092915050565b60007f00000000000000000000000000000000000000000000000000000000000000003373ffffffffffffffffffffffffffffffffffffffff821614611336576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f73656e646572206d7573742062652061646d696e000000000000000000000000604482015260640161038b565b73ffffffffffffffffffffffffffffffffffffffff8085166000908152602081815260408083208151606080820184528254825260018084015483870152600293840154838601527f0000000000000000000000000000000000000000000000000000000000000000909716865285855294839020835195860184528054865295860154938501939093529390930154928201929092528151859083906113de90839061175c565b9150818152505060007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663bd6d894d6040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561144f57600080fd5b505af1158015611463573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061148791906116b6565b9050600080828460400151146115675760408401511561155f5760015460ff16156114f1576a52b7d2dcc80cd2e400000084604001516002546a52b7d2dcc80cd2e40000006114d6919061171f565b6114e091906116e6565b6114ea919061175c565b9150611524565b60408401516a52b7d2dcc80cd2e40000009061150d858361171f565b61151791906116e6565b611521919061175c565b91505b83516a52b7d2dcc80cd2e40000009061153d908461171f565b61154791906116e6565b9050808460200181815161155b91906116ce565b9052505b604084018390525b878460000181815161157991906116ce565b905250505073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000008116600090815260208181526040808320865181558287015160018083019190915596820151600291820155938b168352918290208651815590860151818601559401519301929092559250505092915050565b803573ffffffffffffffffffffffffffffffffffffffff8116811461162c57600080fd5b919050565b600060208284031215611642578081fd5b61164b82611608565b9392505050565b600080600060608486031215611666578182fd5b61166f84611608565b925061167d60208501611608565b9150604084013590509250925092565b6000806040838503121561169f578182fd5b6116a883611608565b946020939093013593505050565b6000602082840312156116c7578081fd5b5051919050565b600082198211156116e1576116e1611773565b500190565b60008261171a577f4e487b710000000000000000000000000000000000000000000000000000000081526012600452602481fd5b500490565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048311821515161561175757611757611773565b500290565b60008282101561176e5761176e611773565b500390565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fdfea264697066735822122095fdafb69b51d8f2b50aa69920ca732a455288c23d96942686f7fdabba389c0364736f6c63430008040033a264697066735822122068ace4fc5b89030958360053e93d080af1c25bc657bcbc3707cf8f9a5e915ffa64736f6c63430008040033" + +// DeployMarketPlace deploys a new Ethereum contract, binding an instance of MarketPlace to it. +func DeployMarketPlace(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *MarketPlace, error) { + parsed, err := abi.JSON(strings.NewReader(MarketPlaceABI)) + if err != nil { + return common.Address{}, nil, nil, err + } + + address, tx, contract, err := bind.DeployContract(auth, parsed, common.FromHex(MarketPlaceBin), backend) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &MarketPlace{MarketPlaceCaller: MarketPlaceCaller{contract: contract}, MarketPlaceTransactor: MarketPlaceTransactor{contract: contract}, MarketPlaceFilterer: MarketPlaceFilterer{contract: contract}}, nil +} + +// MarketPlace is an auto generated Go binding around an Ethereum contract. +type MarketPlace struct { + MarketPlaceCaller // Read-only binding to the contract + MarketPlaceTransactor // Write-only binding to the contract + MarketPlaceFilterer // Log filterer for contract events +} + +// MarketPlaceCaller is an auto generated read-only Go binding around an Ethereum contract. +type MarketPlaceCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// MarketPlaceTransactor is an auto generated write-only Go binding around an Ethereum contract. +type MarketPlaceTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// MarketPlaceFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type MarketPlaceFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// MarketPlaceSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type MarketPlaceSession struct { + Contract *MarketPlace // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// MarketPlaceCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type MarketPlaceCallerSession struct { + Contract *MarketPlaceCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// MarketPlaceTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type MarketPlaceTransactorSession struct { + Contract *MarketPlaceTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// MarketPlaceRaw is an auto generated low-level Go binding around an Ethereum contract. +type MarketPlaceRaw struct { + Contract *MarketPlace // Generic contract binding to access the raw methods on +} + +// MarketPlaceCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type MarketPlaceCallerRaw struct { + Contract *MarketPlaceCaller // Generic read-only contract binding to access the raw methods on +} + +// MarketPlaceTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type MarketPlaceTransactorRaw struct { + Contract *MarketPlaceTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewMarketPlace creates a new instance of MarketPlace, bound to a specific deployed contract. +func NewMarketPlace(address common.Address, backend bind.ContractBackend) (*MarketPlace, error) { + contract, err := bindMarketPlace(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &MarketPlace{MarketPlaceCaller: MarketPlaceCaller{contract: contract}, MarketPlaceTransactor: MarketPlaceTransactor{contract: contract}, MarketPlaceFilterer: MarketPlaceFilterer{contract: contract}}, nil +} + +// NewMarketPlaceCaller creates a new read-only instance of MarketPlace, bound to a specific deployed contract. +func NewMarketPlaceCaller(address common.Address, caller bind.ContractCaller) (*MarketPlaceCaller, error) { + contract, err := bindMarketPlace(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &MarketPlaceCaller{contract: contract}, nil +} + +// NewMarketPlaceTransactor creates a new write-only instance of MarketPlace, bound to a specific deployed contract. +func NewMarketPlaceTransactor(address common.Address, transactor bind.ContractTransactor) (*MarketPlaceTransactor, error) { + contract, err := bindMarketPlace(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &MarketPlaceTransactor{contract: contract}, nil +} + +// NewMarketPlaceFilterer creates a new log filterer instance of MarketPlace, bound to a specific deployed contract. +func NewMarketPlaceFilterer(address common.Address, filterer bind.ContractFilterer) (*MarketPlaceFilterer, error) { + contract, err := bindMarketPlace(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &MarketPlaceFilterer{contract: contract}, nil +} + +// bindMarketPlace binds a generic wrapper to an already deployed contract. +func bindMarketPlace(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := abi.JSON(strings.NewReader(MarketPlaceABI)) + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_MarketPlace *MarketPlaceRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _MarketPlace.Contract.MarketPlaceCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_MarketPlace *MarketPlaceRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _MarketPlace.Contract.MarketPlaceTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_MarketPlace *MarketPlaceRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _MarketPlace.Contract.MarketPlaceTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_MarketPlace *MarketPlaceCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _MarketPlace.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_MarketPlace *MarketPlaceTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _MarketPlace.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_MarketPlace *MarketPlaceTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _MarketPlace.Contract.contract.Transact(opts, method, params...) +} + +// Admin is a free data retrieval call binding the contract method 0xf851a440. +// +// Solidity: function admin() view returns(address) +func (_MarketPlace *MarketPlaceCaller) Admin(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _MarketPlace.contract.Call(opts, &out, "admin") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// Admin is a free data retrieval call binding the contract method 0xf851a440. +// +// Solidity: function admin() view returns(address) +func (_MarketPlace *MarketPlaceSession) Admin() (common.Address, error) { + return _MarketPlace.Contract.Admin(&_MarketPlace.CallOpts) +} + +// Admin is a free data retrieval call binding the contract method 0xf851a440. +// +// Solidity: function admin() view returns(address) +func (_MarketPlace *MarketPlaceCallerSession) Admin() (common.Address, error) { + return _MarketPlace.Contract.Admin(&_MarketPlace.CallOpts) +} + +// CTokenAddress is a free data retrieval call binding the contract method 0x05e1dc25. +// +// Solidity: function cTokenAddress(address a, uint256 m) view returns(address) +func (_MarketPlace *MarketPlaceCaller) CTokenAddress(opts *bind.CallOpts, a common.Address, m *big.Int) (common.Address, error) { + var out []interface{} + err := _MarketPlace.contract.Call(opts, &out, "cTokenAddress", a, m) + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// CTokenAddress is a free data retrieval call binding the contract method 0x05e1dc25. +// +// Solidity: function cTokenAddress(address a, uint256 m) view returns(address) +func (_MarketPlace *MarketPlaceSession) CTokenAddress(a common.Address, m *big.Int) (common.Address, error) { + return _MarketPlace.Contract.CTokenAddress(&_MarketPlace.CallOpts, a, m) +} + +// CTokenAddress is a free data retrieval call binding the contract method 0x05e1dc25. +// +// Solidity: function cTokenAddress(address a, uint256 m) view returns(address) +func (_MarketPlace *MarketPlaceCallerSession) CTokenAddress(a common.Address, m *big.Int) (common.Address, error) { + return _MarketPlace.Contract.CTokenAddress(&_MarketPlace.CallOpts, a, m) +} + +// Markets is a free data retrieval call binding the contract method 0x17b3bba7. +// +// Solidity: function markets(address , uint256 ) view returns(address cTokenAddr, address zcTokenAddr, address vaultAddr) +func (_MarketPlace *MarketPlaceCaller) Markets(opts *bind.CallOpts, arg0 common.Address, arg1 *big.Int) (struct { + CTokenAddr common.Address + ZcTokenAddr common.Address + VaultAddr common.Address +}, error) { + var out []interface{} + err := _MarketPlace.contract.Call(opts, &out, "markets", arg0, arg1) + + outstruct := new(struct { + CTokenAddr common.Address + ZcTokenAddr common.Address + VaultAddr common.Address + }) + if err != nil { + return *outstruct, err + } + + outstruct.CTokenAddr = out[0].(common.Address) + outstruct.ZcTokenAddr = out[1].(common.Address) + outstruct.VaultAddr = out[2].(common.Address) + + return *outstruct, err + +} + +// Markets is a free data retrieval call binding the contract method 0x17b3bba7. +// +// Solidity: function markets(address , uint256 ) view returns(address cTokenAddr, address zcTokenAddr, address vaultAddr) +func (_MarketPlace *MarketPlaceSession) Markets(arg0 common.Address, arg1 *big.Int) (struct { + CTokenAddr common.Address + ZcTokenAddr common.Address + VaultAddr common.Address +}, error) { + return _MarketPlace.Contract.Markets(&_MarketPlace.CallOpts, arg0, arg1) +} + +// Markets is a free data retrieval call binding the contract method 0x17b3bba7. +// +// Solidity: function markets(address , uint256 ) view returns(address cTokenAddr, address zcTokenAddr, address vaultAddr) +func (_MarketPlace *MarketPlaceCallerSession) Markets(arg0 common.Address, arg1 *big.Int) (struct { + CTokenAddr common.Address + ZcTokenAddr common.Address + VaultAddr common.Address +}, error) { + return _MarketPlace.Contract.Markets(&_MarketPlace.CallOpts, arg0, arg1) +} + +// Mature is a free data retrieval call binding the contract method 0x27ee93be. +// +// Solidity: function mature(address , uint256 ) view returns(bool) +func (_MarketPlace *MarketPlaceCaller) Mature(opts *bind.CallOpts, arg0 common.Address, arg1 *big.Int) (bool, error) { + var out []interface{} + err := _MarketPlace.contract.Call(opts, &out, "mature", arg0, arg1) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// Mature is a free data retrieval call binding the contract method 0x27ee93be. +// +// Solidity: function mature(address , uint256 ) view returns(bool) +func (_MarketPlace *MarketPlaceSession) Mature(arg0 common.Address, arg1 *big.Int) (bool, error) { + return _MarketPlace.Contract.Mature(&_MarketPlace.CallOpts, arg0, arg1) +} + +// Mature is a free data retrieval call binding the contract method 0x27ee93be. +// +// Solidity: function mature(address , uint256 ) view returns(bool) +func (_MarketPlace *MarketPlaceCallerSession) Mature(arg0 common.Address, arg1 *big.Int) (bool, error) { + return _MarketPlace.Contract.Mature(&_MarketPlace.CallOpts, arg0, arg1) +} + +// MaturityRate is a free data retrieval call binding the contract method 0xc86adf7c. +// +// Solidity: function maturityRate(address , uint256 ) view returns(uint256) +func (_MarketPlace *MarketPlaceCaller) MaturityRate(opts *bind.CallOpts, arg0 common.Address, arg1 *big.Int) (*big.Int, error) { + var out []interface{} + err := _MarketPlace.contract.Call(opts, &out, "maturityRate", arg0, arg1) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// MaturityRate is a free data retrieval call binding the contract method 0xc86adf7c. +// +// Solidity: function maturityRate(address , uint256 ) view returns(uint256) +func (_MarketPlace *MarketPlaceSession) MaturityRate(arg0 common.Address, arg1 *big.Int) (*big.Int, error) { + return _MarketPlace.Contract.MaturityRate(&_MarketPlace.CallOpts, arg0, arg1) +} + +// MaturityRate is a free data retrieval call binding the contract method 0xc86adf7c. +// +// Solidity: function maturityRate(address , uint256 ) view returns(uint256) +func (_MarketPlace *MarketPlaceCallerSession) MaturityRate(arg0 common.Address, arg1 *big.Int) (*big.Int, error) { + return _MarketPlace.Contract.MaturityRate(&_MarketPlace.CallOpts, arg0, arg1) +} + +// Swivel is a free data retrieval call binding the contract method 0x012b264a. +// +// Solidity: function swivel() view returns(address) +func (_MarketPlace *MarketPlaceCaller) Swivel(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _MarketPlace.contract.Call(opts, &out, "swivel") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// Swivel is a free data retrieval call binding the contract method 0x012b264a. +// +// Solidity: function swivel() view returns(address) +func (_MarketPlace *MarketPlaceSession) Swivel() (common.Address, error) { + return _MarketPlace.Contract.Swivel(&_MarketPlace.CallOpts) +} + +// Swivel is a free data retrieval call binding the contract method 0x012b264a. +// +// Solidity: function swivel() view returns(address) +func (_MarketPlace *MarketPlaceCallerSession) Swivel() (common.Address, error) { + return _MarketPlace.Contract.Swivel(&_MarketPlace.CallOpts) +} + +// BurnZcTokenRemovingNotional is a paid mutator transaction binding the contract method 0xb50a66f7. +// +// Solidity: function burnZcTokenRemovingNotional(address u, uint256 m, address t, uint256 a) returns(bool) +func (_MarketPlace *MarketPlaceTransactor) BurnZcTokenRemovingNotional(opts *bind.TransactOpts, u common.Address, m *big.Int, t common.Address, a *big.Int) (*types.Transaction, error) { + return _MarketPlace.contract.Transact(opts, "burnZcTokenRemovingNotional", u, m, t, a) +} + +// BurnZcTokenRemovingNotional is a paid mutator transaction binding the contract method 0xb50a66f7. +// +// Solidity: function burnZcTokenRemovingNotional(address u, uint256 m, address t, uint256 a) returns(bool) +func (_MarketPlace *MarketPlaceSession) BurnZcTokenRemovingNotional(u common.Address, m *big.Int, t common.Address, a *big.Int) (*types.Transaction, error) { + return _MarketPlace.Contract.BurnZcTokenRemovingNotional(&_MarketPlace.TransactOpts, u, m, t, a) +} + +// BurnZcTokenRemovingNotional is a paid mutator transaction binding the contract method 0xb50a66f7. +// +// Solidity: function burnZcTokenRemovingNotional(address u, uint256 m, address t, uint256 a) returns(bool) +func (_MarketPlace *MarketPlaceTransactorSession) BurnZcTokenRemovingNotional(u common.Address, m *big.Int, t common.Address, a *big.Int) (*types.Transaction, error) { + return _MarketPlace.Contract.BurnZcTokenRemovingNotional(&_MarketPlace.TransactOpts, u, m, t, a) +} + +// CreateMarket is a paid mutator transaction binding the contract method 0x848f5184. +// +// Solidity: function createMarket(address u, uint256 m, address c, string n, string s, uint8 d) returns(bool) +func (_MarketPlace *MarketPlaceTransactor) CreateMarket(opts *bind.TransactOpts, u common.Address, m *big.Int, c common.Address, n string, s string, d uint8) (*types.Transaction, error) { + return _MarketPlace.contract.Transact(opts, "createMarket", u, m, c, n, s, d) +} + +// CreateMarket is a paid mutator transaction binding the contract method 0x848f5184. +// +// Solidity: function createMarket(address u, uint256 m, address c, string n, string s, uint8 d) returns(bool) +func (_MarketPlace *MarketPlaceSession) CreateMarket(u common.Address, m *big.Int, c common.Address, n string, s string, d uint8) (*types.Transaction, error) { + return _MarketPlace.Contract.CreateMarket(&_MarketPlace.TransactOpts, u, m, c, n, s, d) +} + +// CreateMarket is a paid mutator transaction binding the contract method 0x848f5184. +// +// Solidity: function createMarket(address u, uint256 m, address c, string n, string s, uint8 d) returns(bool) +func (_MarketPlace *MarketPlaceTransactorSession) CreateMarket(u common.Address, m *big.Int, c common.Address, n string, s string, d uint8) (*types.Transaction, error) { + return _MarketPlace.Contract.CreateMarket(&_MarketPlace.TransactOpts, u, m, c, n, s, d) +} + +// CustodialExit is a paid mutator transaction binding the contract method 0x8c6b9b41. +// +// Solidity: function custodialExit(address u, uint256 m, address z, address n, uint256 a) returns(bool) +func (_MarketPlace *MarketPlaceTransactor) CustodialExit(opts *bind.TransactOpts, u common.Address, m *big.Int, z common.Address, n common.Address, a *big.Int) (*types.Transaction, error) { + return _MarketPlace.contract.Transact(opts, "custodialExit", u, m, z, n, a) +} + +// CustodialExit is a paid mutator transaction binding the contract method 0x8c6b9b41. +// +// Solidity: function custodialExit(address u, uint256 m, address z, address n, uint256 a) returns(bool) +func (_MarketPlace *MarketPlaceSession) CustodialExit(u common.Address, m *big.Int, z common.Address, n common.Address, a *big.Int) (*types.Transaction, error) { + return _MarketPlace.Contract.CustodialExit(&_MarketPlace.TransactOpts, u, m, z, n, a) +} + +// CustodialExit is a paid mutator transaction binding the contract method 0x8c6b9b41. +// +// Solidity: function custodialExit(address u, uint256 m, address z, address n, uint256 a) returns(bool) +func (_MarketPlace *MarketPlaceTransactorSession) CustodialExit(u common.Address, m *big.Int, z common.Address, n common.Address, a *big.Int) (*types.Transaction, error) { + return _MarketPlace.Contract.CustodialExit(&_MarketPlace.TransactOpts, u, m, z, n, a) +} + +// CustodialInitiate is a paid mutator transaction binding the contract method 0xf8e51bcb. +// +// Solidity: function custodialInitiate(address u, uint256 m, address z, address n, uint256 a) returns(bool) +func (_MarketPlace *MarketPlaceTransactor) CustodialInitiate(opts *bind.TransactOpts, u common.Address, m *big.Int, z common.Address, n common.Address, a *big.Int) (*types.Transaction, error) { + return _MarketPlace.contract.Transact(opts, "custodialInitiate", u, m, z, n, a) +} + +// CustodialInitiate is a paid mutator transaction binding the contract method 0xf8e51bcb. +// +// Solidity: function custodialInitiate(address u, uint256 m, address z, address n, uint256 a) returns(bool) +func (_MarketPlace *MarketPlaceSession) CustodialInitiate(u common.Address, m *big.Int, z common.Address, n common.Address, a *big.Int) (*types.Transaction, error) { + return _MarketPlace.Contract.CustodialInitiate(&_MarketPlace.TransactOpts, u, m, z, n, a) +} + +// CustodialInitiate is a paid mutator transaction binding the contract method 0xf8e51bcb. +// +// Solidity: function custodialInitiate(address u, uint256 m, address z, address n, uint256 a) returns(bool) +func (_MarketPlace *MarketPlaceTransactorSession) CustodialInitiate(u common.Address, m *big.Int, z common.Address, n common.Address, a *big.Int) (*types.Transaction, error) { + return _MarketPlace.Contract.CustodialInitiate(&_MarketPlace.TransactOpts, u, m, z, n, a) +} + +// MatureMarket is a paid mutator transaction binding the contract method 0x5db0ae58. +// +// Solidity: function matureMarket(address u, uint256 m) returns(bool) +func (_MarketPlace *MarketPlaceTransactor) MatureMarket(opts *bind.TransactOpts, u common.Address, m *big.Int) (*types.Transaction, error) { + return _MarketPlace.contract.Transact(opts, "matureMarket", u, m) +} + +// MatureMarket is a paid mutator transaction binding the contract method 0x5db0ae58. +// +// Solidity: function matureMarket(address u, uint256 m) returns(bool) +func (_MarketPlace *MarketPlaceSession) MatureMarket(u common.Address, m *big.Int) (*types.Transaction, error) { + return _MarketPlace.Contract.MatureMarket(&_MarketPlace.TransactOpts, u, m) +} + +// MatureMarket is a paid mutator transaction binding the contract method 0x5db0ae58. +// +// Solidity: function matureMarket(address u, uint256 m) returns(bool) +func (_MarketPlace *MarketPlaceTransactorSession) MatureMarket(u common.Address, m *big.Int) (*types.Transaction, error) { + return _MarketPlace.Contract.MatureMarket(&_MarketPlace.TransactOpts, u, m) +} + +// MintZcTokenAddingNotional is a paid mutator transaction binding the contract method 0xef267f2c. +// +// Solidity: function mintZcTokenAddingNotional(address u, uint256 m, address t, uint256 a) returns(bool) +func (_MarketPlace *MarketPlaceTransactor) MintZcTokenAddingNotional(opts *bind.TransactOpts, u common.Address, m *big.Int, t common.Address, a *big.Int) (*types.Transaction, error) { + return _MarketPlace.contract.Transact(opts, "mintZcTokenAddingNotional", u, m, t, a) +} + +// MintZcTokenAddingNotional is a paid mutator transaction binding the contract method 0xef267f2c. +// +// Solidity: function mintZcTokenAddingNotional(address u, uint256 m, address t, uint256 a) returns(bool) +func (_MarketPlace *MarketPlaceSession) MintZcTokenAddingNotional(u common.Address, m *big.Int, t common.Address, a *big.Int) (*types.Transaction, error) { + return _MarketPlace.Contract.MintZcTokenAddingNotional(&_MarketPlace.TransactOpts, u, m, t, a) +} + +// MintZcTokenAddingNotional is a paid mutator transaction binding the contract method 0xef267f2c. +// +// Solidity: function mintZcTokenAddingNotional(address u, uint256 m, address t, uint256 a) returns(bool) +func (_MarketPlace *MarketPlaceTransactorSession) MintZcTokenAddingNotional(u common.Address, m *big.Int, t common.Address, a *big.Int) (*types.Transaction, error) { + return _MarketPlace.Contract.MintZcTokenAddingNotional(&_MarketPlace.TransactOpts, u, m, t, a) +} + +// P2pVaultExchange is a paid mutator transaction binding the contract method 0xbddbfbe4. +// +// Solidity: function p2pVaultExchange(address u, uint256 m, address f, address t, uint256 a) returns(bool) +func (_MarketPlace *MarketPlaceTransactor) P2pVaultExchange(opts *bind.TransactOpts, u common.Address, m *big.Int, f common.Address, t common.Address, a *big.Int) (*types.Transaction, error) { + return _MarketPlace.contract.Transact(opts, "p2pVaultExchange", u, m, f, t, a) +} + +// P2pVaultExchange is a paid mutator transaction binding the contract method 0xbddbfbe4. +// +// Solidity: function p2pVaultExchange(address u, uint256 m, address f, address t, uint256 a) returns(bool) +func (_MarketPlace *MarketPlaceSession) P2pVaultExchange(u common.Address, m *big.Int, f common.Address, t common.Address, a *big.Int) (*types.Transaction, error) { + return _MarketPlace.Contract.P2pVaultExchange(&_MarketPlace.TransactOpts, u, m, f, t, a) +} + +// P2pVaultExchange is a paid mutator transaction binding the contract method 0xbddbfbe4. +// +// Solidity: function p2pVaultExchange(address u, uint256 m, address f, address t, uint256 a) returns(bool) +func (_MarketPlace *MarketPlaceTransactorSession) P2pVaultExchange(u common.Address, m *big.Int, f common.Address, t common.Address, a *big.Int) (*types.Transaction, error) { + return _MarketPlace.Contract.P2pVaultExchange(&_MarketPlace.TransactOpts, u, m, f, t, a) +} + +// P2pZcTokenExchange is a paid mutator transaction binding the contract method 0x65a963aa. +// +// Solidity: function p2pZcTokenExchange(address u, uint256 m, address f, address t, uint256 a) returns(bool) +func (_MarketPlace *MarketPlaceTransactor) P2pZcTokenExchange(opts *bind.TransactOpts, u common.Address, m *big.Int, f common.Address, t common.Address, a *big.Int) (*types.Transaction, error) { + return _MarketPlace.contract.Transact(opts, "p2pZcTokenExchange", u, m, f, t, a) +} + +// P2pZcTokenExchange is a paid mutator transaction binding the contract method 0x65a963aa. +// +// Solidity: function p2pZcTokenExchange(address u, uint256 m, address f, address t, uint256 a) returns(bool) +func (_MarketPlace *MarketPlaceSession) P2pZcTokenExchange(u common.Address, m *big.Int, f common.Address, t common.Address, a *big.Int) (*types.Transaction, error) { + return _MarketPlace.Contract.P2pZcTokenExchange(&_MarketPlace.TransactOpts, u, m, f, t, a) +} + +// P2pZcTokenExchange is a paid mutator transaction binding the contract method 0x65a963aa. +// +// Solidity: function p2pZcTokenExchange(address u, uint256 m, address f, address t, uint256 a) returns(bool) +func (_MarketPlace *MarketPlaceTransactorSession) P2pZcTokenExchange(u common.Address, m *big.Int, f common.Address, t common.Address, a *big.Int) (*types.Transaction, error) { + return _MarketPlace.Contract.P2pZcTokenExchange(&_MarketPlace.TransactOpts, u, m, f, t, a) +} + +// RedeemVaultInterest is a paid mutator transaction binding the contract method 0xa11f4856. +// +// Solidity: function redeemVaultInterest(address u, uint256 m, address t) returns(uint256) +func (_MarketPlace *MarketPlaceTransactor) RedeemVaultInterest(opts *bind.TransactOpts, u common.Address, m *big.Int, t common.Address) (*types.Transaction, error) { + return _MarketPlace.contract.Transact(opts, "redeemVaultInterest", u, m, t) +} + +// RedeemVaultInterest is a paid mutator transaction binding the contract method 0xa11f4856. +// +// Solidity: function redeemVaultInterest(address u, uint256 m, address t) returns(uint256) +func (_MarketPlace *MarketPlaceSession) RedeemVaultInterest(u common.Address, m *big.Int, t common.Address) (*types.Transaction, error) { + return _MarketPlace.Contract.RedeemVaultInterest(&_MarketPlace.TransactOpts, u, m, t) +} + +// RedeemVaultInterest is a paid mutator transaction binding the contract method 0xa11f4856. +// +// Solidity: function redeemVaultInterest(address u, uint256 m, address t) returns(uint256) +func (_MarketPlace *MarketPlaceTransactorSession) RedeemVaultInterest(u common.Address, m *big.Int, t common.Address) (*types.Transaction, error) { + return _MarketPlace.Contract.RedeemVaultInterest(&_MarketPlace.TransactOpts, u, m, t) +} + +// RedeemZcToken is a paid mutator transaction binding the contract method 0xc5ee114d. +// +// Solidity: function redeemZcToken(address u, uint256 m, address t, uint256 a) returns(uint256) +func (_MarketPlace *MarketPlaceTransactor) RedeemZcToken(opts *bind.TransactOpts, u common.Address, m *big.Int, t common.Address, a *big.Int) (*types.Transaction, error) { + return _MarketPlace.contract.Transact(opts, "redeemZcToken", u, m, t, a) +} + +// RedeemZcToken is a paid mutator transaction binding the contract method 0xc5ee114d. +// +// Solidity: function redeemZcToken(address u, uint256 m, address t, uint256 a) returns(uint256) +func (_MarketPlace *MarketPlaceSession) RedeemZcToken(u common.Address, m *big.Int, t common.Address, a *big.Int) (*types.Transaction, error) { + return _MarketPlace.Contract.RedeemZcToken(&_MarketPlace.TransactOpts, u, m, t, a) +} + +// RedeemZcToken is a paid mutator transaction binding the contract method 0xc5ee114d. +// +// Solidity: function redeemZcToken(address u, uint256 m, address t, uint256 a) returns(uint256) +func (_MarketPlace *MarketPlaceTransactorSession) RedeemZcToken(u common.Address, m *big.Int, t common.Address, a *big.Int) (*types.Transaction, error) { + return _MarketPlace.Contract.RedeemZcToken(&_MarketPlace.TransactOpts, u, m, t, a) +} + +// SetSwivelAddress is a paid mutator transaction binding the contract method 0xe5a2aa62. +// +// Solidity: function setSwivelAddress(address s) returns(bool) +func (_MarketPlace *MarketPlaceTransactor) SetSwivelAddress(opts *bind.TransactOpts, s common.Address) (*types.Transaction, error) { + return _MarketPlace.contract.Transact(opts, "setSwivelAddress", s) +} + +// SetSwivelAddress is a paid mutator transaction binding the contract method 0xe5a2aa62. +// +// Solidity: function setSwivelAddress(address s) returns(bool) +func (_MarketPlace *MarketPlaceSession) SetSwivelAddress(s common.Address) (*types.Transaction, error) { + return _MarketPlace.Contract.SetSwivelAddress(&_MarketPlace.TransactOpts, s) +} + +// SetSwivelAddress is a paid mutator transaction binding the contract method 0xe5a2aa62. +// +// Solidity: function setSwivelAddress(address s) returns(bool) +func (_MarketPlace *MarketPlaceTransactorSession) SetSwivelAddress(s common.Address) (*types.Transaction, error) { + return _MarketPlace.Contract.SetSwivelAddress(&_MarketPlace.TransactOpts, s) +} + +// TransferVaultNotional is a paid mutator transaction binding the contract method 0x5292ecf2. +// +// Solidity: function transferVaultNotional(address u, uint256 m, address t, uint256 a) returns(bool) +func (_MarketPlace *MarketPlaceTransactor) TransferVaultNotional(opts *bind.TransactOpts, u common.Address, m *big.Int, t common.Address, a *big.Int) (*types.Transaction, error) { + return _MarketPlace.contract.Transact(opts, "transferVaultNotional", u, m, t, a) +} + +// TransferVaultNotional is a paid mutator transaction binding the contract method 0x5292ecf2. +// +// Solidity: function transferVaultNotional(address u, uint256 m, address t, uint256 a) returns(bool) +func (_MarketPlace *MarketPlaceSession) TransferVaultNotional(u common.Address, m *big.Int, t common.Address, a *big.Int) (*types.Transaction, error) { + return _MarketPlace.Contract.TransferVaultNotional(&_MarketPlace.TransactOpts, u, m, t, a) +} + +// TransferVaultNotional is a paid mutator transaction binding the contract method 0x5292ecf2. +// +// Solidity: function transferVaultNotional(address u, uint256 m, address t, uint256 a) returns(bool) +func (_MarketPlace *MarketPlaceTransactorSession) TransferVaultNotional(u common.Address, m *big.Int, t common.Address, a *big.Int) (*types.Transaction, error) { + return _MarketPlace.Contract.TransferVaultNotional(&_MarketPlace.TransactOpts, u, m, t, a) +} + +// TransferVaultNotionalFee is a paid mutator transaction binding the contract method 0x3cf9a4e3. +// +// Solidity: function transferVaultNotionalFee(address u, uint256 m, address f, uint256 a) returns(bool) +func (_MarketPlace *MarketPlaceTransactor) TransferVaultNotionalFee(opts *bind.TransactOpts, u common.Address, m *big.Int, f common.Address, a *big.Int) (*types.Transaction, error) { + return _MarketPlace.contract.Transact(opts, "transferVaultNotionalFee", u, m, f, a) +} + +// TransferVaultNotionalFee is a paid mutator transaction binding the contract method 0x3cf9a4e3. +// +// Solidity: function transferVaultNotionalFee(address u, uint256 m, address f, uint256 a) returns(bool) +func (_MarketPlace *MarketPlaceSession) TransferVaultNotionalFee(u common.Address, m *big.Int, f common.Address, a *big.Int) (*types.Transaction, error) { + return _MarketPlace.Contract.TransferVaultNotionalFee(&_MarketPlace.TransactOpts, u, m, f, a) +} + +// TransferVaultNotionalFee is a paid mutator transaction binding the contract method 0x3cf9a4e3. +// +// Solidity: function transferVaultNotionalFee(address u, uint256 m, address f, uint256 a) returns(bool) +func (_MarketPlace *MarketPlaceTransactorSession) TransferVaultNotionalFee(u common.Address, m *big.Int, f common.Address, a *big.Int) (*types.Transaction, error) { + return _MarketPlace.Contract.TransferVaultNotionalFee(&_MarketPlace.TransactOpts, u, m, f, a) +} + +// MarketPlaceCreateIterator is returned from FilterCreate and is used to iterate over the raw logs and unpacked data for Create events raised by the MarketPlace contract. +type MarketPlaceCreateIterator struct { + Event *MarketPlaceCreate // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *MarketPlaceCreateIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(MarketPlaceCreate) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(MarketPlaceCreate) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *MarketPlaceCreateIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *MarketPlaceCreateIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// MarketPlaceCreate represents a Create event raised by the MarketPlace contract. +type MarketPlaceCreate struct { + Underlying common.Address + Maturity *big.Int + CToken common.Address + ZcToken common.Address + VaultTracker common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterCreate is a free log retrieval operation binding the contract event 0x1747a3ed83b35b999b9000df0690f6563f6b016a1cce0c8dfc911866d3b92177. +// +// Solidity: event Create(address indexed underlying, uint256 indexed maturity, address cToken, address zcToken, address vaultTracker) +func (_MarketPlace *MarketPlaceFilterer) FilterCreate(opts *bind.FilterOpts, underlying []common.Address, maturity []*big.Int) (*MarketPlaceCreateIterator, error) { + + var underlyingRule []interface{} + for _, underlyingItem := range underlying { + underlyingRule = append(underlyingRule, underlyingItem) + } + var maturityRule []interface{} + for _, maturityItem := range maturity { + maturityRule = append(maturityRule, maturityItem) + } + + logs, sub, err := _MarketPlace.contract.FilterLogs(opts, "Create", underlyingRule, maturityRule) + if err != nil { + return nil, err + } + return &MarketPlaceCreateIterator{contract: _MarketPlace.contract, event: "Create", logs: logs, sub: sub}, nil +} + +// WatchCreate is a free log subscription operation binding the contract event 0x1747a3ed83b35b999b9000df0690f6563f6b016a1cce0c8dfc911866d3b92177. +// +// Solidity: event Create(address indexed underlying, uint256 indexed maturity, address cToken, address zcToken, address vaultTracker) +func (_MarketPlace *MarketPlaceFilterer) WatchCreate(opts *bind.WatchOpts, sink chan<- *MarketPlaceCreate, underlying []common.Address, maturity []*big.Int) (event.Subscription, error) { + + var underlyingRule []interface{} + for _, underlyingItem := range underlying { + underlyingRule = append(underlyingRule, underlyingItem) + } + var maturityRule []interface{} + for _, maturityItem := range maturity { + maturityRule = append(maturityRule, maturityItem) + } + + logs, sub, err := _MarketPlace.contract.WatchLogs(opts, "Create", underlyingRule, maturityRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(MarketPlaceCreate) + if err := _MarketPlace.contract.UnpackLog(event, "Create", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseCreate is a log parse operation binding the contract event 0x1747a3ed83b35b999b9000df0690f6563f6b016a1cce0c8dfc911866d3b92177. +// +// Solidity: event Create(address indexed underlying, uint256 indexed maturity, address cToken, address zcToken, address vaultTracker) +func (_MarketPlace *MarketPlaceFilterer) ParseCreate(log types.Log) (*MarketPlaceCreate, error) { + event := new(MarketPlaceCreate) + if err := _MarketPlace.contract.UnpackLog(event, "Create", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// MarketPlaceCustodialExitIterator is returned from FilterCustodialExit and is used to iterate over the raw logs and unpacked data for CustodialExit events raised by the MarketPlace contract. +type MarketPlaceCustodialExitIterator struct { + Event *MarketPlaceCustodialExit // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *MarketPlaceCustodialExitIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(MarketPlaceCustodialExit) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(MarketPlaceCustodialExit) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *MarketPlaceCustodialExitIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *MarketPlaceCustodialExitIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// MarketPlaceCustodialExit represents a CustodialExit event raised by the MarketPlace contract. +type MarketPlaceCustodialExit struct { + Underlying common.Address + Maturity *big.Int + ZcTarget common.Address + NTarget common.Address + Amount *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterCustodialExit is a free log retrieval operation binding the contract event 0x219a55ae9a5a1822159d55db6dd594a28be30b02c0d18a71469ef28030b3fb59. +// +// Solidity: event CustodialExit(address indexed underlying, uint256 indexed maturity, address zcTarget, address nTarget, uint256 amount) +func (_MarketPlace *MarketPlaceFilterer) FilterCustodialExit(opts *bind.FilterOpts, underlying []common.Address, maturity []*big.Int) (*MarketPlaceCustodialExitIterator, error) { + + var underlyingRule []interface{} + for _, underlyingItem := range underlying { + underlyingRule = append(underlyingRule, underlyingItem) + } + var maturityRule []interface{} + for _, maturityItem := range maturity { + maturityRule = append(maturityRule, maturityItem) + } + + logs, sub, err := _MarketPlace.contract.FilterLogs(opts, "CustodialExit", underlyingRule, maturityRule) + if err != nil { + return nil, err + } + return &MarketPlaceCustodialExitIterator{contract: _MarketPlace.contract, event: "CustodialExit", logs: logs, sub: sub}, nil +} + +// WatchCustodialExit is a free log subscription operation binding the contract event 0x219a55ae9a5a1822159d55db6dd594a28be30b02c0d18a71469ef28030b3fb59. +// +// Solidity: event CustodialExit(address indexed underlying, uint256 indexed maturity, address zcTarget, address nTarget, uint256 amount) +func (_MarketPlace *MarketPlaceFilterer) WatchCustodialExit(opts *bind.WatchOpts, sink chan<- *MarketPlaceCustodialExit, underlying []common.Address, maturity []*big.Int) (event.Subscription, error) { + + var underlyingRule []interface{} + for _, underlyingItem := range underlying { + underlyingRule = append(underlyingRule, underlyingItem) + } + var maturityRule []interface{} + for _, maturityItem := range maturity { + maturityRule = append(maturityRule, maturityItem) + } + + logs, sub, err := _MarketPlace.contract.WatchLogs(opts, "CustodialExit", underlyingRule, maturityRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(MarketPlaceCustodialExit) + if err := _MarketPlace.contract.UnpackLog(event, "CustodialExit", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseCustodialExit is a log parse operation binding the contract event 0x219a55ae9a5a1822159d55db6dd594a28be30b02c0d18a71469ef28030b3fb59. +// +// Solidity: event CustodialExit(address indexed underlying, uint256 indexed maturity, address zcTarget, address nTarget, uint256 amount) +func (_MarketPlace *MarketPlaceFilterer) ParseCustodialExit(log types.Log) (*MarketPlaceCustodialExit, error) { + event := new(MarketPlaceCustodialExit) + if err := _MarketPlace.contract.UnpackLog(event, "CustodialExit", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// MarketPlaceCustodialInitiateIterator is returned from FilterCustodialInitiate and is used to iterate over the raw logs and unpacked data for CustodialInitiate events raised by the MarketPlace contract. +type MarketPlaceCustodialInitiateIterator struct { + Event *MarketPlaceCustodialInitiate // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *MarketPlaceCustodialInitiateIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(MarketPlaceCustodialInitiate) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(MarketPlaceCustodialInitiate) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *MarketPlaceCustodialInitiateIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *MarketPlaceCustodialInitiateIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// MarketPlaceCustodialInitiate represents a CustodialInitiate event raised by the MarketPlace contract. +type MarketPlaceCustodialInitiate struct { + Underlying common.Address + Maturity *big.Int + ZcTarget common.Address + NTarget common.Address + Amount *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterCustodialInitiate is a free log retrieval operation binding the contract event 0x8dad4d03bd4209aa6dc2bea238510998bf39bb034bc9c20d52f0bd241fc0c516. +// +// Solidity: event CustodialInitiate(address indexed underlying, uint256 indexed maturity, address zcTarget, address nTarget, uint256 amount) +func (_MarketPlace *MarketPlaceFilterer) FilterCustodialInitiate(opts *bind.FilterOpts, underlying []common.Address, maturity []*big.Int) (*MarketPlaceCustodialInitiateIterator, error) { + + var underlyingRule []interface{} + for _, underlyingItem := range underlying { + underlyingRule = append(underlyingRule, underlyingItem) + } + var maturityRule []interface{} + for _, maturityItem := range maturity { + maturityRule = append(maturityRule, maturityItem) + } + + logs, sub, err := _MarketPlace.contract.FilterLogs(opts, "CustodialInitiate", underlyingRule, maturityRule) + if err != nil { + return nil, err + } + return &MarketPlaceCustodialInitiateIterator{contract: _MarketPlace.contract, event: "CustodialInitiate", logs: logs, sub: sub}, nil +} + +// WatchCustodialInitiate is a free log subscription operation binding the contract event 0x8dad4d03bd4209aa6dc2bea238510998bf39bb034bc9c20d52f0bd241fc0c516. +// +// Solidity: event CustodialInitiate(address indexed underlying, uint256 indexed maturity, address zcTarget, address nTarget, uint256 amount) +func (_MarketPlace *MarketPlaceFilterer) WatchCustodialInitiate(opts *bind.WatchOpts, sink chan<- *MarketPlaceCustodialInitiate, underlying []common.Address, maturity []*big.Int) (event.Subscription, error) { + + var underlyingRule []interface{} + for _, underlyingItem := range underlying { + underlyingRule = append(underlyingRule, underlyingItem) + } + var maturityRule []interface{} + for _, maturityItem := range maturity { + maturityRule = append(maturityRule, maturityItem) + } + + logs, sub, err := _MarketPlace.contract.WatchLogs(opts, "CustodialInitiate", underlyingRule, maturityRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(MarketPlaceCustodialInitiate) + if err := _MarketPlace.contract.UnpackLog(event, "CustodialInitiate", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseCustodialInitiate is a log parse operation binding the contract event 0x8dad4d03bd4209aa6dc2bea238510998bf39bb034bc9c20d52f0bd241fc0c516. +// +// Solidity: event CustodialInitiate(address indexed underlying, uint256 indexed maturity, address zcTarget, address nTarget, uint256 amount) +func (_MarketPlace *MarketPlaceFilterer) ParseCustodialInitiate(log types.Log) (*MarketPlaceCustodialInitiate, error) { + event := new(MarketPlaceCustodialInitiate) + if err := _MarketPlace.contract.UnpackLog(event, "CustodialInitiate", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// MarketPlaceMatureIterator is returned from FilterMature and is used to iterate over the raw logs and unpacked data for Mature events raised by the MarketPlace contract. +type MarketPlaceMatureIterator struct { + Event *MarketPlaceMature // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *MarketPlaceMatureIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(MarketPlaceMature) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(MarketPlaceMature) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *MarketPlaceMatureIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *MarketPlaceMatureIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// MarketPlaceMature represents a Mature event raised by the MarketPlace contract. +type MarketPlaceMature struct { + Underlying common.Address + Maturity *big.Int + MaturityRate *big.Int + Matured *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterMature is a free log retrieval operation binding the contract event 0x0080e09d7b4544aa5a923873be1df3e31945593d40cb1c874d99259ec3ac43a4. +// +// Solidity: event Mature(address indexed underlying, uint256 indexed maturity, uint256 maturityRate, uint256 matured) +func (_MarketPlace *MarketPlaceFilterer) FilterMature(opts *bind.FilterOpts, underlying []common.Address, maturity []*big.Int) (*MarketPlaceMatureIterator, error) { + + var underlyingRule []interface{} + for _, underlyingItem := range underlying { + underlyingRule = append(underlyingRule, underlyingItem) + } + var maturityRule []interface{} + for _, maturityItem := range maturity { + maturityRule = append(maturityRule, maturityItem) + } + + logs, sub, err := _MarketPlace.contract.FilterLogs(opts, "Mature", underlyingRule, maturityRule) + if err != nil { + return nil, err + } + return &MarketPlaceMatureIterator{contract: _MarketPlace.contract, event: "Mature", logs: logs, sub: sub}, nil +} + +// WatchMature is a free log subscription operation binding the contract event 0x0080e09d7b4544aa5a923873be1df3e31945593d40cb1c874d99259ec3ac43a4. +// +// Solidity: event Mature(address indexed underlying, uint256 indexed maturity, uint256 maturityRate, uint256 matured) +func (_MarketPlace *MarketPlaceFilterer) WatchMature(opts *bind.WatchOpts, sink chan<- *MarketPlaceMature, underlying []common.Address, maturity []*big.Int) (event.Subscription, error) { + + var underlyingRule []interface{} + for _, underlyingItem := range underlying { + underlyingRule = append(underlyingRule, underlyingItem) + } + var maturityRule []interface{} + for _, maturityItem := range maturity { + maturityRule = append(maturityRule, maturityItem) + } + + logs, sub, err := _MarketPlace.contract.WatchLogs(opts, "Mature", underlyingRule, maturityRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(MarketPlaceMature) + if err := _MarketPlace.contract.UnpackLog(event, "Mature", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseMature is a log parse operation binding the contract event 0x0080e09d7b4544aa5a923873be1df3e31945593d40cb1c874d99259ec3ac43a4. +// +// Solidity: event Mature(address indexed underlying, uint256 indexed maturity, uint256 maturityRate, uint256 matured) +func (_MarketPlace *MarketPlaceFilterer) ParseMature(log types.Log) (*MarketPlaceMature, error) { + event := new(MarketPlaceMature) + if err := _MarketPlace.contract.UnpackLog(event, "Mature", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// MarketPlaceP2pVaultExchangeIterator is returned from FilterP2pVaultExchange and is used to iterate over the raw logs and unpacked data for P2pVaultExchange events raised by the MarketPlace contract. +type MarketPlaceP2pVaultExchangeIterator struct { + Event *MarketPlaceP2pVaultExchange // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *MarketPlaceP2pVaultExchangeIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(MarketPlaceP2pVaultExchange) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(MarketPlaceP2pVaultExchange) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *MarketPlaceP2pVaultExchangeIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *MarketPlaceP2pVaultExchangeIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// MarketPlaceP2pVaultExchange represents a P2pVaultExchange event raised by the MarketPlace contract. +type MarketPlaceP2pVaultExchange struct { + Underlying common.Address + Maturity *big.Int + From common.Address + To common.Address + Amount *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterP2pVaultExchange is a free log retrieval operation binding the contract event 0x31d266c2b6075063717026bd27ba8bb527366457893dc211091b2e1d9713f152. +// +// Solidity: event P2pVaultExchange(address indexed underlying, uint256 indexed maturity, address from, address to, uint256 amount) +func (_MarketPlace *MarketPlaceFilterer) FilterP2pVaultExchange(opts *bind.FilterOpts, underlying []common.Address, maturity []*big.Int) (*MarketPlaceP2pVaultExchangeIterator, error) { + + var underlyingRule []interface{} + for _, underlyingItem := range underlying { + underlyingRule = append(underlyingRule, underlyingItem) + } + var maturityRule []interface{} + for _, maturityItem := range maturity { + maturityRule = append(maturityRule, maturityItem) + } + + logs, sub, err := _MarketPlace.contract.FilterLogs(opts, "P2pVaultExchange", underlyingRule, maturityRule) + if err != nil { + return nil, err + } + return &MarketPlaceP2pVaultExchangeIterator{contract: _MarketPlace.contract, event: "P2pVaultExchange", logs: logs, sub: sub}, nil +} + +// WatchP2pVaultExchange is a free log subscription operation binding the contract event 0x31d266c2b6075063717026bd27ba8bb527366457893dc211091b2e1d9713f152. +// +// Solidity: event P2pVaultExchange(address indexed underlying, uint256 indexed maturity, address from, address to, uint256 amount) +func (_MarketPlace *MarketPlaceFilterer) WatchP2pVaultExchange(opts *bind.WatchOpts, sink chan<- *MarketPlaceP2pVaultExchange, underlying []common.Address, maturity []*big.Int) (event.Subscription, error) { + + var underlyingRule []interface{} + for _, underlyingItem := range underlying { + underlyingRule = append(underlyingRule, underlyingItem) + } + var maturityRule []interface{} + for _, maturityItem := range maturity { + maturityRule = append(maturityRule, maturityItem) + } + + logs, sub, err := _MarketPlace.contract.WatchLogs(opts, "P2pVaultExchange", underlyingRule, maturityRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(MarketPlaceP2pVaultExchange) + if err := _MarketPlace.contract.UnpackLog(event, "P2pVaultExchange", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseP2pVaultExchange is a log parse operation binding the contract event 0x31d266c2b6075063717026bd27ba8bb527366457893dc211091b2e1d9713f152. +// +// Solidity: event P2pVaultExchange(address indexed underlying, uint256 indexed maturity, address from, address to, uint256 amount) +func (_MarketPlace *MarketPlaceFilterer) ParseP2pVaultExchange(log types.Log) (*MarketPlaceP2pVaultExchange, error) { + event := new(MarketPlaceP2pVaultExchange) + if err := _MarketPlace.contract.UnpackLog(event, "P2pVaultExchange", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// MarketPlaceP2pZcTokenExchangeIterator is returned from FilterP2pZcTokenExchange and is used to iterate over the raw logs and unpacked data for P2pZcTokenExchange events raised by the MarketPlace contract. +type MarketPlaceP2pZcTokenExchangeIterator struct { + Event *MarketPlaceP2pZcTokenExchange // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *MarketPlaceP2pZcTokenExchangeIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(MarketPlaceP2pZcTokenExchange) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(MarketPlaceP2pZcTokenExchange) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *MarketPlaceP2pZcTokenExchangeIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *MarketPlaceP2pZcTokenExchangeIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// MarketPlaceP2pZcTokenExchange represents a P2pZcTokenExchange event raised by the MarketPlace contract. +type MarketPlaceP2pZcTokenExchange struct { + Underlying common.Address + Maturity *big.Int + From common.Address + To common.Address + Amount *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterP2pZcTokenExchange is a free log retrieval operation binding the contract event 0x86ac24e4ee753e21fb51afa847265cb350e500593f3204057e40079c3ef54422. +// +// Solidity: event P2pZcTokenExchange(address indexed underlying, uint256 indexed maturity, address from, address to, uint256 amount) +func (_MarketPlace *MarketPlaceFilterer) FilterP2pZcTokenExchange(opts *bind.FilterOpts, underlying []common.Address, maturity []*big.Int) (*MarketPlaceP2pZcTokenExchangeIterator, error) { + + var underlyingRule []interface{} + for _, underlyingItem := range underlying { + underlyingRule = append(underlyingRule, underlyingItem) + } + var maturityRule []interface{} + for _, maturityItem := range maturity { + maturityRule = append(maturityRule, maturityItem) + } + + logs, sub, err := _MarketPlace.contract.FilterLogs(opts, "P2pZcTokenExchange", underlyingRule, maturityRule) + if err != nil { + return nil, err + } + return &MarketPlaceP2pZcTokenExchangeIterator{contract: _MarketPlace.contract, event: "P2pZcTokenExchange", logs: logs, sub: sub}, nil +} + +// WatchP2pZcTokenExchange is a free log subscription operation binding the contract event 0x86ac24e4ee753e21fb51afa847265cb350e500593f3204057e40079c3ef54422. +// +// Solidity: event P2pZcTokenExchange(address indexed underlying, uint256 indexed maturity, address from, address to, uint256 amount) +func (_MarketPlace *MarketPlaceFilterer) WatchP2pZcTokenExchange(opts *bind.WatchOpts, sink chan<- *MarketPlaceP2pZcTokenExchange, underlying []common.Address, maturity []*big.Int) (event.Subscription, error) { + + var underlyingRule []interface{} + for _, underlyingItem := range underlying { + underlyingRule = append(underlyingRule, underlyingItem) + } + var maturityRule []interface{} + for _, maturityItem := range maturity { + maturityRule = append(maturityRule, maturityItem) + } + + logs, sub, err := _MarketPlace.contract.WatchLogs(opts, "P2pZcTokenExchange", underlyingRule, maturityRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(MarketPlaceP2pZcTokenExchange) + if err := _MarketPlace.contract.UnpackLog(event, "P2pZcTokenExchange", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseP2pZcTokenExchange is a log parse operation binding the contract event 0x86ac24e4ee753e21fb51afa847265cb350e500593f3204057e40079c3ef54422. +// +// Solidity: event P2pZcTokenExchange(address indexed underlying, uint256 indexed maturity, address from, address to, uint256 amount) +func (_MarketPlace *MarketPlaceFilterer) ParseP2pZcTokenExchange(log types.Log) (*MarketPlaceP2pZcTokenExchange, error) { + event := new(MarketPlaceP2pZcTokenExchange) + if err := _MarketPlace.contract.UnpackLog(event, "P2pZcTokenExchange", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// MarketPlaceRedeemVaultInterestIterator is returned from FilterRedeemVaultInterest and is used to iterate over the raw logs and unpacked data for RedeemVaultInterest events raised by the MarketPlace contract. +type MarketPlaceRedeemVaultInterestIterator struct { + Event *MarketPlaceRedeemVaultInterest // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *MarketPlaceRedeemVaultInterestIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(MarketPlaceRedeemVaultInterest) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(MarketPlaceRedeemVaultInterest) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *MarketPlaceRedeemVaultInterestIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *MarketPlaceRedeemVaultInterestIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// MarketPlaceRedeemVaultInterest represents a RedeemVaultInterest event raised by the MarketPlace contract. +type MarketPlaceRedeemVaultInterest struct { + Underlying common.Address + Maturity *big.Int + Sender common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterRedeemVaultInterest is a free log retrieval operation binding the contract event 0x646390328280b54978a07e7bd72dd9b3f9515286196024882943a96d5c279874. +// +// Solidity: event RedeemVaultInterest(address indexed underlying, uint256 indexed maturity, address indexed sender) +func (_MarketPlace *MarketPlaceFilterer) FilterRedeemVaultInterest(opts *bind.FilterOpts, underlying []common.Address, maturity []*big.Int, sender []common.Address) (*MarketPlaceRedeemVaultInterestIterator, error) { + + var underlyingRule []interface{} + for _, underlyingItem := range underlying { + underlyingRule = append(underlyingRule, underlyingItem) + } + var maturityRule []interface{} + for _, maturityItem := range maturity { + maturityRule = append(maturityRule, maturityItem) + } + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _MarketPlace.contract.FilterLogs(opts, "RedeemVaultInterest", underlyingRule, maturityRule, senderRule) + if err != nil { + return nil, err + } + return &MarketPlaceRedeemVaultInterestIterator{contract: _MarketPlace.contract, event: "RedeemVaultInterest", logs: logs, sub: sub}, nil +} + +// WatchRedeemVaultInterest is a free log subscription operation binding the contract event 0x646390328280b54978a07e7bd72dd9b3f9515286196024882943a96d5c279874. +// +// Solidity: event RedeemVaultInterest(address indexed underlying, uint256 indexed maturity, address indexed sender) +func (_MarketPlace *MarketPlaceFilterer) WatchRedeemVaultInterest(opts *bind.WatchOpts, sink chan<- *MarketPlaceRedeemVaultInterest, underlying []common.Address, maturity []*big.Int, sender []common.Address) (event.Subscription, error) { + + var underlyingRule []interface{} + for _, underlyingItem := range underlying { + underlyingRule = append(underlyingRule, underlyingItem) + } + var maturityRule []interface{} + for _, maturityItem := range maturity { + maturityRule = append(maturityRule, maturityItem) + } + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _MarketPlace.contract.WatchLogs(opts, "RedeemVaultInterest", underlyingRule, maturityRule, senderRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(MarketPlaceRedeemVaultInterest) + if err := _MarketPlace.contract.UnpackLog(event, "RedeemVaultInterest", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseRedeemVaultInterest is a log parse operation binding the contract event 0x646390328280b54978a07e7bd72dd9b3f9515286196024882943a96d5c279874. +// +// Solidity: event RedeemVaultInterest(address indexed underlying, uint256 indexed maturity, address indexed sender) +func (_MarketPlace *MarketPlaceFilterer) ParseRedeemVaultInterest(log types.Log) (*MarketPlaceRedeemVaultInterest, error) { + event := new(MarketPlaceRedeemVaultInterest) + if err := _MarketPlace.contract.UnpackLog(event, "RedeemVaultInterest", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// MarketPlaceRedeemZcTokenIterator is returned from FilterRedeemZcToken and is used to iterate over the raw logs and unpacked data for RedeemZcToken events raised by the MarketPlace contract. +type MarketPlaceRedeemZcTokenIterator struct { + Event *MarketPlaceRedeemZcToken // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *MarketPlaceRedeemZcTokenIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(MarketPlaceRedeemZcToken) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(MarketPlaceRedeemZcToken) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *MarketPlaceRedeemZcTokenIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *MarketPlaceRedeemZcTokenIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// MarketPlaceRedeemZcToken represents a RedeemZcToken event raised by the MarketPlace contract. +type MarketPlaceRedeemZcToken struct { + Underlying common.Address + Maturity *big.Int + Sender common.Address + Amount *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterRedeemZcToken is a free log retrieval operation binding the contract event 0x49dc20daa9f95793b82245100affbf87ad23d1761bdef94975542564f4023e45. +// +// Solidity: event RedeemZcToken(address indexed underlying, uint256 indexed maturity, address indexed sender, uint256 amount) +func (_MarketPlace *MarketPlaceFilterer) FilterRedeemZcToken(opts *bind.FilterOpts, underlying []common.Address, maturity []*big.Int, sender []common.Address) (*MarketPlaceRedeemZcTokenIterator, error) { + + var underlyingRule []interface{} + for _, underlyingItem := range underlying { + underlyingRule = append(underlyingRule, underlyingItem) + } + var maturityRule []interface{} + for _, maturityItem := range maturity { + maturityRule = append(maturityRule, maturityItem) + } + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _MarketPlace.contract.FilterLogs(opts, "RedeemZcToken", underlyingRule, maturityRule, senderRule) + if err != nil { + return nil, err + } + return &MarketPlaceRedeemZcTokenIterator{contract: _MarketPlace.contract, event: "RedeemZcToken", logs: logs, sub: sub}, nil +} + +// WatchRedeemZcToken is a free log subscription operation binding the contract event 0x49dc20daa9f95793b82245100affbf87ad23d1761bdef94975542564f4023e45. +// +// Solidity: event RedeemZcToken(address indexed underlying, uint256 indexed maturity, address indexed sender, uint256 amount) +func (_MarketPlace *MarketPlaceFilterer) WatchRedeemZcToken(opts *bind.WatchOpts, sink chan<- *MarketPlaceRedeemZcToken, underlying []common.Address, maturity []*big.Int, sender []common.Address) (event.Subscription, error) { + + var underlyingRule []interface{} + for _, underlyingItem := range underlying { + underlyingRule = append(underlyingRule, underlyingItem) + } + var maturityRule []interface{} + for _, maturityItem := range maturity { + maturityRule = append(maturityRule, maturityItem) + } + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _MarketPlace.contract.WatchLogs(opts, "RedeemZcToken", underlyingRule, maturityRule, senderRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(MarketPlaceRedeemZcToken) + if err := _MarketPlace.contract.UnpackLog(event, "RedeemZcToken", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseRedeemZcToken is a log parse operation binding the contract event 0x49dc20daa9f95793b82245100affbf87ad23d1761bdef94975542564f4023e45. +// +// Solidity: event RedeemZcToken(address indexed underlying, uint256 indexed maturity, address indexed sender, uint256 amount) +func (_MarketPlace *MarketPlaceFilterer) ParseRedeemZcToken(log types.Log) (*MarketPlaceRedeemZcToken, error) { + event := new(MarketPlaceRedeemZcToken) + if err := _MarketPlace.contract.UnpackLog(event, "RedeemZcToken", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// MarketPlaceTransferVaultNotionalIterator is returned from FilterTransferVaultNotional and is used to iterate over the raw logs and unpacked data for TransferVaultNotional events raised by the MarketPlace contract. +type MarketPlaceTransferVaultNotionalIterator struct { + Event *MarketPlaceTransferVaultNotional // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *MarketPlaceTransferVaultNotionalIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(MarketPlaceTransferVaultNotional) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(MarketPlaceTransferVaultNotional) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *MarketPlaceTransferVaultNotionalIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *MarketPlaceTransferVaultNotionalIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// MarketPlaceTransferVaultNotional represents a TransferVaultNotional event raised by the MarketPlace contract. +type MarketPlaceTransferVaultNotional struct { + Underlying common.Address + Maturity *big.Int + From common.Address + To common.Address + Amount *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterTransferVaultNotional is a free log retrieval operation binding the contract event 0x1d06fe04c445804d7b460d2d5f2fee7c4cc5ba874f3311d2768f849c66cf3098. +// +// Solidity: event TransferVaultNotional(address indexed underlying, uint256 indexed maturity, address from, address to, uint256 amount) +func (_MarketPlace *MarketPlaceFilterer) FilterTransferVaultNotional(opts *bind.FilterOpts, underlying []common.Address, maturity []*big.Int) (*MarketPlaceTransferVaultNotionalIterator, error) { + + var underlyingRule []interface{} + for _, underlyingItem := range underlying { + underlyingRule = append(underlyingRule, underlyingItem) + } + var maturityRule []interface{} + for _, maturityItem := range maturity { + maturityRule = append(maturityRule, maturityItem) + } + + logs, sub, err := _MarketPlace.contract.FilterLogs(opts, "TransferVaultNotional", underlyingRule, maturityRule) + if err != nil { + return nil, err + } + return &MarketPlaceTransferVaultNotionalIterator{contract: _MarketPlace.contract, event: "TransferVaultNotional", logs: logs, sub: sub}, nil +} + +// WatchTransferVaultNotional is a free log subscription operation binding the contract event 0x1d06fe04c445804d7b460d2d5f2fee7c4cc5ba874f3311d2768f849c66cf3098. +// +// Solidity: event TransferVaultNotional(address indexed underlying, uint256 indexed maturity, address from, address to, uint256 amount) +func (_MarketPlace *MarketPlaceFilterer) WatchTransferVaultNotional(opts *bind.WatchOpts, sink chan<- *MarketPlaceTransferVaultNotional, underlying []common.Address, maturity []*big.Int) (event.Subscription, error) { + + var underlyingRule []interface{} + for _, underlyingItem := range underlying { + underlyingRule = append(underlyingRule, underlyingItem) + } + var maturityRule []interface{} + for _, maturityItem := range maturity { + maturityRule = append(maturityRule, maturityItem) + } + + logs, sub, err := _MarketPlace.contract.WatchLogs(opts, "TransferVaultNotional", underlyingRule, maturityRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(MarketPlaceTransferVaultNotional) + if err := _MarketPlace.contract.UnpackLog(event, "TransferVaultNotional", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseTransferVaultNotional is a log parse operation binding the contract event 0x1d06fe04c445804d7b460d2d5f2fee7c4cc5ba874f3311d2768f849c66cf3098. +// +// Solidity: event TransferVaultNotional(address indexed underlying, uint256 indexed maturity, address from, address to, uint256 amount) +func (_MarketPlace *MarketPlaceFilterer) ParseTransferVaultNotional(log types.Log) (*MarketPlaceTransferVaultNotional, error) { + event := new(MarketPlaceTransferVaultNotional) + if err := _MarketPlace.contract.UnpackLog(event, "TransferVaultNotional", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} diff --git a/gost/build/swivel/Abstracts.sol b/gost/build/swivel/Abstracts.sol new file mode 100644 index 0000000..1bd2f21 --- /dev/null +++ b/gost/build/swivel/Abstracts.sol @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: UNLICENSED + +pragma solidity 0.8.4; + +abstract contract Erc20 { + function approve(address, uint256) virtual external returns (bool); + function transfer(address, uint256) virtual external returns (bool); + function balanceOf(address) virtual external returns (uint256); + function transferFrom(address, address, uint256) virtual public returns (bool); +} + +abstract contract CErc20 is Erc20 { + function mint(uint256) virtual external returns (uint256); + function redeem(uint256) virtual external returns (uint256); + function redeemUnderlying(uint256) virtual external returns (uint256); + function exchangeRateCurrent() virtual external returns (uint256); +} + +abstract contract MarketPlace { + // adds notional and mints zctokens + function mintZcTokenAddingNotional(address, uint256, address, uint256) virtual external returns (bool); + // removes notional and burns zctokens + function burnZcTokenRemovingNotional(address, uint256, address, uint256) virtual external returns (bool); + // returns the amount of underlying principal to send + function redeemZcToken(address, uint256, address, uint256) virtual external returns (uint256); + // returns the amount of underlying interest to send + function redeemVaultInterest(address, uint256, address) virtual external returns (uint256); + // returns the cToken address for a given market + function cTokenAddress(address, uint256) virtual external returns (address); + // EVFZE FF EZFVE call this which would then burn zctoken and remove notional + function custodialExit(address, uint256, address, address, uint256) virtual external returns (bool); + // IVFZI && IZFVI call this which would then mint zctoken and add notional + function custodialInitiate(address, uint256, address, address, uint256) virtual external returns (bool); + // IZFZE && EZFZI call this, tranferring zctoken from one party to another + function p2pZcTokenExchange(address, uint256, address, address, uint256) virtual external returns (bool); + // IVFVE && EVFVI call this, removing notional from one party and adding to the other + function p2pVaultExchange(address, uint256, address, address, uint256) virtual external returns (bool); + // IVFZI && IVFVE call this which then transfers notional from msg.sender (taker) to swivel + function transferVaultNotionalFee(address, uint256, address, uint256) virtual external returns (bool); +} diff --git a/gost/build/swivel/CErc20.abi b/gost/build/swivel/CErc20.abi new file mode 100644 index 0000000..03e1ca1 --- /dev/null +++ b/gost/build/swivel/CErc20.abi @@ -0,0 +1 @@ +[{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"exchangeRateCurrent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"mint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"redeem","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"redeemUnderlying","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file diff --git a/gost/build/swivel/CErc20.bin b/gost/build/swivel/CErc20.bin new file mode 100644 index 0000000..e69de29 diff --git a/gost/build/swivel/Erc20.abi b/gost/build/swivel/Erc20.abi new file mode 100644 index 0000000..88abe05 --- /dev/null +++ b/gost/build/swivel/Erc20.abi @@ -0,0 +1 @@ +[{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file diff --git a/gost/build/swivel/Erc20.bin b/gost/build/swivel/Erc20.bin new file mode 100644 index 0000000..e69de29 diff --git a/gost/build/swivel/Hash.abi b/gost/build/swivel/Hash.abi new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/gost/build/swivel/Hash.abi @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/gost/build/swivel/Hash.bin b/gost/build/swivel/Hash.bin new file mode 100644 index 0000000..f259eb7 --- /dev/null +++ b/gost/build/swivel/Hash.bin @@ -0,0 +1 @@ +60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea26469706673582212202a97c5526533de0171fc617a17a3414ab24252fdcb7f46f7d0c816e806020d8264736f6c63430008040033 \ No newline at end of file diff --git a/gost/build/swivel/Hash.sol b/gost/build/swivel/Hash.sol new file mode 100644 index 0000000..9cfefb2 --- /dev/null +++ b/gost/build/swivel/Hash.sol @@ -0,0 +1,107 @@ +// SPDX-License-Identifier: UNLICENSED + +pragma solidity 0.8.4; + +/** + @notice Encapsulation of the logic to produce EIP712 hashed domain and messages. + Also to produce / verify hashed and signed Orders. + See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-712.md + See/attribute https://github.com/0xProject/0x-monorepo/blob/development/contracts/utils/contracts/src/LibEIP712.sol +*/ + +library Hash { + /// @dev struct represents the attributes of an offchain Swivel.Order + struct Order { + bytes32 key; + address maker; + address underlying; + bool vault; + bool exit; + uint256 principal; + uint256 premium; + uint256 maturity; + uint256 expiry; + } + + // EIP712 Domain Separator typeHash + // keccak256(abi.encodePacked( + // 'EIP712Domain(', + // 'string name,', + // 'string version,', + // 'uint256 chainId,', + // 'address verifyingContract', + // ')' + // )); + bytes32 constant internal DOMAIN_TYPEHASH = 0x8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f; + + // EIP712 typeHash of an Order + // keccak256(abi.encodePacked( + // 'Order(', + // 'bytes32 key,', + // 'address maker,', + // 'address underlying,', + // 'bool vault,', + // 'bool exit,', + // 'uint256 principal,', + // 'uint256 premium,', + // 'uint256 maturity,', + // 'uint256 expiry', + // ')' + // )); + bytes32 constant internal ORDER_TYPEHASH = 0x7ddd38ab5ed1c16b61ca90eeb9579e29da1ba821cf42d8cdef8f30a31a6a4146; + + /// @param n EIP712 domain name + /// @param version EIP712 semantic version string + /// @param i Chain ID + /// @param verifier address of the verifying contract + function domain(string memory n, string memory version, uint256 i, address verifier) internal pure returns (bytes32) { + bytes32 hash; + + assembly { + let nameHash := keccak256(add(n, 32), mload(n)) + let versionHash := keccak256(add(version, 32), mload(version)) + let pointer := mload(64) + mstore(pointer, DOMAIN_TYPEHASH) + mstore(add(pointer, 32), nameHash) + mstore(add(pointer, 64), versionHash) + mstore(add(pointer, 96), i) + mstore(add(pointer, 128), verifier) + hash := keccak256(pointer, 160) + } + + return hash; + } + + /// @param d Type hash of the domain separator (see Hash.domain) + /// @param h EIP712 hash struct (order for example) + function message(bytes32 d, bytes32 h) internal pure returns (bytes32) { + bytes32 hash; + + assembly { + let pointer := mload(64) + mstore(pointer, 0x1901000000000000000000000000000000000000000000000000000000000000) + mstore(add(pointer, 2), d) + mstore(add(pointer, 34), h) + hash := keccak256(pointer, 66) + } + + return hash; + } + + /// @param o A Swivel Order + function order(Order calldata o) internal pure returns (bytes32) { + // TODO assembly + return keccak256(abi.encode( + ORDER_TYPEHASH, + o.key, + o.maker, + o.underlying, + o.vault, + o.exit, + o.principal, + o.premium, + o.maturity, + o.expiry + )); + } +} diff --git a/gost/build/swivel/MarketPlace.abi b/gost/build/swivel/MarketPlace.abi new file mode 100644 index 0000000..6cc9d61 --- /dev/null +++ b/gost/build/swivel/MarketPlace.abi @@ -0,0 +1 @@ +[{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"burnZcTokenRemovingNotional","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"cTokenAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"custodialExit","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"custodialInitiate","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"mintZcTokenAddingNotional","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"p2pVaultExchange","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"p2pZcTokenExchange","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"}],"name":"redeemVaultInterest","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"redeemZcToken","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"transferVaultNotionalFee","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file diff --git a/gost/build/swivel/MarketPlace.bin b/gost/build/swivel/MarketPlace.bin new file mode 100644 index 0000000..e69de29 diff --git a/gost/build/swivel/Sig.abi b/gost/build/swivel/Sig.abi new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/gost/build/swivel/Sig.abi @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/gost/build/swivel/Sig.bin b/gost/build/swivel/Sig.bin new file mode 100644 index 0000000..aa7c796 --- /dev/null +++ b/gost/build/swivel/Sig.bin @@ -0,0 +1 @@ +60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220735e9d23802816c8cde968a4d7255d3461dd148eb9f6499347df39a53148f20d64736f6c63430008040033 \ No newline at end of file diff --git a/gost/build/swivel/Sig.sol b/gost/build/swivel/Sig.sol new file mode 100644 index 0000000..c80008f --- /dev/null +++ b/gost/build/swivel/Sig.sol @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: UNLICENSED + +pragma solidity 0.8.4; + +library Sig { + /// @dev ECDSA V,R and S components encapsulated here as we may not always be able to accept a bytes signature + struct Components { + uint8 v; + bytes32 r; + bytes32 s; + } + + /// @param h Hashed data which was originally signed + /// @param c signature struct containing V,R and S + /// @return The recovered address + function recover(bytes32 h, Components calldata c) internal pure returns (address) { + // EIP-2 and malleable signatures... + // see https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/cryptography/ECDSA.sol + require(uint256(c.s) <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0, 'invalid signature "s" value'); + require(c.v == 27 || c.v == 28, 'invalid signature "v" value'); + + return ecrecover(h, c.v, c.r, c.s); + } + + /// @param h Hashed data which was originally signed + /// @param sig Valid ECDSA signature + /// @dev splitAndRecover should only be used if it is known that the resulting + /// verifying bit (V) will be 27 || 28. Otherwise use recover, possibly calling split first. + /// @return The recovered address + function splitAndRecover(bytes32 h, bytes memory sig) internal pure returns (address) { + (uint8 v, bytes32 r, bytes32 s) = split(sig); + + return ecrecover(h, v, r, s); + } + + /// @param sig Valid ECDSA signature + /// @return v The verification bit + /// @return r First 32 bytes + /// @return s Next 32 bytes + function split(bytes memory sig) internal pure returns (uint8, bytes32, bytes32) { + require(sig.length == 65, 'invalid signature length'); // TODO standardize error messages + + bytes32 r; + bytes32 s; + uint8 v; + + assembly { + r := mload(add(sig, 32)) + s := mload(add(sig, 64)) + v := byte(0, mload(add(sig, 96))) + } + + return (v, r, s); + } +} diff --git a/gost/build/swivel/Swivel.abi b/gost/build/swivel/Swivel.abi new file mode 100644 index 0000000..d834fdd --- /dev/null +++ b/gost/build/swivel/Swivel.abi @@ -0,0 +1 @@ +[{"inputs":[{"internalType":"address","name":"m","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"key","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"hash","type":"bytes32"}],"name":"Cancel","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"key","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"hash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"maker","type":"address"},{"indexed":false,"internalType":"bool","name":"vault","type":"bool"},{"indexed":false,"internalType":"bool","name":"exit","type":"bool"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"filled","type":"uint256"}],"name":"Exit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"key","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"hash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"maker","type":"address"},{"indexed":false,"internalType":"bool","name":"vault","type":"bool"},{"indexed":false,"internalType":"bool","name":"exit","type":"bool"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"filled","type":"uint256"}],"name":"Initiate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"hold","type":"uint256"}],"name":"WithdrawalScheduled","type":"event"},{"inputs":[],"name":"HOLD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"NAME","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"VERSION","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"admin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"e","type":"address"}],"name":"blockWithdrawal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"key","type":"bytes32"},{"internalType":"address","name":"maker","type":"address"},{"internalType":"address","name":"underlying","type":"address"},{"internalType":"bool","name":"vault","type":"bool"},{"internalType":"bool","name":"exit","type":"bool"},{"internalType":"uint256","name":"principal","type":"uint256"},{"internalType":"uint256","name":"premium","type":"uint256"},{"internalType":"uint256","name":"maturity","type":"uint256"},{"internalType":"uint256","name":"expiry","type":"uint256"}],"internalType":"struct Hash.Order","name":"o","type":"tuple"},{"components":[{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct Sig.Components","name":"c","type":"tuple"}],"name":"cancel","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"cancelled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"u","type":"address"},{"internalType":"uint256","name":"m","type":"uint256"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"combineTokens","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"domain","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"key","type":"bytes32"},{"internalType":"address","name":"maker","type":"address"},{"internalType":"address","name":"underlying","type":"address"},{"internalType":"bool","name":"vault","type":"bool"},{"internalType":"bool","name":"exit","type":"bool"},{"internalType":"uint256","name":"principal","type":"uint256"},{"internalType":"uint256","name":"premium","type":"uint256"},{"internalType":"uint256","name":"maturity","type":"uint256"},{"internalType":"uint256","name":"expiry","type":"uint256"}],"internalType":"struct Hash.Order[]","name":"o","type":"tuple[]"},{"internalType":"uint256[]","name":"a","type":"uint256[]"},{"components":[{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct Sig.Components[]","name":"c","type":"tuple[]"}],"name":"exit","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"fenominator","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"filled","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"key","type":"bytes32"},{"internalType":"address","name":"maker","type":"address"},{"internalType":"address","name":"underlying","type":"address"},{"internalType":"bool","name":"vault","type":"bool"},{"internalType":"bool","name":"exit","type":"bool"},{"internalType":"uint256","name":"principal","type":"uint256"},{"internalType":"uint256","name":"premium","type":"uint256"},{"internalType":"uint256","name":"maturity","type":"uint256"},{"internalType":"uint256","name":"expiry","type":"uint256"}],"internalType":"struct Hash.Order[]","name":"o","type":"tuple[]"},{"internalType":"uint256[]","name":"a","type":"uint256[]"},{"components":[{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct Sig.Components[]","name":"c","type":"tuple[]"}],"name":"initiate","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"marketPlace","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"u","type":"address"},{"internalType":"uint256","name":"m","type":"uint256"}],"name":"redeemVaultInterest","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"u","type":"address"},{"internalType":"uint256","name":"m","type":"uint256"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"redeemZcToken","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"e","type":"address"}],"name":"scheduleWithdrawal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"t","type":"uint16"},{"internalType":"uint16","name":"d","type":"uint16"}],"name":"setFee","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"u","type":"address"},{"internalType":"uint256","name":"m","type":"uint256"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"splitUnderlying","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"e","type":"address"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"withdrawals","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}] \ No newline at end of file diff --git a/gost/build/swivel/Swivel.bin b/gost/build/swivel/Swivel.bin new file mode 100644 index 0000000..1f5b400 --- /dev/null +++ b/gost/build/swivel/Swivel.bin @@ -0,0 +1 @@ +60e06040523480156200001157600080fd5b50604051620054a7380380620054a7833981016040819052620000349162000206565b3360601b60c052604080518082018252600e81526d53776976656c2046696e616e636560901b602080830191909152825180840190935260058352640322e302e360dc1b838201526200009592904690309062001caa620000e8821b17901c565b6080908152606082811b6001600160601b03191660a05260408051928301815260c880845261025860208501526101909184019190915290820152620000e09060039060046200013f565b505062000236565b8351602094850120835193850193909320604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f815295860194909452928401929092526060830152608082015260a0902090565b82805482825590600052602060002090600f01601090048101928215620001dd5791602002820160005b83821115620001ab57835183826101000a81548161ffff021916908361ffff160217905550926020019260020160208160010104928301926001030262000169565b8015620001db5782816101000a81549061ffff0219169055600201602081600101049283019260010302620001ab565b505b50620001eb929150620001ef565b5090565b5b80821115620001eb5760008155600101620001f0565b60006020828403121562000218578081fd5b81516001600160a01b03811681146200022f578182fd5b9392505050565b60805160a05160601c60c05160601c6151bd620002ea600039600081816103a601528181610e1b01528181610f9a015281816114b7015281816115900152611bc601526000818161020d01528181610466015281816107d301528181610b8801528181611198015281816121a101528181612659015281816128f601528181612f5f0152818161362901528181613dfd015281816143cf01526147cd0152600081816103620152611dec01526151bd6000f3fe608060405234801561001057600080fd5b50600436106101775760003560e01c806392ae3764116100d8578063c2fb26a61161008c578063f851a44011610066578063f851a440146103a1578063f8eaad35146103c8578063ffa1ad74146103db57600080fd5b8063c2fb26a61461035d578063d0886f9714610384578063d2144f581461038e57600080fd5b8063a102e384116100bd578063a102e384146102ee578063a3f4df7e14610301578063aba287011461034a57600080fd5b806392ae3764146102c857806399b64de1146102db57600080fd5b806333c810e91161012f57806340d37cdf1161011457806340d37cdf1461028057806351cff8d9146102935780637a9262a2146102a857600080fd5b806333c810e9146102475780633e1608b41461026d57600080fd5b8063288cdc9111610160578063288cdc91146101b75780632ac12622146101e55780632e25d2a61461020857600080fd5b80630908ff2d1461017c578063154e0f2e146101a4575b600080fd5b61018f61018a366004614e03565b610417565b60405190151581526020015b60405180910390f35b61018f6101b2366004614e03565b610784565b6101d76101c5366004614f31565b60016020526000908152604090205481565b60405190815260200161019b565b61018f6101f3366004614f31565b60006020819052908152604090205460ff1681565b61022f7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b03909116815260200161019b565b61025a610255366004614f31565b610a0b565b60405161ffff909116815260200161019b565b61018f61027b366004614f49565b610a43565b61018f61028e366004614dd8565b610b40565b6102a66102a1366004614da0565b610e19565b005b6101d76102b6366004614da0565b60026020526000908152604090205481565b61018f6102d6366004614e03565b6110b4565b61018f6102e9366004614faa565b6114b3565b6102a66102fc366004614da0565b61158e565b61033d6040518060400160405280600e81526020017f53776976656c2046696e616e636500000000000000000000000000000000000081525081565b60405161019b9190615015565b61018f610358366004614e37565b611622565b6101d77f000000000000000000000000000000000000000000000000000000000000000081565b6101d76203f48081565b61018f61039c366004614e37565b6118fa565b61022f7f000000000000000000000000000000000000000000000000000000000000000081565b6102a66103d6366004614da0565b611bc4565b61033d6040518060400160405280600581526020017f322e302e3000000000000000000000000000000000000000000000000000000081525081565b6040517fb50a66f70000000000000000000000000000000000000000000000000000000081526001600160a01b03848116600483015260248201849052336044830152606482018390526000917f00000000000000000000000000000000000000000000000000000000000000009182169063b50a66f790608401602060405180830381600087803b1580156104ac57600080fd5b505af11580156104c0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104e49190614f15565b61055b5760405162461bcd60e51b815260206004820152602560248201527f6275726e205a63546f6b656e2072656d6f76696e67204e6f74696f6e616c206660448201527f61696c656400000000000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b6040517f05e1dc250000000000000000000000000000000000000000000000000000000081526001600160a01b03868116600483015260248201869052600091908316906305e1dc2590604401602060405180830381600087803b1580156105c257600080fd5b505af11580156105d6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105fa9190614dbc565b6040517f852a12e3000000000000000000000000000000000000000000000000000000008152600481018690529091506001600160a01b0382169063852a12e390602401602060405180830381600087803b15801561065857600080fd5b505af115801561066c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106909190614fdc565b156106dd5760405162461bcd60e51b815260206004820152601960248201527f636f6d706f756e6420726564656d7074696f6e206572726f72000000000000006044820152606401610552565b6040517fa9059cbb000000000000000000000000000000000000000000000000000000008152336004820152602481018590526001600160a01b0387169063a9059cbb906044015b602060405180830381600087803b15801561073f57600080fd5b505af1158015610753573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107779190614f15565b5060019695505050505050565b6040517fc5ee114d0000000000000000000000000000000000000000000000000000000081526001600160a01b03848116600483015260248201849052336044830152606482018390526000917f00000000000000000000000000000000000000000000000000000000000000009183919083169063c5ee114d90608401602060405180830381600087803b15801561081c57600080fd5b505af1158015610830573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108549190614fdc565b6040517f05e1dc250000000000000000000000000000000000000000000000000000000081526001600160a01b03888116600483015260248201889052919250908316906305e1dc2590604401602060405180830381600087803b1580156108bb57600080fd5b505af11580156108cf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108f39190614dbc565b6001600160a01b031663852a12e3826040518263ffffffff1660e01b815260040161092091815260200190565b602060405180830381600087803b15801561093a57600080fd5b505af115801561094e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109729190614fdc565b156109bf5760405162461bcd60e51b815260206004820152601a60248201527f636f6d706f756e6420726564656d7074696f6e206661696c65640000000000006044820152606401610552565b6040517fa9059cbb000000000000000000000000000000000000000000000000000000008152336004820152602481018290526001600160a01b0387169063a9059cbb90604401610725565b60038181548110610a1b57600080fd5b9060005260206000209060109182820401919006600202915054906101000a900461ffff1681565b600080610a508484611d01565b9050610a626040850160208601614da0565b6001600160a01b0316336001600160a01b031614610ac25760405162461bcd60e51b815260206004820152601460248201527f73656e646572206d757374206265206d616b65720000000000000000000000006044820152606401610552565b6000818152602081905260409081902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055518435907f9e5d8891dc1b047de610617bc9bc2d8ccffebbc3d63363431a546831245858a690610b2e9084815260200190565b60405180910390a25060019392505050565b6040517fa11f48560000000000000000000000000000000000000000000000000000000081526001600160a01b038381166004830152602482018390523360448301526000917f00000000000000000000000000000000000000000000000000000000000000009183919083169063a11f485690606401602060405180830381600087803b158015610bd157600080fd5b505af1158015610be5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c099190614fdc565b6040517f05e1dc250000000000000000000000000000000000000000000000000000000081526001600160a01b03878116600483015260248201879052919250908316906305e1dc2590604401602060405180830381600087803b158015610c7057600080fd5b505af1158015610c84573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ca89190614dbc565b6001600160a01b031663852a12e3826040518263ffffffff1660e01b8152600401610cd591815260200190565b602060405180830381600087803b158015610cef57600080fd5b505af1158015610d03573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d279190614fdc565b15610d745760405162461bcd60e51b815260206004820152601a60248201527f636f6d706f756e6420726564656d7074696f6e206661696c65640000000000006044820152606401610552565b6040517fa9059cbb000000000000000000000000000000000000000000000000000000008152336004820152602481018290526001600160a01b0386169063a9059cbb90604401602060405180830381600087803b158015610dd557600080fd5b505af1158015610de9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e0d9190614f15565b50600195945050505050565b7f0000000000000000000000000000000000000000000000000000000000000000336001600160a01b03821614610e925760405162461bcd60e51b815260206004820152601460248201527f73656e646572206d7573742062652061646d696e0000000000000000000000006044820152606401610552565b6001600160a01b03821660009081526002602052604090205480610ef85760405162461bcd60e51b815260206004820152601760248201527f6e6f207769746864726177616c207363686564756c65640000000000000000006044820152606401610552565b80421015610f485760405162461bcd60e51b815260206004820152601860248201527f7769746864726177616c207374696c6c206f6e20686f6c6400000000000000006044820152606401610552565b6001600160a01b03831660008181526002602052604080822091909155517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015284919063a9059cbb907f00000000000000000000000000000000000000000000000000000000000000009083906370a0823190602401602060405180830381600087803b158015610fdf57600080fd5b505af1158015610ff3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110179190614fdc565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381600087803b15801561107557600080fd5b505af1158015611089573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110ad9190614f15565b5050505050565b6040517f23b872dd0000000000000000000000000000000000000000000000000000000081523360048201523060248201526044810182905260009084906001600160a01b038216906323b872dd90606401602060405180830381600087803b15801561112057600080fd5b505af1158015611134573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111589190614f15565b506040517f05e1dc250000000000000000000000000000000000000000000000000000000081526001600160a01b038681166004830152602482018690527f0000000000000000000000000000000000000000000000000000000000000000916000918316906305e1dc2590604401602060405180830381600087803b1580156111e157600080fd5b505af11580156111f5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112199190614dbc565b6040517f095ea7b30000000000000000000000000000000000000000000000000000000081526001600160a01b038083166004830152602482018890529192509084169063095ea7b390604401602060405180830381600087803b15801561128057600080fd5b505af1158015611294573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112b89190614f15565b506040517fa0712d68000000000000000000000000000000000000000000000000000000008152600481018690526001600160a01b0382169063a0712d6890602401602060405180830381600087803b15801561131457600080fd5b505af1158015611328573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061134c9190614fdc565b156113995760405162461bcd60e51b815260206004820152601560248201527f6d696e74696e672043546f6b656e204661696c656400000000000000000000006044820152606401610552565b6040517fef267f2c0000000000000000000000000000000000000000000000000000000081526001600160a01b038881166004830152602482018890523360448301526064820187905283169063ef267f2c90608401602060405180830381600087803b15801561140957600080fd5b505af115801561141d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114419190614f15565b6107775760405162461bcd60e51b815260206004820152602360248201527f6d696e74205a63546f6b656e20616464696e67204e6f74696f6e616c2066616960448201527f6c656400000000000000000000000000000000000000000000000000000000006064820152608401610552565b60007f0000000000000000000000000000000000000000000000000000000000000000336001600160a01b0382161461152e5760405162461bcd60e51b815260206004820152601460248201527f73656e646572206d7573742062652061646d696e0000000000000000000000006044820152606401610552565b8260038561ffff168154811061155457634e487b7160e01b600052603260045260246000fd5b90600052602060002090601091828204019190066002026101000a81548161ffff021916908361ffff160217905550600191505092915050565b7f0000000000000000000000000000000000000000000000000000000000000000336001600160a01b038216146116075760405162461bcd60e51b815260206004820152601460248201527f73656e646572206d7573742062652061646d696e0000000000000000000000006044820152606401610552565b506001600160a01b0316600090815260026020526040812055565b6000805b868110156118ec5787878281811061164e57634e487b7160e01b600052603260045260246000fd5b9050610120020160800160208101906116679190614ef9565b6117a55787878281811061168b57634e487b7160e01b600052603260045260246000fd5b9050610120020160600160208101906116a49190614ef9565b611729576117248888838181106116cb57634e487b7160e01b600052603260045260246000fd5b905061012002018787848181106116f257634e487b7160e01b600052603260045260246000fd5b9050602002013586868581811061171957634e487b7160e01b600052603260045260246000fd5b905060600201611e9b565b6118da565b61172488888381811061174c57634e487b7160e01b600052603260045260246000fd5b9050610120020187878481811061177357634e487b7160e01b600052603260045260246000fd5b9050602002013586868581811061179a57634e487b7160e01b600052603260045260246000fd5b90506060020161237d565b8787828181106117c557634e487b7160e01b600052603260045260246000fd5b9050610120020160600160208101906117de9190614ef9565b61185e5761172488888381811061180557634e487b7160e01b600052603260045260246000fd5b9050610120020187878481811061182c57634e487b7160e01b600052603260045260246000fd5b9050602002013586868581811061185357634e487b7160e01b600052603260045260246000fd5b9050606002016127a0565b6118da88888381811061188157634e487b7160e01b600052603260045260246000fd5b905061012002018787848181106118a857634e487b7160e01b600052603260045260246000fd5b905060200201358686858181106118cf57634e487b7160e01b600052603260045260246000fd5b905060600201612e08565b806118e481615112565b915050611626565b506001979650505050505050565b6000805b868110156118ec5787878281811061192657634e487b7160e01b600052603260045260246000fd5b90506101200201608001602081019061193f9190614ef9565b611a7d5787878281811061196357634e487b7160e01b600052603260045260246000fd5b90506101200201606001602081019061197c9190614ef9565b611a01576119fc8888838181106119a357634e487b7160e01b600052603260045260246000fd5b905061012002018787848181106119ca57634e487b7160e01b600052603260045260246000fd5b905060200201358686858181106119f157634e487b7160e01b600052603260045260246000fd5b905060600201613340565b611bb2565b6119fc888883818110611a2457634e487b7160e01b600052603260045260246000fd5b90506101200201878784818110611a4b57634e487b7160e01b600052603260045260246000fd5b90506020020135868685818110611a7257634e487b7160e01b600052603260045260246000fd5b905060600201613b19565b878782818110611a9d57634e487b7160e01b600052603260045260246000fd5b905061012002016060016020810190611ab69190614ef9565b611b36576119fc888883818110611add57634e487b7160e01b600052603260045260246000fd5b90506101200201878784818110611b0457634e487b7160e01b600052603260045260246000fd5b90506020020135868685818110611b2b57634e487b7160e01b600052603260045260246000fd5b90506060020161418c565b611bb2888883818110611b5957634e487b7160e01b600052603260045260246000fd5b90506101200201878784818110611b8057634e487b7160e01b600052603260045260246000fd5b90506020020135868685818110611ba757634e487b7160e01b600052603260045260246000fd5b9050606002016145a7565b80611bbc81615112565b9150506118fe565b7f0000000000000000000000000000000000000000000000000000000000000000336001600160a01b03821614611c3d5760405162461bcd60e51b815260206004820152601460248201527f73656e646572206d7573742062652061646d696e0000000000000000000000006044820152606401610552565b6000611c4c6203f48042615086565b6001600160a01b0384166000818152600260205260409081902083905551919250907fd9cf0116e5bb6fbe3d257dc8d1ee7ae76c303efeae77f1e93024d2cb218bedd390611c9d9084815260200190565b60405180910390a2505050565b8351602094850120835193850193909320604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f815295860194909452928401929092526060830152608082015260a0902090565b600080611d0d84614a7b565b60008181526020819052604090205490915060ff1615611d6f5760405162461bcd60e51b815260206004820152600f60248201527f6f726465722063616e63656c6c656400000000000000000000000000000000006044820152606401610552565b428461010001351015611dc45760405162461bcd60e51b815260206004820152600d60248201527f6f726465722065787069726564000000000000000000000000000000000000006044820152606401610552565b6040517f190100000000000000000000000000000000000000000000000000000000000081527f000000000000000000000000000000000000000000000000000000000000000060028201526022810182905260429020611e259084614b79565b6001600160a01b0316611e3e6040860160208701614da0565b6001600160a01b031614611e945760405162461bcd60e51b815260206004820152601160248201527f696e76616c6964207369676e61747572650000000000000000000000000000006044820152606401610552565b9392505050565b6000611ea78483611d01565b600081815260016020526040902054909150611ec79060c08601356150fb565b831115611f165760405162461bcd60e51b815260206004820152601f60248201527f74616b657220616d6f756e74203e20617661696c61626c6520766f6c756d65006044820152606401610552565b60008181526001602052604081208054859290611f34908490615086565b9091555060009050670de0b6b3a764000060a086013560c0870135611f5987846150be565b611f63919061509e565b611f6d91906150be565b611f77919061509e565b90506000670de0b6b3a76400006003600181548110611fa657634e487b7160e01b600052603260045260246000fd5b60009182526020909120601082040154600f9091166002026101000a900461ffff16611fda84670de0b6b3a76400006150be565b611fe4919061509e565b611fee919061509e565b905060006120026060880160408901614da0565b90506001600160a01b0381166323b872dd61202360408a0160208b01614da0565b338561202f8b896150fb565b61203991906150fb565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b1681526001600160a01b0393841660048201529290911660248301526044820152606401602060405180830381600087803b1580156120a057600080fd5b505af11580156120b4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120d89190614f15565b506001600160a01b0381166323b872dd6120f860408a0160208b01614da0565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b03909116600482015230602482015260448101859052606401602060405180830381600087803b15801561215e57600080fd5b505af1158015612172573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121969190614f15565b506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166365a963aa6121d660608a0160408b01614da0565b60e08a0135336121ec60408d0160208e01614da0565b60405160e086901b7fffffffff000000000000000000000000000000000000000000000000000000001681526001600160a01b0394851660048201526024810193909352908316604483015290911660648201526084810186905260a401602060405180830381600087803b15801561226457600080fd5b505af1158015612278573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061229c9190614f15565b6122e85760405162461bcd60e51b815260206004820152601760248201527f7a63546f6b656e2065786368616e6765206661696c65640000000000000000006044820152606401610552565b336122f96040890160208a01614da0565b6001600160a01b031688357f51cad9177cf46d59109ae978bb3cf5ffed2bb3d53fb3682fa56fbd92667128348761233660808d0160608e01614ef9565b61234660a08e0160808f01614ef9565b604080519384529115156020840152151590820152606081018b90526080810188905260a00160405180910390a450505050505050565b60006123898483611d01565b6000818152600160205260409020549091506123a99060a08601356150fb565b8311156123f85760405162461bcd60e51b815260206004820152601f60248201527f74616b657220616d6f756e74203e20617661696c61626c6520766f6c756d65006044820152606401610552565b60008181526001602052604081208054859290612416908490615086565b9091555060009050670de0b6b3a764000060c086013560a087013561243b87846150be565b612445919061509e565b61244f91906150be565b612459919061509e565b90506000670de0b6b3a76400006003808154811061248757634e487b7160e01b600052603260045260246000fd5b60009182526020909120601082040154600f9091166002026101000a900461ffff166124bb84670de0b6b3a76400006150be565b6124c5919061509e565b6124cf919061509e565b905060006124e36060880160408901614da0565b90506001600160a01b0381166323b872dd61250460408a0160208b01614da0565b3361250f86886150fb565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b1681526001600160a01b0393841660048201529290911660248301526044820152606401602060405180830381600087803b15801561257657600080fd5b505af115801561258a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125ae9190614f15565b506040517f23b872dd000000000000000000000000000000000000000000000000000000008152336004820152306024820152604481018390526001600160a01b038216906323b872dd90606401602060405180830381600087803b15801561261657600080fd5b505af115801561262a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061264e9190614f15565b506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663bddbfbe461268e60608a0160408b01614da0565b60e08a0135336126a460408d0160208e01614da0565b60405160e086901b7fffffffff000000000000000000000000000000000000000000000000000000001681526001600160a01b0394851660048201526024810193909352908316604483015290911660648201526084810189905260a401602060405180830381600087803b15801561271c57600080fd5b505af1158015612730573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127549190614f15565b6122e85760405162461bcd60e51b815260206004820152601560248201527f7661756c742065786368616e6765206661696c656400000000000000000000006044820152606401610552565b60006127ac8483611d01565b6000818152600160205260409020549091506127cc9060a08601356150fb565b83111561281b5760405162461bcd60e51b815260206004820152601f60248201527f74616b657220616d6f756e74203e20617661696c61626c6520766f6c756d65006044820152606401610552565b60008181526001602052604081208054859290612839908490615086565b9091555060009050670de0b6b3a764000060c086013560a087013561285e87846150be565b612868919061509e565b61287291906150be565b61287c919061509e565b90506000670de0b6b3a7640000600380815481106128aa57634e487b7160e01b600052603260045260246000fd5b60009182526020909120601082040154600f9091166002026101000a900461ffff166128de84670de0b6b3a76400006150be565b6128e8919061509e565b6128f2919061509e565b90507f000000000000000000000000000000000000000000000000000000000000000060006001600160a01b0382166305e1dc2561293660608b0160408c01614da0565b60405160e083811b7fffffffff000000000000000000000000000000000000000000000000000000001682526001600160a01b03929092166004820152908b01356024820152604401602060405180830381600087803b15801561299957600080fd5b505af11580156129ad573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129d19190614dbc565b6040517f852a12e3000000000000000000000000000000000000000000000000000000008152600481018990529091506001600160a01b0382169063852a12e390602401602060405180830381600087803b158015612a2f57600080fd5b505af1158015612a43573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a679190614fdc565b15612ab45760405162461bcd60e51b815260206004820152601960248201527f636f6d706f756e6420726564656d7074696f6e206572726f72000000000000006044820152606401610552565b6000612ac660608a0160408b01614da0565b90506001600160a01b03811663a9059cbb612ae760408c0160208d01614da0565b612af1888c6150fb565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381600087803b158015612b4f57600080fd5b505af1158015612b63573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b879190614f15565b506001600160a01b03811663a9059cbb33612ba287896150fb565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381600087803b158015612c0057600080fd5b505af1158015612c14573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c389190614f15565b506001600160a01b038316638c6b9b41612c5860608c0160408d01614da0565b60e08c0135612c6d60408e0160208f01614da0565b60405160e085901b7fffffffff000000000000000000000000000000000000000000000000000000001681526001600160a01b03938416600482015260248101929092529091166044820152336064820152608481018b905260a4015b602060405180830381600087803b158015612ce457600080fd5b505af1158015612cf8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d1c9190614f15565b612d685760405162461bcd60e51b815260206004820152601560248201527f637573746f6469616c2065786974206661696c656400000000000000000000006044820152606401610552565b33612d7960408b0160208c01614da0565b6001600160a01b03168a600001357f51cad9177cf46d59109ae978bb3cf5ffed2bb3d53fb3682fa56fbd9266712834898d6060016020810190612dbc9190614ef9565b8e6080016020810190612dcf9190614ef9565b604080519384529115156020840152151590820152606081018d9052608081018a905260a00160405180910390a4505050505050505050565b6000612e148483611d01565b600081815260016020526040902054909150612e349060c08601356150fb565b831115612e835760405162461bcd60e51b815260206004820152601f60248201527f74616b657220616d6f756e74203e20617661696c61626c6520766f6c756d65006044820152606401610552565b60008181526001602052604081208054859290612ea1908490615086565b9091555060009050670de0b6b3a764000060a086013560c0870135612ec687846150be565b612ed0919061509e565b612eda91906150be565b612ee4919061509e565b90506000670de0b6b3a76400006003600181548110612f1357634e487b7160e01b600052603260045260246000fd5b60009182526020909120601082040154600f9091166002026101000a900461ffff16612f4784670de0b6b3a76400006150be565b612f51919061509e565b612f5b919061509e565b90507f000000000000000000000000000000000000000000000000000000000000000060006001600160a01b0382166305e1dc25612f9f60608b0160408c01614da0565b60405160e083811b7fffffffff000000000000000000000000000000000000000000000000000000001682526001600160a01b03929092166004820152908b01356024820152604401602060405180830381600087803b15801561300257600080fd5b505af1158015613016573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061303a9190614dbc565b6040517f852a12e3000000000000000000000000000000000000000000000000000000008152600481018690529091506001600160a01b0382169063852a12e390602401602060405180830381600087803b15801561309857600080fd5b505af11580156130ac573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130d09190614fdc565b1561311d5760405162461bcd60e51b815260206004820152601960248201527f636f6d706f756e6420726564656d7074696f6e206572726f72000000000000006044820152606401610552565b600061312f60608a0160408b01614da0565b90506001600160a01b03811663a9059cbb338661314c8c8a6150fb565b61315691906150fb565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381600087803b1580156131b457600080fd5b505af11580156131c8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131ec9190614f15565b506001600160a01b03811663a9059cbb61320c60408c0160208d01614da0565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602481018b9052604401602060405180830381600087803b15801561326c57600080fd5b505af1158015613280573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132a49190614f15565b506001600160a01b038316638c6b9b416132c460608c0160408d01614da0565b8b60e00135338d60200160208101906132dd9190614da0565b60405160e086901b7fffffffff000000000000000000000000000000000000000000000000000000001681526001600160a01b0394851660048201526024810193909352908316604483015290911660648201526084810188905260a401612cca565b600061334c8483611d01565b60008181526001602052604090205490915061336c9060c08601356150fb565b8311156133bb5760405162461bcd60e51b815260206004820152601f60248201527f74616b657220616d6f756e74203e20617661696c61626c6520766f6c756d65006044820152606401610552565b600081815260016020526040812080548592906133d9908490615086565b9091555060009050670de0b6b3a764000060a086013560c08701356133fe87846150be565b613408919061509e565b61341291906150be565b61341c919061509e565b90506000670de0b6b3a7640000600360028154811061344b57634e487b7160e01b600052603260045260246000fd5b60009182526020909120601082040154600f9091166002026101000a900461ffff1661347f84670de0b6b3a76400006150be565b613489919061509e565b613493919061509e565b905060006134a76060880160408901614da0565b90506001600160a01b0381166323b872dd336134c960408b0160208c01614da0565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b1681526001600160a01b0392831660048201529116602482015260448101899052606401602060405180830381600087803b15801561353057600080fd5b505af1158015613544573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135689190614f15565b506001600160a01b0381166323b872dd61358860408a0160208b01614da0565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b03909116600482015230602482015260448101869052606401602060405180830381600087803b1580156135ee57600080fd5b505af1158015613602573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136269190614f15565b507f000000000000000000000000000000000000000000000000000000000000000060006001600160a01b0382166305e1dc2561366960608c0160408d01614da0565b60405160e083811b7fffffffff000000000000000000000000000000000000000000000000000000001682526001600160a01b03929092166004820152908c01356024820152604401602060405180830381600087803b1580156136cc57600080fd5b505af11580156136e0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137049190614dbc565b6040517f095ea7b30000000000000000000000000000000000000000000000000000000081526001600160a01b038083166004830152602482018890529192509084169063095ea7b390604401602060405180830381600087803b15801561376b57600080fd5b505af115801561377f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137a39190614f15565b506040517fa0712d68000000000000000000000000000000000000000000000000000000008152600481018690526001600160a01b0382169063a0712d6890602401602060405180830381600087803b1580156137ff57600080fd5b505af1158015613813573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138379190614fdc565b156138845760405162461bcd60e51b815260206004820152601560248201527f6d696e74696e672043546f6b656e206661696c656400000000000000000000006044820152606401610552565b6001600160a01b03821663f8e51bcb6138a360608c0160408d01614da0565b60e08c01356138b860408e0160208f01614da0565b60405160e085901b7fffffffff000000000000000000000000000000000000000000000000000000001681526001600160a01b039384166004820152602481019290925290911660448201523360648201526084810188905260a401602060405180830381600087803b15801561392e57600080fd5b505af1158015613942573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139669190614f15565b6139b25760405162461bcd60e51b815260206004820152601960248201527f637573746f6469616c20696e697469617465206661696c6564000000000000006044820152606401610552565b6001600160a01b038216633cf9a4e36139d160608c0160408d01614da0565b60405160e083811b7fffffffff000000000000000000000000000000000000000000000000000000001682526001600160a01b03929092166004820152908c0135602482015233604482015260648101879052608401602060405180830381600087803b158015613a4157600080fd5b505af1158015613a55573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a799190614f15565b613ac55760405162461bcd60e51b815260206004820152601c60248201527f6e6f74696f6e616c20666565207472616e73666572206661696c6564000000006044820152606401610552565b33613ad660408b0160208c01614da0565b6001600160a01b03168a600001357f32bc401d77ffde781b234d480866e0c360e724770a30ea3299309f9171e400ef898d6060016020810190612dbc9190614ef9565b6000613b258483611d01565b600081815260016020526040902054909150613b459060a08601356150fb565b831115613b945760405162461bcd60e51b815260206004820152601f60248201527f74616b657220616d6f756e74203e20617661696c61626c6520766f6c756d65006044820152606401610552565b60008181526001602052604081208054859290613bb2908490615086565b9091555060009050670de0b6b3a764000060c086013560a0870135613bd787846150be565b613be1919061509e565b613beb91906150be565b613bf5919061509e565b90506000670de0b6b3a76400006003600081548110613c2457634e487b7160e01b600052603260045260246000fd5b60009182526020909120601082040154600f9091166002026101000a900461ffff16613c5884670de0b6b3a76400006150be565b613c62919061509e565b613c6c919061509e565b90506000613c806060880160408901614da0565b90506001600160a01b0381166323b872dd613ca160408a0160208b01614da0565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b03909116600482015233602482015260448101869052606401602060405180830381600087803b158015613d0757600080fd5b505af1158015613d1b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613d3f9190614f15565b506001600160a01b0381166323b872dd3330613d5b868b615086565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b1681526001600160a01b0393841660048201529290911660248301526044820152606401602060405180830381600087803b158015613dc257600080fd5b505af1158015613dd6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613dfa9190614f15565b507f000000000000000000000000000000000000000000000000000000000000000060006001600160a01b0382166305e1dc25613e3d60608c0160408d01614da0565b60405160e083811b7fffffffff000000000000000000000000000000000000000000000000000000001682526001600160a01b03929092166004820152908c01356024820152604401602060405180830381600087803b158015613ea057600080fd5b505af1158015613eb4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ed89190614dbc565b6040517f095ea7b30000000000000000000000000000000000000000000000000000000081526001600160a01b038083166004830152602482018b90529192509084169063095ea7b390604401602060405180830381600087803b158015613f3f57600080fd5b505af1158015613f53573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f779190614f15565b506040517fa0712d68000000000000000000000000000000000000000000000000000000008152600481018990526001600160a01b0382169063a0712d6890602401602060405180830381600087803b158015613fd357600080fd5b505af1158015613fe7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061400b9190614fdc565b156140585760405162461bcd60e51b815260206004820152601560248201527f6d696e74696e672043546f6b656e204661696c656400000000000000000000006044820152606401610552565b6001600160a01b03821663f8e51bcb61407760608c0160408d01614da0565b8b60e00135338d60200160208101906140909190614da0565b60405160e086901b7fffffffff000000000000000000000000000000000000000000000000000000001681526001600160a01b039485166004820152602481019390935290831660448301529091166064820152608481018b905260a401602060405180830381600087803b15801561410857600080fd5b505af115801561411c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141409190614f15565b613ac55760405162461bcd60e51b815260206004820152601960248201527f637573746f6469616c20696e697469617465206661696c6564000000000000006044820152606401610552565b60006141988483611d01565b6000818152600160205260409020549091506141b89060a08601356150fb565b8311156142075760405162461bcd60e51b815260206004820152601f60248201527f74616b657220616d6f756e74203e20617661696c61626c6520766f6c756d65006044820152606401610552565b60008181526001602052604081208054859290614225908490615086565b9091555060009050670de0b6b3a764000060c086013560a087013561424a87846150be565b614254919061509e565b61425e91906150be565b614268919061509e565b90506000670de0b6b3a7640000600360008154811061429757634e487b7160e01b600052603260045260246000fd5b60009182526020909120601082040154600f9091166002026101000a900461ffff166142cb84670de0b6b3a76400006150be565b6142d5919061509e565b6142df919061509e565b90506142f16060870160408801614da0565b6001600160a01b03166323b872dd3361431060408a0160208b01614da0565b8461431b878b6150fb565b6143259190615086565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b1681526001600160a01b0393841660048201529290911660248301526044820152606401602060405180830381600087803b15801561438c57600080fd5b505af11580156143a0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906143c49190614f15565b506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166365a963aa6144046060890160408a01614da0565b60e089013561441960408b0160208c01614da0565b60405160e085901b7fffffffff000000000000000000000000000000000000000000000000000000001681526001600160a01b039384166004820152602481019290925290911660448201523360648201526084810188905260a401602060405180830381600087803b15801561448f57600080fd5b505af11580156144a3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906144c79190614f15565b6145135760405162461bcd60e51b815260206004820152601760248201527f7a63546f6b656e2065786368616e6765206661696c65640000000000000000006044820152606401610552565b336145246040880160208901614da0565b6001600160a01b031687357f32bc401d77ffde781b234d480866e0c360e724770a30ea3299309f9171e400ef8661456160808c0160608d01614ef9565b61457160a08d0160808e01614ef9565b604080519384529115156020840152151590820152606081018a90526080810187905260a00160405180910390a4505050505050565b60006145b38483611d01565b6000818152600160205260409020549091506145d39060c08601356150fb565b8311156146225760405162461bcd60e51b815260206004820152601f60248201527f74616b657220616d6f756e74203e20617661696c61626c6520766f6c756d65006044820152606401610552565b60008181526001602052604081208054859290614640908490615086565b9091555060009050670de0b6b3a764000060a086013560c087013561466587846150be565b61466f919061509e565b61467991906150be565b614683919061509e565b90506000670de0b6b3a764000060036002815481106146b257634e487b7160e01b600052603260045260246000fd5b60009182526020909120601082040154600f9091166002026101000a900461ffff166146e684670de0b6b3a76400006150be565b6146f0919061509e565b6146fa919061509e565b905061470c6060870160408801614da0565b6001600160a01b03166323b872dd3361472b60408a0160208b01614da0565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b1681526001600160a01b0392831660048201529116602482015260448101889052606401602060405180830381600087803b15801561479257600080fd5b505af11580156147a6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906147ca9190614f15565b507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03811663bddbfbe461480b60608a0160408b01614da0565b60e08a013561482060408c0160208d01614da0565b60405160e085901b7fffffffff000000000000000000000000000000000000000000000000000000001681526001600160a01b039384166004820152602481019290925290911660448201523360648201526084810186905260a401602060405180830381600087803b15801561489657600080fd5b505af11580156148aa573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906148ce9190614f15565b61491a5760405162461bcd60e51b815260206004820152601560248201527f7661756c742065786368616e6765206661696c656400000000000000000000006044820152606401610552565b6001600160a01b038116633cf9a4e361493960608a0160408b01614da0565b60405160e083811b7fffffffff000000000000000000000000000000000000000000000000000000001682526001600160a01b03929092166004820152908a0135602482015233604482015260648101859052608401602060405180830381600087803b1580156149a957600080fd5b505af11580156149bd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906149e19190614f15565b614a2d5760405162461bcd60e51b815260206004820152601c60248201527f6e6f74696f6e616c20666565207472616e73666572206661696c6564000000006044820152606401610552565b33614a3e6040890160208a01614da0565b6001600160a01b031688357f32bc401d77ffde781b234d480866e0c360e724770a30ea3299309f9171e400ef8761233660808d0160608e01614ef9565b60007f7ddd38ab5ed1c16b61ca90eeb9579e29da1ba821cf42d8cdef8f30a31a6a41468235614ab06040850160208601614da0565b614ac06060860160408701614da0565b614ad06080870160608801614ef9565b614ae060a0880160808901614ef9565b8760a001358860c001358960e001358a6101000135604051602001614b5c9a99989796959493929190998a5260208a01989098526001600160a01b0396871660408a01529490951660608801529115156080870152151560a086015260c085015260e08401919091526101008301526101208201526101400190565b604051602081830303815290604052805190602001209050919050565b60007f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a060408301351115614bef5760405162461bcd60e51b815260206004820152601b60248201527f696e76616c6964207369676e6174757265202273222076616c756500000000006044820152606401610552565b614bfc6020830183614ff4565b60ff16601b1480614c1c5750614c156020830183614ff4565b60ff16601c145b614c685760405162461bcd60e51b815260206004820152601b60248201527f696e76616c6964207369676e6174757265202276222076616c756500000000006044820152606401610552565b600183614c786020850185614ff4565b604080516000815260208181018084529490945260ff9092168282015291850135606082015290840135608082015260a0016020604051602081039080840390855afa158015614ccc573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00151949350505050565b60008083601f840112614d0d578182fd5b50813567ffffffffffffffff811115614d24578182fd5b602083019150836020606083028501011115614d3f57600080fd5b9250929050565b60008083601f840112614d57578182fd5b50813567ffffffffffffffff811115614d6e578182fd5b6020830191508360208260051b8501011115614d3f57600080fd5b803561ffff81168114614d9b57600080fd5b919050565b600060208284031215614db1578081fd5b8135611e9481615161565b600060208284031215614dcd578081fd5b8151611e9481615161565b60008060408385031215614dea578081fd5b8235614df581615161565b946020939093013593505050565b600080600060608486031215614e17578081fd5b8335614e2281615161565b95602085013595506040909401359392505050565b60008060008060008060608789031215614e4f578182fd5b863567ffffffffffffffff80821115614e66578384fd5b818901915089601f830112614e79578384fd5b813581811115614e87578485fd5b8a602061012083028501011115614e9c578485fd5b602092830198509650908801359080821115614eb6578384fd5b614ec28a838b01614d46565b90965094506040890135915080821115614eda578384fd5b50614ee789828a01614cfc565b979a9699509497509295939492505050565b600060208284031215614f0a578081fd5b8135611e9481615179565b600060208284031215614f26578081fd5b8151611e9481615179565b600060208284031215614f42578081fd5b5035919050565b600080828403610180811215614f5d578283fd5b61012080821215614f6c578384fd5b84935060607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee083011215614f9e578283fd5b92959390920193505050565b60008060408385031215614fbc578182fd5b614fc583614d89565b9150614fd360208401614d89565b90509250929050565b600060208284031215614fed578081fd5b5051919050565b600060208284031215615005578081fd5b813560ff81168114611e94578182fd5b6000602080835283518082850152825b8181101561504157858101830151858201604001528201615025565b818111156150525783604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016929092016040019392505050565b600082198211156150995761509961514b565b500190565b6000826150b957634e487b7160e01b81526012600452602481fd5b500490565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156150f6576150f661514b565b500290565b60008282101561510d5761510d61514b565b500390565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8214156151445761514461514b565b5060010190565b634e487b7160e01b600052601160045260246000fd5b6001600160a01b038116811461517657600080fd5b50565b801515811461517657600080fdfea26469706673582212205f378ff9258482fd3585160b580b3ee430a16e6be0e73bb225aedf404ea77ccf64736f6c63430008040033 \ No newline at end of file diff --git a/gost/build/swivel/Swivel.sol b/gost/build/swivel/Swivel.sol new file mode 100644 index 0000000..d810c32 --- /dev/null +++ b/gost/build/swivel/Swivel.sol @@ -0,0 +1,490 @@ +// SPDX-License-Identifier: UNLICENSED + +pragma solidity 0.8.4; + +import './Abstracts.sol'; +import './Hash.sol'; +import './Sig.sol'; + +contract Swivel { + /// @dev maps the key of an order to a boolean indicating if an order was cancelled + mapping (bytes32 => bool) public cancelled; + /// @dev maps the key of an order to an amount representing its taken volume + mapping (bytes32 => uint256) public filled; + /// @dev maps a token address to a point in time, a hold, after which a withdrawal can be made + mapping (address => uint256) public withdrawals; + + string constant public NAME = 'Swivel Finance'; + string constant public VERSION = '2.0.0'; + uint256 constant public HOLD = 259200; // obvs could be a smaller uint but packing? + bytes32 public immutable domain; + address public immutable marketPlace; + address public immutable admin; + /// @dev holds the fee demoninators for [zcTokenInitiate, zcTokenExit, vaultInitiate, vaultExit] + uint16[] public fenominator; + + /// @notice Emitted on order cancellation + event Cancel (bytes32 indexed key, bytes32 hash); + /// @notice Emitted on any initiate* + /// @dev filled is 'principalFilled' when (vault:false, exit:false) && (vault:true, exit:true) + /// @dev filled is 'premiumFilled' when (vault:true, exit:false) && (vault:false, exit:true) + event Initiate(bytes32 indexed key, bytes32 hash, address indexed maker, bool vault, bool exit, address indexed sender, uint256 amount, uint256 filled); + /// @notice Emitted on any exit* + /// @dev filled is 'principalFilled' when (vault:false, exit:false) && (vault:true, exit:true) + /// @dev filled is 'premiumFilled' when (vault:true, exit:false) && (vault:false, exit:true) + event Exit(bytes32 indexed key, bytes32 hash, address indexed maker, bool vault, bool exit, address indexed sender, uint256 amount, uint256 filled); + /// @notice Emitted on token withdrawal scheduling + /// @dev token is the address of the token scheduled for withdrawal + /// @dev withdrawalTime is the timestamp at which the queued withdrawal will be possible + event WithdrawalScheduled (address indexed token, uint256 hold); + + /// @param m deployed MarketPlace contract address + constructor(address m) { + admin = msg.sender; + domain = Hash.domain(NAME, VERSION, block.chainid, address(this)); + marketPlace = m; + fenominator = [200, 600, 400, 200]; + } + + // ********* INITIATING ************* + + /// @notice Allows a user to initiate a position + /// @param o Array of offline Swivel.Orders + /// @param a Array of order volume (principal) amounts relative to passed orders + /// @param c Array of Components from valid ECDSA signatures + function initiate(Hash.Order[] calldata o, uint256[] calldata a, Sig.Components[] calldata c) external returns (bool) { + // for each order filled, routes the order to the right interaction depending on its params + for (uint256 i=0; i < o.length; i++) { + // If the order filled is NOT an exit + if (!o[i].exit) { + // if the order filled does NOT involve a vault (nTokens) + if (!o[i].vault) { + // then the user has called `initiate` against a zcToken initiate and msg.sender is initiating a vault (purchasing nTokens, payingPremium) + initiateVaultFillingZcTokenInitiate(o[i], a[i], c[i]); + } else { + // then the user has called `initiate` against a vault initiate and msg.sender is initiating a zcToken position (splitting and selling nTokens, receivingPremium) + initiateZcTokenFillingVaultInitiate(o[i], a[i], c[i]); + } + } else { + if (!o[i].vault) { + // then the user has called `initiate` against a zcToken exit and msg.sender is initiating a zcToken position (splitting and selling nTokens, receivingPremium) + initiateZcTokenFillingZcTokenExit(o[i], a[i], c[i]); + } else { + // then the user has called `initiate` against a vault exit (selling nTokens) and msg.sender is initiating a vault (purchasing nTokens, payingPremium) + initiateVaultFillingVaultExit(o[i], a[i], c[i]); + } + } + } + + return true; + } + + /// @notice Allows a user to initiate a Vault by filling an offline zcToken initiate order + /// @dev This method should pass (underlying, maturity, maker, sender, principalFilled) to MarketPlace.custodialInitiate + /// @param o Order being filled + /// @param a Amount of volume (premium) being filled by the taker's exit + /// @param c Components of a valid ECDSA signature + function initiateVaultFillingZcTokenInitiate(Hash.Order calldata o, uint256 a, Sig.Components calldata c) internal { + // checks order signature, order cancellation and order expiry + bytes32 hash = validOrderHash(o, c); + + // checks the taker amount passed to amount available in the order + require(a <= (o.premium - filled[hash]), 'taker amount > available volume'); + + // adds the taker amount to the order's filled amount + filled[hash] += a; + + // calculate principal filled and fee + uint256 principalFilled = (((a * 1e18) / o.premium) * o.principal) / 1e18; + uint256 fee = ((principalFilled * 1e18) / fenominator[2]) / 1e18; + + // transfer underlying tokens + Erc20 uToken = Erc20(o.underlying); + uToken.transferFrom(msg.sender, o.maker, a); + uToken.transferFrom(o.maker, address(this), principalFilled); + + // deposit underlying to Compound and mint cTokens + MarketPlace mPlace = MarketPlace(marketPlace); + address cTokenAddr = mPlace.cTokenAddress(o.underlying, o.maturity); + uToken.approve(cTokenAddr, principalFilled); + require(CErc20(cTokenAddr).mint(principalFilled) == 0, 'minting CToken failed'); + + // mint zcTokens + nTokens and allocate appropriately in marketplace + require(mPlace.custodialInitiate(o.underlying, o.maturity, o.maker, msg.sender, principalFilled), 'custodial initiate failed'); + + // transfer fee in vault notional to swivel (from msg.sender) + require(mPlace.transferVaultNotionalFee(o.underlying, o.maturity, msg.sender, fee), "notional fee transfer failed"); + + emit Initiate(o.key, hash, o.maker, o.vault, o.exit, msg.sender, a, principalFilled); + } + + /// @notice Allows a user to initiate a zcToken by filling an offline vault initiate order + /// @dev This method should pass (underlying, maturity, sender, maker, a) to MarketPlace.custodialInitiate + /// @param o Order being filled + /// @param o Amount of volume (principal) being filled by the taker's exit + /// @param c Components of a valid ECDSA signature + function initiateZcTokenFillingVaultInitiate(Hash.Order calldata o, uint256 a, Sig.Components calldata c) internal { + bytes32 hash = validOrderHash(o, c); + + require((a <= o.principal - filled[hash]), 'taker amount > available volume'); + + filled[hash] += a; + + uint256 premiumFilled = (((a * 1e18) / o.principal) * o.premium) / 1e18; + uint256 fee = ((premiumFilled * 1e18) / fenominator[0]) / 1e18; + + Erc20 uToken = Erc20(o.underlying); + uToken.transferFrom(o.maker, msg.sender, premiumFilled); + // transfer principal + fee in underlying to swivel (from sender) + uToken.transferFrom(msg.sender, address(this), (a + fee)); + + // deposit underlying to Compound and mint cTokens + MarketPlace mPlace = MarketPlace(marketPlace); + address cTokenAddr = mPlace.cTokenAddress(o.underlying, o.maturity); + uToken.approve(cTokenAddr, a); + require(CErc20(cTokenAddr).mint(a) == 0, 'minting CToken Failed'); + + // mint zcTokens + nTokens and allocate appropriately in marketplace + require(mPlace.custodialInitiate(o.underlying, o.maturity, msg.sender, o.maker, a), 'custodial initiate failed'); + + emit Initiate(o.key, hash, o.maker, o.vault, o.exit, msg.sender, a, premiumFilled); + } + + /// @notice Allows a user to initiate zcToken? by filling an offline zcToken exit order + /// @dev This method should pass (underlying, maturity, maker, sender, a) to MarketPlace.p2pZcTokenExchange + /// @param o Order being filled + /// @param a Amount of volume (principal) being filled by the taker's exit + /// @param c Components of a valid ECDSA signature + function initiateZcTokenFillingZcTokenExit(Hash.Order calldata o, uint256 a, Sig.Components calldata c) internal { + bytes32 hash = validOrderHash(o, c); + + require(a <= ((o.principal - filled[hash])), 'taker amount > available volume'); + + filled[hash] += a; + + uint256 premiumFilled = (((a * 1e18) / o.principal) * o.premium) / 1e18; + uint256 fee = ((premiumFilled * 1e18) / fenominator[0]) / 1e18; + + // transfer underlying tokens - the premium paid + fee in underlying to swivel (from sender) + Erc20(o.underlying).transferFrom(msg.sender, o.maker, ((a - premiumFilled) + fee)); + // transfer zcTokens between users in marketplace + require(MarketPlace(marketPlace).p2pZcTokenExchange(o.underlying, o.maturity, o.maker, msg.sender, a), 'zcToken exchange failed'); + + emit Initiate(o.key, hash, o.maker, o.vault, o.exit, msg.sender, a, premiumFilled); + } + + /// @notice Allows a user to initiate a Vault by filling an offline vault exit order + /// @dev This method should pass (underlying, maturity, maker, sender, principalFilled) to MarketPlace.p2pVaultExchange + /// @param o Order being filled + /// @param a Amount of volume (interest) being filled by the taker's exit + /// @param c Components of a valid ECDSA signature + function initiateVaultFillingVaultExit(Hash.Order calldata o, uint256 a, Sig.Components calldata c) internal { + bytes32 hash = validOrderHash(o, c); + + require(a <= (o.premium - filled[hash]), 'taker amount > available volume'); + + filled[hash] += a; + + uint256 principalFilled = (((a * 1e18) / o.premium) * o.principal) / 1e18; + uint256 fee = ((principalFilled * 1e18) / fenominator[2]) / 1e18; + + Erc20(o.underlying).transferFrom(msg.sender, o.maker, a); + + MarketPlace mPlace = MarketPlace(marketPlace); + // transfer vault.notional (nTokens) between users in marketplace + require(mPlace.p2pVaultExchange(o.underlying, o.maturity, o.maker, msg.sender, principalFilled), 'vault exchange failed'); + + // transfer fee (in nTokens) to swivel + require(mPlace.transferVaultNotionalFee(o.underlying, o.maturity, msg.sender, fee), "notional fee transfer failed"); + + emit Initiate(o.key, hash, o.maker, o.vault, o.exit, msg.sender, a, principalFilled); + } + + // ********* EXITING *************** + + /// @notice Allows a user to exit (sell) a currently held position to the marketplace. + /// @param o Array of offline Swivel.Orders + /// @param a Array of order volume (principal) amounts relative to passed orders + /// @param c Components of a valid ECDSA signature + function exit(Hash.Order[] calldata o, uint256[] calldata a, Sig.Components[] calldata c) external returns (bool) { + // for each order filled, routes the order to the right interaction depending on its params + for (uint256 i=0; i < o.length; i++) { + // if the order is NOT an exit + if (!o[i].exit) { + // if the order filled does NOT involve a vault (nTokens) + if (!o[i].vault) { + // then the user has called `exit` against a zcToken initiate and msg.sender is exiting zcTokens (buying nTokens + redeeming, payingPremium) + exitZcTokenFillingZcTokenInitiate(o[i], a[i], c[i]); + } else { + // then the user has called `exit` against a vault initiate and msg.sender is exiting nTokens (selling nTokens, receivingPremium) + exitVaultFillingVaultInitiate(o[i], a[i], c[i]); + } + } else { + if (!o[i].vault) { + // then the user has called `exit` against a zcToken exit and msg.sender is exiting nTokens (selling nTokens, receivingPremium) + exitVaultFillingZcTokenExit(o[i], a[i], c[i]); + } else { + // then the user has called `exit` against a vault exit and msg.sender is exiting zcTokens (buying nTokens + redeeming, payingPremium) + exitZcTokenFillingVaultExit(o[i], a[i], c[i]); + } + } + } + + return true; + } + + /// @notice Allows a user to exit their zcTokens by filling an offline zcToken initiate order + /// @dev This method should pass (underlying, maturity, sender, maker, principalFilled) to MarketPlace.p2pZcTokenExchange + /// @param o Order being filled + /// @param a Amount of volume (interest) being filled by the taker's exit + /// @param c Components of a valid ECDSA signature + function exitZcTokenFillingZcTokenInitiate(Hash.Order calldata o, uint256 a, Sig.Components calldata c) internal { + bytes32 hash = validOrderHash(o, c); + + require(a <= (o.premium - filled[hash]), 'taker amount > available volume'); + + filled[hash] += a; + + uint256 principalFilled = (((a * 1e18) / o.premium) * o.principal) / 1e18; + uint256 fee = ((principalFilled * 1e18) / fenominator[1]) / 1e18; + + Erc20 uToken = Erc20(o.underlying); + // transfer underlying from initiating party to exiting party, minus the price the exit party pays for the exit (premium), and the fee. + uToken.transferFrom(o.maker, msg.sender, principalFilled - a - fee); + // transfer fee in underlying to swivel + uToken.transferFrom(o.maker, address(this), fee); + + // transfer zcTokens from msg.sender to o.maker + require(MarketPlace(marketPlace).p2pZcTokenExchange(o.underlying, o.maturity, msg.sender, o.maker, principalFilled), 'zcToken exchange failed'); + + emit Exit(o.key, hash, o.maker, o.vault, o.exit, msg.sender, a, principalFilled); + } + + /// @notice Allows a user to exit their Vault by filling an offline vault initiate order + /// @dev This method should pass (underlying, maturity, sender, maker, a) to MarketPlace.p2pVaultExchange + /// @param o Order being filled + /// @param a Amount of volume (principal) being filled by the taker's exit + /// @param c Components of a valid ECDSA signature + function exitVaultFillingVaultInitiate(Hash.Order calldata o, uint256 a, Sig.Components calldata c) internal { + bytes32 hash = validOrderHash(o, c); + + require(a <= (o.principal - filled[hash]), 'taker amount > available volume'); + + filled[hash] += a; + + uint256 premiumFilled = (((a * 1e18) / o.principal) * o.premium) / 1e18; + uint256 fee = ((premiumFilled * 1e18) / fenominator[3]) / 1e18; + + Erc20 uToken = Erc20(o.underlying); + // transfer premium minus fee from maker to sender + uToken.transferFrom(o.maker, msg.sender, premiumFilled - fee); + + // transfer fee in underlying to swivel from sender + uToken.transferFrom(msg.sender, address(this), fee); + + // transfer vault.notional (nTokens) from sender to maker + require(MarketPlace(marketPlace).p2pVaultExchange(o.underlying, o.maturity, msg.sender, o.maker, a), 'vault exchange failed'); + + emit Exit(o.key, hash, o.maker, o.vault, o.exit, msg.sender, a, premiumFilled); + } + + /// @notice Allows a user to exit their Vault filling an offline zcToken exit order + /// @dev This method should pass (underlying, maturity, maker, sender, a) to MarketPlace.exitFillingExit + /// @param o Order being filled + /// @param a Amount of volume (principal) being filled by the taker's exit + /// @param c Components of a valid ECDSA signature + function exitVaultFillingZcTokenExit(Hash.Order calldata o, uint256 a, Sig.Components calldata c) internal { + bytes32 hash = validOrderHash(o, c); + + require(a <= (o.principal - filled[hash]), 'taker amount > available volume'); + + filled[hash] += a; + + uint256 premiumFilled = (((a * 1e18) / o.principal) * o.premium) / 1e18; + uint256 fee = ((premiumFilled * 1e18) / fenominator[3]) / 1e18; + + // redeem underlying on Compound and burn cTokens + MarketPlace mPlace = MarketPlace(marketPlace); + address cTokenAddr = mPlace.cTokenAddress(o.underlying, o.maturity); + require((CErc20(cTokenAddr).redeemUnderlying(a) == 0), "compound redemption error"); + + Erc20 uToken = Erc20(o.underlying); + // transfer principal-premium back to fixed exit party now that the interest coupon and zcb have been redeemed + uToken.transfer(o.maker, a - premiumFilled); + // transfer premium-fee to floating exit party + uToken.transfer(msg.sender, premiumFilled - fee); + + // burn zcTokens + nTokens from o.maker and msg.sender respectively + require(mPlace.custodialExit(o.underlying, o.maturity, o.maker, msg.sender, a), 'custodial exit failed'); + + + emit Exit(o.key, hash, o.maker, o.vault, o.exit, msg.sender, a, premiumFilled); + } + + /// @notice Allows a user to exit their zcTokens by filling an offline vault exit order + /// @dev This method should pass (underlying, maturity, sender, maker, principalFilled) to MarketPlace.exitFillingExit + /// @param o Order being filled + /// @param a Amount of volume (interest) being filled by the taker's exit + /// @param c Components of a valid ECDSA signature + function exitZcTokenFillingVaultExit(Hash.Order calldata o, uint256 a, Sig.Components calldata c) internal { + bytes32 hash = validOrderHash(o, c); + + require(a <= (o.premium - filled[hash]), 'taker amount > available volume'); + + filled[hash] += a; + + uint256 principalFilled = (((a * 1e18) / o.premium) * o.principal) / 1e18; + uint256 fee = ((principalFilled * 1e18) / fenominator[1]) / 1e18; + + // redeem underlying on Compound and burn cTokens + MarketPlace mPlace = MarketPlace(marketPlace); + address cTokenAddr = mPlace.cTokenAddress(o.underlying, o.maturity); + require((CErc20(cTokenAddr).redeemUnderlying(principalFilled) == 0), "compound redemption error"); + + Erc20 uToken = Erc20(o.underlying); + // transfer principal-premium-fee back to fixed exit party now that the interest coupon and zcb have been redeemed + uToken.transfer(msg.sender, principalFilled - a - fee); + uToken.transfer(o.maker, a); + + // burn zcTokens + nTokens from msg.sender and o.maker respectively + require(mPlace.custodialExit(o.underlying, o.maturity, msg.sender, o.maker, principalFilled), 'custodial exit failed'); + + emit Exit(o.key, hash, o.maker, o.vault, o.exit, msg.sender, a, principalFilled); + } + + /// @notice Allows a user to cancel an order, preventing it from being filled in the future + /// @param o Order being cancelled + /// @param c Components of a valid ECDSA signature + function cancel(Hash.Order calldata o, Sig.Components calldata c) external returns (bool) { + bytes32 hash = validOrderHash(o, c); + + require(msg.sender == o.maker, 'sender must be maker'); + + cancelled[hash] = true; + + emit Cancel(o.key, hash); + + return true; + } + + // ********* ADMINISTRATIVE *************** + + /// @notice Allows the admin to schedule the withdrawal of tokens + /// @param e Address of token to withdraw + function scheduleWithdrawal(address e) external onlyAdmin(admin) { + uint256 when = block.timestamp + HOLD; + withdrawals[e] = when; + emit WithdrawalScheduled(e, when); + } + + /// @notice Emergency function to block unplanned withdrawals + /// @param e Address of token withdrawal to block + function blockWithdrawal(address e) external onlyAdmin(admin) { + withdrawals[e] = 0; + } + + /// @notice Allows the admin to withdraw the given token, provided the holding period has been observed + /// @param e Address of token to withdraw + function withdraw(address e) external onlyAdmin(admin) { + uint256 when = withdrawals[e]; + require (when != 0, 'no withdrawal scheduled'); + require (block.timestamp >= when, 'withdrawal still on hold'); + + withdrawals[e] = 0; + + Erc20 token = Erc20(e); + token.transfer(admin, token.balanceOf(address(this))); + } + + /// @notice Allows the admin to set a new fee denominator + /// @param t The index of the new fee denominator + /// @param d The new fee denominator + function setFee(uint16 t, uint16 d) external onlyAdmin(admin) returns (bool) { + fenominator[t] = d; + return true; + } + + // ********* PROTOCOL UTILITY *************** + + /// @notice Allows users to deposit underlying and in the process split it into/mint + /// zcTokens and vault notional. Calls mPlace.mintZcTokenAddingNotional + /// @param u Underlying token address associated with the market + /// @param m Maturity timestamp of the market + /// @param a Amount of underlying being deposited + function splitUnderlying(address u, uint256 m, uint256 a) external returns (bool) { + Erc20 uToken = Erc20(u); + uToken.transferFrom(msg.sender, address(this), a); + MarketPlace mPlace = MarketPlace(marketPlace); + address cTokenAddr = mPlace.cTokenAddress(u, m); + uToken.approve(cTokenAddr, a); + require(CErc20(cTokenAddr).mint(a) == 0, 'minting CToken Failed'); + require(mPlace.mintZcTokenAddingNotional(u, m, msg.sender, a), 'mint ZcToken adding Notional failed'); + + return true; + } + + /// @notice Allows users deposit/burn 1-1 amounts of both zcTokens and vault notional, + /// in the process "combining" the two, and redeeming underlying. Calls mPlace.burnZcTokenRemovingNotional. + /// @param u Underlying token address associated with the market + /// @param m Maturity timestamp of the market + /// @param a Amount of zcTokens being redeemed + function combineTokens(address u, uint256 m, uint256 a) external returns (bool) { + MarketPlace mPlace = MarketPlace(marketPlace); + require(mPlace.burnZcTokenRemovingNotional(u, m, msg.sender, a), 'burn ZcToken removing Notional failed'); + address cTokenAddr = mPlace.cTokenAddress(u, m); + require((CErc20(cTokenAddr).redeemUnderlying(a) == 0), "compound redemption error"); + Erc20(u).transfer(msg.sender, a); + + return true; + } + + /// @notice Allows zcToken holders to redeem their tokens for underlying tokens after maturity has been reached (via MarketPlace). + /// @param u Underlying token address associated with the market + /// @param m Maturity timestamp of the market + /// @param a Amount of zcTokens being redeemed + function redeemZcToken(address u, uint256 m, uint256 a) external returns (bool) { + MarketPlace mPlace = MarketPlace(marketPlace); + // call marketplace to determine the amount redeemed + uint256 redeemed = mPlace.redeemZcToken(u, m, msg.sender, a); + // redeem underlying from compound + require(CErc20(mPlace.cTokenAddress(u, m)).redeemUnderlying(redeemed) == 0, 'compound redemption failed'); + // transfer underlying back to msg.sender + Erc20(u).transfer(msg.sender, redeemed); + + return true; + } + + /// @notice Allows Vault owners to redeem any currently accrued interest (via MarketPlace) + /// @param u Underlying token address associated with the market + /// @param m Maturity timestamp of the market + function redeemVaultInterest(address u, uint256 m) external returns (bool) { + MarketPlace mPlace = MarketPlace(marketPlace); + // call marketplace to determine the amount redeemed + uint256 redeemed = mPlace.redeemVaultInterest(u, m, msg.sender); + // redeem underlying from compound + require(CErc20(mPlace.cTokenAddress(u, m)).redeemUnderlying(redeemed) == 0, 'compound redemption failed'); + // transfer underlying back to msg.sender + Erc20(u).transfer(msg.sender, redeemed); + + return true; + } + + /// @notice Varifies the validity of an order and it's signature. + /// @param o An offline Swivel.Order + /// @param c Components of a valid ECDSA signature + /// @return the hashed order. + function validOrderHash(Hash.Order calldata o, Sig.Components calldata c) internal view returns (bytes32) { + bytes32 hash = Hash.order(o); + + require(!cancelled[hash], 'order cancelled'); + require(o.expiry >= block.timestamp, 'order expired'); + require(o.maker == Sig.recover(Hash.message(domain, hash), c), 'invalid signature'); + + return hash; + } + + modifier onlyAdmin(address a) { + require(msg.sender == a, 'sender must be admin'); + _; + } +} diff --git a/gost/build/swivel/swivel.go b/gost/build/swivel/swivel.go new file mode 100644 index 0000000..ba7eb25 --- /dev/null +++ b/gost/build/swivel/swivel.go @@ -0,0 +1,1382 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package swivel + +import ( + "math/big" + "strings" + + ethereum "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/event" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription +) + +// HashOrder is an auto generated low-level Go binding around an user-defined struct. +type HashOrder struct { + Key [32]byte + Maker common.Address + Underlying common.Address + Vault bool + Exit bool + Principal *big.Int + Premium *big.Int + Maturity *big.Int + Expiry *big.Int +} + +// SigComponents is an auto generated low-level Go binding around an user-defined struct. +type SigComponents struct { + V uint8 + R [32]byte + S [32]byte +} + +// SwivelABI is the input ABI used to generate the binding from. +const SwivelABI = "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"m\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"key\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"hash\",\"type\":\"bytes32\"}],\"name\":\"Cancel\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"key\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"hash\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"maker\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"vault\",\"type\":\"bool\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"exit\",\"type\":\"bool\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"filled\",\"type\":\"uint256\"}],\"name\":\"Exit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"key\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"hash\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"maker\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"vault\",\"type\":\"bool\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"exit\",\"type\":\"bool\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"filled\",\"type\":\"uint256\"}],\"name\":\"Initiate\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"hold\",\"type\":\"uint256\"}],\"name\":\"WithdrawalScheduled\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"HOLD\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"NAME\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"VERSION\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"admin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"e\",\"type\":\"address\"}],\"name\":\"blockWithdrawal\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"key\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"maker\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"underlying\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"vault\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"exit\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"principal\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"premium\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maturity\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"expiry\",\"type\":\"uint256\"}],\"internalType\":\"structHash.Order\",\"name\":\"o\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"r\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"s\",\"type\":\"bytes32\"}],\"internalType\":\"structSig.Components\",\"name\":\"c\",\"type\":\"tuple\"}],\"name\":\"cancel\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"cancelled\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"u\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"m\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"a\",\"type\":\"uint256\"}],\"name\":\"combineTokens\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"domain\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"key\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"maker\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"underlying\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"vault\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"exit\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"principal\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"premium\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maturity\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"expiry\",\"type\":\"uint256\"}],\"internalType\":\"structHash.Order[]\",\"name\":\"o\",\"type\":\"tuple[]\"},{\"internalType\":\"uint256[]\",\"name\":\"a\",\"type\":\"uint256[]\"},{\"components\":[{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"r\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"s\",\"type\":\"bytes32\"}],\"internalType\":\"structSig.Components[]\",\"name\":\"c\",\"type\":\"tuple[]\"}],\"name\":\"exit\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"fenominator\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"filled\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"key\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"maker\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"underlying\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"vault\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"exit\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"principal\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"premium\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maturity\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"expiry\",\"type\":\"uint256\"}],\"internalType\":\"structHash.Order[]\",\"name\":\"o\",\"type\":\"tuple[]\"},{\"internalType\":\"uint256[]\",\"name\":\"a\",\"type\":\"uint256[]\"},{\"components\":[{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"r\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"s\",\"type\":\"bytes32\"}],\"internalType\":\"structSig.Components[]\",\"name\":\"c\",\"type\":\"tuple[]\"}],\"name\":\"initiate\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"marketPlace\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"u\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"m\",\"type\":\"uint256\"}],\"name\":\"redeemVaultInterest\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"u\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"m\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"a\",\"type\":\"uint256\"}],\"name\":\"redeemZcToken\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"e\",\"type\":\"address\"}],\"name\":\"scheduleWithdrawal\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint16\",\"name\":\"t\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"d\",\"type\":\"uint16\"}],\"name\":\"setFee\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"u\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"m\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"a\",\"type\":\"uint256\"}],\"name\":\"splitUnderlying\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"e\",\"type\":\"address\"}],\"name\":\"withdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"withdrawals\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]" + +// SwivelBin is the compiled bytecode used for deploying new contracts. +var SwivelBin = "0x60e06040523480156200001157600080fd5b50604051620054a7380380620054a7833981016040819052620000349162000206565b3360601b60c052604080518082018252600e81526d53776976656c2046696e616e636560901b602080830191909152825180840190935260058352640322e302e360dc1b838201526200009592904690309062001caa620000e8821b17901c565b6080908152606082811b6001600160601b03191660a05260408051928301815260c880845261025860208501526101909184019190915290820152620000e09060039060046200013f565b505062000236565b8351602094850120835193850193909320604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f815295860194909452928401929092526060830152608082015260a0902090565b82805482825590600052602060002090600f01601090048101928215620001dd5791602002820160005b83821115620001ab57835183826101000a81548161ffff021916908361ffff160217905550926020019260020160208160010104928301926001030262000169565b8015620001db5782816101000a81549061ffff0219169055600201602081600101049283019260010302620001ab565b505b50620001eb929150620001ef565b5090565b5b80821115620001eb5760008155600101620001f0565b60006020828403121562000218578081fd5b81516001600160a01b03811681146200022f578182fd5b9392505050565b60805160a05160601c60c05160601c6151bd620002ea600039600081816103a601528181610e1b01528181610f9a015281816114b7015281816115900152611bc601526000818161020d01528181610466015281816107d301528181610b8801528181611198015281816121a101528181612659015281816128f601528181612f5f0152818161362901528181613dfd015281816143cf01526147cd0152600081816103620152611dec01526151bd6000f3fe608060405234801561001057600080fd5b50600436106101775760003560e01c806392ae3764116100d8578063c2fb26a61161008c578063f851a44011610066578063f851a440146103a1578063f8eaad35146103c8578063ffa1ad74146103db57600080fd5b8063c2fb26a61461035d578063d0886f9714610384578063d2144f581461038e57600080fd5b8063a102e384116100bd578063a102e384146102ee578063a3f4df7e14610301578063aba287011461034a57600080fd5b806392ae3764146102c857806399b64de1146102db57600080fd5b806333c810e91161012f57806340d37cdf1161011457806340d37cdf1461028057806351cff8d9146102935780637a9262a2146102a857600080fd5b806333c810e9146102475780633e1608b41461026d57600080fd5b8063288cdc9111610160578063288cdc91146101b75780632ac12622146101e55780632e25d2a61461020857600080fd5b80630908ff2d1461017c578063154e0f2e146101a4575b600080fd5b61018f61018a366004614e03565b610417565b60405190151581526020015b60405180910390f35b61018f6101b2366004614e03565b610784565b6101d76101c5366004614f31565b60016020526000908152604090205481565b60405190815260200161019b565b61018f6101f3366004614f31565b60006020819052908152604090205460ff1681565b61022f7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b03909116815260200161019b565b61025a610255366004614f31565b610a0b565b60405161ffff909116815260200161019b565b61018f61027b366004614f49565b610a43565b61018f61028e366004614dd8565b610b40565b6102a66102a1366004614da0565b610e19565b005b6101d76102b6366004614da0565b60026020526000908152604090205481565b61018f6102d6366004614e03565b6110b4565b61018f6102e9366004614faa565b6114b3565b6102a66102fc366004614da0565b61158e565b61033d6040518060400160405280600e81526020017f53776976656c2046696e616e636500000000000000000000000000000000000081525081565b60405161019b9190615015565b61018f610358366004614e37565b611622565b6101d77f000000000000000000000000000000000000000000000000000000000000000081565b6101d76203f48081565b61018f61039c366004614e37565b6118fa565b61022f7f000000000000000000000000000000000000000000000000000000000000000081565b6102a66103d6366004614da0565b611bc4565b61033d6040518060400160405280600581526020017f322e302e3000000000000000000000000000000000000000000000000000000081525081565b6040517fb50a66f70000000000000000000000000000000000000000000000000000000081526001600160a01b03848116600483015260248201849052336044830152606482018390526000917f00000000000000000000000000000000000000000000000000000000000000009182169063b50a66f790608401602060405180830381600087803b1580156104ac57600080fd5b505af11580156104c0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104e49190614f15565b61055b5760405162461bcd60e51b815260206004820152602560248201527f6275726e205a63546f6b656e2072656d6f76696e67204e6f74696f6e616c206660448201527f61696c656400000000000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b6040517f05e1dc250000000000000000000000000000000000000000000000000000000081526001600160a01b03868116600483015260248201869052600091908316906305e1dc2590604401602060405180830381600087803b1580156105c257600080fd5b505af11580156105d6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105fa9190614dbc565b6040517f852a12e3000000000000000000000000000000000000000000000000000000008152600481018690529091506001600160a01b0382169063852a12e390602401602060405180830381600087803b15801561065857600080fd5b505af115801561066c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106909190614fdc565b156106dd5760405162461bcd60e51b815260206004820152601960248201527f636f6d706f756e6420726564656d7074696f6e206572726f72000000000000006044820152606401610552565b6040517fa9059cbb000000000000000000000000000000000000000000000000000000008152336004820152602481018590526001600160a01b0387169063a9059cbb906044015b602060405180830381600087803b15801561073f57600080fd5b505af1158015610753573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107779190614f15565b5060019695505050505050565b6040517fc5ee114d0000000000000000000000000000000000000000000000000000000081526001600160a01b03848116600483015260248201849052336044830152606482018390526000917f00000000000000000000000000000000000000000000000000000000000000009183919083169063c5ee114d90608401602060405180830381600087803b15801561081c57600080fd5b505af1158015610830573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108549190614fdc565b6040517f05e1dc250000000000000000000000000000000000000000000000000000000081526001600160a01b03888116600483015260248201889052919250908316906305e1dc2590604401602060405180830381600087803b1580156108bb57600080fd5b505af11580156108cf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108f39190614dbc565b6001600160a01b031663852a12e3826040518263ffffffff1660e01b815260040161092091815260200190565b602060405180830381600087803b15801561093a57600080fd5b505af115801561094e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109729190614fdc565b156109bf5760405162461bcd60e51b815260206004820152601a60248201527f636f6d706f756e6420726564656d7074696f6e206661696c65640000000000006044820152606401610552565b6040517fa9059cbb000000000000000000000000000000000000000000000000000000008152336004820152602481018290526001600160a01b0387169063a9059cbb90604401610725565b60038181548110610a1b57600080fd5b9060005260206000209060109182820401919006600202915054906101000a900461ffff1681565b600080610a508484611d01565b9050610a626040850160208601614da0565b6001600160a01b0316336001600160a01b031614610ac25760405162461bcd60e51b815260206004820152601460248201527f73656e646572206d757374206265206d616b65720000000000000000000000006044820152606401610552565b6000818152602081905260409081902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055518435907f9e5d8891dc1b047de610617bc9bc2d8ccffebbc3d63363431a546831245858a690610b2e9084815260200190565b60405180910390a25060019392505050565b6040517fa11f48560000000000000000000000000000000000000000000000000000000081526001600160a01b038381166004830152602482018390523360448301526000917f00000000000000000000000000000000000000000000000000000000000000009183919083169063a11f485690606401602060405180830381600087803b158015610bd157600080fd5b505af1158015610be5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c099190614fdc565b6040517f05e1dc250000000000000000000000000000000000000000000000000000000081526001600160a01b03878116600483015260248201879052919250908316906305e1dc2590604401602060405180830381600087803b158015610c7057600080fd5b505af1158015610c84573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ca89190614dbc565b6001600160a01b031663852a12e3826040518263ffffffff1660e01b8152600401610cd591815260200190565b602060405180830381600087803b158015610cef57600080fd5b505af1158015610d03573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d279190614fdc565b15610d745760405162461bcd60e51b815260206004820152601a60248201527f636f6d706f756e6420726564656d7074696f6e206661696c65640000000000006044820152606401610552565b6040517fa9059cbb000000000000000000000000000000000000000000000000000000008152336004820152602481018290526001600160a01b0386169063a9059cbb90604401602060405180830381600087803b158015610dd557600080fd5b505af1158015610de9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e0d9190614f15565b50600195945050505050565b7f0000000000000000000000000000000000000000000000000000000000000000336001600160a01b03821614610e925760405162461bcd60e51b815260206004820152601460248201527f73656e646572206d7573742062652061646d696e0000000000000000000000006044820152606401610552565b6001600160a01b03821660009081526002602052604090205480610ef85760405162461bcd60e51b815260206004820152601760248201527f6e6f207769746864726177616c207363686564756c65640000000000000000006044820152606401610552565b80421015610f485760405162461bcd60e51b815260206004820152601860248201527f7769746864726177616c207374696c6c206f6e20686f6c6400000000000000006044820152606401610552565b6001600160a01b03831660008181526002602052604080822091909155517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015284919063a9059cbb907f00000000000000000000000000000000000000000000000000000000000000009083906370a0823190602401602060405180830381600087803b158015610fdf57600080fd5b505af1158015610ff3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110179190614fdc565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381600087803b15801561107557600080fd5b505af1158015611089573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110ad9190614f15565b5050505050565b6040517f23b872dd0000000000000000000000000000000000000000000000000000000081523360048201523060248201526044810182905260009084906001600160a01b038216906323b872dd90606401602060405180830381600087803b15801561112057600080fd5b505af1158015611134573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111589190614f15565b506040517f05e1dc250000000000000000000000000000000000000000000000000000000081526001600160a01b038681166004830152602482018690527f0000000000000000000000000000000000000000000000000000000000000000916000918316906305e1dc2590604401602060405180830381600087803b1580156111e157600080fd5b505af11580156111f5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112199190614dbc565b6040517f095ea7b30000000000000000000000000000000000000000000000000000000081526001600160a01b038083166004830152602482018890529192509084169063095ea7b390604401602060405180830381600087803b15801561128057600080fd5b505af1158015611294573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112b89190614f15565b506040517fa0712d68000000000000000000000000000000000000000000000000000000008152600481018690526001600160a01b0382169063a0712d6890602401602060405180830381600087803b15801561131457600080fd5b505af1158015611328573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061134c9190614fdc565b156113995760405162461bcd60e51b815260206004820152601560248201527f6d696e74696e672043546f6b656e204661696c656400000000000000000000006044820152606401610552565b6040517fef267f2c0000000000000000000000000000000000000000000000000000000081526001600160a01b038881166004830152602482018890523360448301526064820187905283169063ef267f2c90608401602060405180830381600087803b15801561140957600080fd5b505af115801561141d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114419190614f15565b6107775760405162461bcd60e51b815260206004820152602360248201527f6d696e74205a63546f6b656e20616464696e67204e6f74696f6e616c2066616960448201527f6c656400000000000000000000000000000000000000000000000000000000006064820152608401610552565b60007f0000000000000000000000000000000000000000000000000000000000000000336001600160a01b0382161461152e5760405162461bcd60e51b815260206004820152601460248201527f73656e646572206d7573742062652061646d696e0000000000000000000000006044820152606401610552565b8260038561ffff168154811061155457634e487b7160e01b600052603260045260246000fd5b90600052602060002090601091828204019190066002026101000a81548161ffff021916908361ffff160217905550600191505092915050565b7f0000000000000000000000000000000000000000000000000000000000000000336001600160a01b038216146116075760405162461bcd60e51b815260206004820152601460248201527f73656e646572206d7573742062652061646d696e0000000000000000000000006044820152606401610552565b506001600160a01b0316600090815260026020526040812055565b6000805b868110156118ec5787878281811061164e57634e487b7160e01b600052603260045260246000fd5b9050610120020160800160208101906116679190614ef9565b6117a55787878281811061168b57634e487b7160e01b600052603260045260246000fd5b9050610120020160600160208101906116a49190614ef9565b611729576117248888838181106116cb57634e487b7160e01b600052603260045260246000fd5b905061012002018787848181106116f257634e487b7160e01b600052603260045260246000fd5b9050602002013586868581811061171957634e487b7160e01b600052603260045260246000fd5b905060600201611e9b565b6118da565b61172488888381811061174c57634e487b7160e01b600052603260045260246000fd5b9050610120020187878481811061177357634e487b7160e01b600052603260045260246000fd5b9050602002013586868581811061179a57634e487b7160e01b600052603260045260246000fd5b90506060020161237d565b8787828181106117c557634e487b7160e01b600052603260045260246000fd5b9050610120020160600160208101906117de9190614ef9565b61185e5761172488888381811061180557634e487b7160e01b600052603260045260246000fd5b9050610120020187878481811061182c57634e487b7160e01b600052603260045260246000fd5b9050602002013586868581811061185357634e487b7160e01b600052603260045260246000fd5b9050606002016127a0565b6118da88888381811061188157634e487b7160e01b600052603260045260246000fd5b905061012002018787848181106118a857634e487b7160e01b600052603260045260246000fd5b905060200201358686858181106118cf57634e487b7160e01b600052603260045260246000fd5b905060600201612e08565b806118e481615112565b915050611626565b506001979650505050505050565b6000805b868110156118ec5787878281811061192657634e487b7160e01b600052603260045260246000fd5b90506101200201608001602081019061193f9190614ef9565b611a7d5787878281811061196357634e487b7160e01b600052603260045260246000fd5b90506101200201606001602081019061197c9190614ef9565b611a01576119fc8888838181106119a357634e487b7160e01b600052603260045260246000fd5b905061012002018787848181106119ca57634e487b7160e01b600052603260045260246000fd5b905060200201358686858181106119f157634e487b7160e01b600052603260045260246000fd5b905060600201613340565b611bb2565b6119fc888883818110611a2457634e487b7160e01b600052603260045260246000fd5b90506101200201878784818110611a4b57634e487b7160e01b600052603260045260246000fd5b90506020020135868685818110611a7257634e487b7160e01b600052603260045260246000fd5b905060600201613b19565b878782818110611a9d57634e487b7160e01b600052603260045260246000fd5b905061012002016060016020810190611ab69190614ef9565b611b36576119fc888883818110611add57634e487b7160e01b600052603260045260246000fd5b90506101200201878784818110611b0457634e487b7160e01b600052603260045260246000fd5b90506020020135868685818110611b2b57634e487b7160e01b600052603260045260246000fd5b90506060020161418c565b611bb2888883818110611b5957634e487b7160e01b600052603260045260246000fd5b90506101200201878784818110611b8057634e487b7160e01b600052603260045260246000fd5b90506020020135868685818110611ba757634e487b7160e01b600052603260045260246000fd5b9050606002016145a7565b80611bbc81615112565b9150506118fe565b7f0000000000000000000000000000000000000000000000000000000000000000336001600160a01b03821614611c3d5760405162461bcd60e51b815260206004820152601460248201527f73656e646572206d7573742062652061646d696e0000000000000000000000006044820152606401610552565b6000611c4c6203f48042615086565b6001600160a01b0384166000818152600260205260409081902083905551919250907fd9cf0116e5bb6fbe3d257dc8d1ee7ae76c303efeae77f1e93024d2cb218bedd390611c9d9084815260200190565b60405180910390a2505050565b8351602094850120835193850193909320604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f815295860194909452928401929092526060830152608082015260a0902090565b600080611d0d84614a7b565b60008181526020819052604090205490915060ff1615611d6f5760405162461bcd60e51b815260206004820152600f60248201527f6f726465722063616e63656c6c656400000000000000000000000000000000006044820152606401610552565b428461010001351015611dc45760405162461bcd60e51b815260206004820152600d60248201527f6f726465722065787069726564000000000000000000000000000000000000006044820152606401610552565b6040517f190100000000000000000000000000000000000000000000000000000000000081527f000000000000000000000000000000000000000000000000000000000000000060028201526022810182905260429020611e259084614b79565b6001600160a01b0316611e3e6040860160208701614da0565b6001600160a01b031614611e945760405162461bcd60e51b815260206004820152601160248201527f696e76616c6964207369676e61747572650000000000000000000000000000006044820152606401610552565b9392505050565b6000611ea78483611d01565b600081815260016020526040902054909150611ec79060c08601356150fb565b831115611f165760405162461bcd60e51b815260206004820152601f60248201527f74616b657220616d6f756e74203e20617661696c61626c6520766f6c756d65006044820152606401610552565b60008181526001602052604081208054859290611f34908490615086565b9091555060009050670de0b6b3a764000060a086013560c0870135611f5987846150be565b611f63919061509e565b611f6d91906150be565b611f77919061509e565b90506000670de0b6b3a76400006003600181548110611fa657634e487b7160e01b600052603260045260246000fd5b60009182526020909120601082040154600f9091166002026101000a900461ffff16611fda84670de0b6b3a76400006150be565b611fe4919061509e565b611fee919061509e565b905060006120026060880160408901614da0565b90506001600160a01b0381166323b872dd61202360408a0160208b01614da0565b338561202f8b896150fb565b61203991906150fb565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b1681526001600160a01b0393841660048201529290911660248301526044820152606401602060405180830381600087803b1580156120a057600080fd5b505af11580156120b4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120d89190614f15565b506001600160a01b0381166323b872dd6120f860408a0160208b01614da0565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b03909116600482015230602482015260448101859052606401602060405180830381600087803b15801561215e57600080fd5b505af1158015612172573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121969190614f15565b506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166365a963aa6121d660608a0160408b01614da0565b60e08a0135336121ec60408d0160208e01614da0565b60405160e086901b7fffffffff000000000000000000000000000000000000000000000000000000001681526001600160a01b0394851660048201526024810193909352908316604483015290911660648201526084810186905260a401602060405180830381600087803b15801561226457600080fd5b505af1158015612278573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061229c9190614f15565b6122e85760405162461bcd60e51b815260206004820152601760248201527f7a63546f6b656e2065786368616e6765206661696c65640000000000000000006044820152606401610552565b336122f96040890160208a01614da0565b6001600160a01b031688357f51cad9177cf46d59109ae978bb3cf5ffed2bb3d53fb3682fa56fbd92667128348761233660808d0160608e01614ef9565b61234660a08e0160808f01614ef9565b604080519384529115156020840152151590820152606081018b90526080810188905260a00160405180910390a450505050505050565b60006123898483611d01565b6000818152600160205260409020549091506123a99060a08601356150fb565b8311156123f85760405162461bcd60e51b815260206004820152601f60248201527f74616b657220616d6f756e74203e20617661696c61626c6520766f6c756d65006044820152606401610552565b60008181526001602052604081208054859290612416908490615086565b9091555060009050670de0b6b3a764000060c086013560a087013561243b87846150be565b612445919061509e565b61244f91906150be565b612459919061509e565b90506000670de0b6b3a76400006003808154811061248757634e487b7160e01b600052603260045260246000fd5b60009182526020909120601082040154600f9091166002026101000a900461ffff166124bb84670de0b6b3a76400006150be565b6124c5919061509e565b6124cf919061509e565b905060006124e36060880160408901614da0565b90506001600160a01b0381166323b872dd61250460408a0160208b01614da0565b3361250f86886150fb565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b1681526001600160a01b0393841660048201529290911660248301526044820152606401602060405180830381600087803b15801561257657600080fd5b505af115801561258a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125ae9190614f15565b506040517f23b872dd000000000000000000000000000000000000000000000000000000008152336004820152306024820152604481018390526001600160a01b038216906323b872dd90606401602060405180830381600087803b15801561261657600080fd5b505af115801561262a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061264e9190614f15565b506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663bddbfbe461268e60608a0160408b01614da0565b60e08a0135336126a460408d0160208e01614da0565b60405160e086901b7fffffffff000000000000000000000000000000000000000000000000000000001681526001600160a01b0394851660048201526024810193909352908316604483015290911660648201526084810189905260a401602060405180830381600087803b15801561271c57600080fd5b505af1158015612730573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127549190614f15565b6122e85760405162461bcd60e51b815260206004820152601560248201527f7661756c742065786368616e6765206661696c656400000000000000000000006044820152606401610552565b60006127ac8483611d01565b6000818152600160205260409020549091506127cc9060a08601356150fb565b83111561281b5760405162461bcd60e51b815260206004820152601f60248201527f74616b657220616d6f756e74203e20617661696c61626c6520766f6c756d65006044820152606401610552565b60008181526001602052604081208054859290612839908490615086565b9091555060009050670de0b6b3a764000060c086013560a087013561285e87846150be565b612868919061509e565b61287291906150be565b61287c919061509e565b90506000670de0b6b3a7640000600380815481106128aa57634e487b7160e01b600052603260045260246000fd5b60009182526020909120601082040154600f9091166002026101000a900461ffff166128de84670de0b6b3a76400006150be565b6128e8919061509e565b6128f2919061509e565b90507f000000000000000000000000000000000000000000000000000000000000000060006001600160a01b0382166305e1dc2561293660608b0160408c01614da0565b60405160e083811b7fffffffff000000000000000000000000000000000000000000000000000000001682526001600160a01b03929092166004820152908b01356024820152604401602060405180830381600087803b15801561299957600080fd5b505af11580156129ad573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129d19190614dbc565b6040517f852a12e3000000000000000000000000000000000000000000000000000000008152600481018990529091506001600160a01b0382169063852a12e390602401602060405180830381600087803b158015612a2f57600080fd5b505af1158015612a43573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a679190614fdc565b15612ab45760405162461bcd60e51b815260206004820152601960248201527f636f6d706f756e6420726564656d7074696f6e206572726f72000000000000006044820152606401610552565b6000612ac660608a0160408b01614da0565b90506001600160a01b03811663a9059cbb612ae760408c0160208d01614da0565b612af1888c6150fb565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381600087803b158015612b4f57600080fd5b505af1158015612b63573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b879190614f15565b506001600160a01b03811663a9059cbb33612ba287896150fb565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381600087803b158015612c0057600080fd5b505af1158015612c14573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c389190614f15565b506001600160a01b038316638c6b9b41612c5860608c0160408d01614da0565b60e08c0135612c6d60408e0160208f01614da0565b60405160e085901b7fffffffff000000000000000000000000000000000000000000000000000000001681526001600160a01b03938416600482015260248101929092529091166044820152336064820152608481018b905260a4015b602060405180830381600087803b158015612ce457600080fd5b505af1158015612cf8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d1c9190614f15565b612d685760405162461bcd60e51b815260206004820152601560248201527f637573746f6469616c2065786974206661696c656400000000000000000000006044820152606401610552565b33612d7960408b0160208c01614da0565b6001600160a01b03168a600001357f51cad9177cf46d59109ae978bb3cf5ffed2bb3d53fb3682fa56fbd9266712834898d6060016020810190612dbc9190614ef9565b8e6080016020810190612dcf9190614ef9565b604080519384529115156020840152151590820152606081018d9052608081018a905260a00160405180910390a4505050505050505050565b6000612e148483611d01565b600081815260016020526040902054909150612e349060c08601356150fb565b831115612e835760405162461bcd60e51b815260206004820152601f60248201527f74616b657220616d6f756e74203e20617661696c61626c6520766f6c756d65006044820152606401610552565b60008181526001602052604081208054859290612ea1908490615086565b9091555060009050670de0b6b3a764000060a086013560c0870135612ec687846150be565b612ed0919061509e565b612eda91906150be565b612ee4919061509e565b90506000670de0b6b3a76400006003600181548110612f1357634e487b7160e01b600052603260045260246000fd5b60009182526020909120601082040154600f9091166002026101000a900461ffff16612f4784670de0b6b3a76400006150be565b612f51919061509e565b612f5b919061509e565b90507f000000000000000000000000000000000000000000000000000000000000000060006001600160a01b0382166305e1dc25612f9f60608b0160408c01614da0565b60405160e083811b7fffffffff000000000000000000000000000000000000000000000000000000001682526001600160a01b03929092166004820152908b01356024820152604401602060405180830381600087803b15801561300257600080fd5b505af1158015613016573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061303a9190614dbc565b6040517f852a12e3000000000000000000000000000000000000000000000000000000008152600481018690529091506001600160a01b0382169063852a12e390602401602060405180830381600087803b15801561309857600080fd5b505af11580156130ac573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130d09190614fdc565b1561311d5760405162461bcd60e51b815260206004820152601960248201527f636f6d706f756e6420726564656d7074696f6e206572726f72000000000000006044820152606401610552565b600061312f60608a0160408b01614da0565b90506001600160a01b03811663a9059cbb338661314c8c8a6150fb565b61315691906150fb565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381600087803b1580156131b457600080fd5b505af11580156131c8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131ec9190614f15565b506001600160a01b03811663a9059cbb61320c60408c0160208d01614da0565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602481018b9052604401602060405180830381600087803b15801561326c57600080fd5b505af1158015613280573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132a49190614f15565b506001600160a01b038316638c6b9b416132c460608c0160408d01614da0565b8b60e00135338d60200160208101906132dd9190614da0565b60405160e086901b7fffffffff000000000000000000000000000000000000000000000000000000001681526001600160a01b0394851660048201526024810193909352908316604483015290911660648201526084810188905260a401612cca565b600061334c8483611d01565b60008181526001602052604090205490915061336c9060c08601356150fb565b8311156133bb5760405162461bcd60e51b815260206004820152601f60248201527f74616b657220616d6f756e74203e20617661696c61626c6520766f6c756d65006044820152606401610552565b600081815260016020526040812080548592906133d9908490615086565b9091555060009050670de0b6b3a764000060a086013560c08701356133fe87846150be565b613408919061509e565b61341291906150be565b61341c919061509e565b90506000670de0b6b3a7640000600360028154811061344b57634e487b7160e01b600052603260045260246000fd5b60009182526020909120601082040154600f9091166002026101000a900461ffff1661347f84670de0b6b3a76400006150be565b613489919061509e565b613493919061509e565b905060006134a76060880160408901614da0565b90506001600160a01b0381166323b872dd336134c960408b0160208c01614da0565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b1681526001600160a01b0392831660048201529116602482015260448101899052606401602060405180830381600087803b15801561353057600080fd5b505af1158015613544573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135689190614f15565b506001600160a01b0381166323b872dd61358860408a0160208b01614da0565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b03909116600482015230602482015260448101869052606401602060405180830381600087803b1580156135ee57600080fd5b505af1158015613602573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136269190614f15565b507f000000000000000000000000000000000000000000000000000000000000000060006001600160a01b0382166305e1dc2561366960608c0160408d01614da0565b60405160e083811b7fffffffff000000000000000000000000000000000000000000000000000000001682526001600160a01b03929092166004820152908c01356024820152604401602060405180830381600087803b1580156136cc57600080fd5b505af11580156136e0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137049190614dbc565b6040517f095ea7b30000000000000000000000000000000000000000000000000000000081526001600160a01b038083166004830152602482018890529192509084169063095ea7b390604401602060405180830381600087803b15801561376b57600080fd5b505af115801561377f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137a39190614f15565b506040517fa0712d68000000000000000000000000000000000000000000000000000000008152600481018690526001600160a01b0382169063a0712d6890602401602060405180830381600087803b1580156137ff57600080fd5b505af1158015613813573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138379190614fdc565b156138845760405162461bcd60e51b815260206004820152601560248201527f6d696e74696e672043546f6b656e206661696c656400000000000000000000006044820152606401610552565b6001600160a01b03821663f8e51bcb6138a360608c0160408d01614da0565b60e08c01356138b860408e0160208f01614da0565b60405160e085901b7fffffffff000000000000000000000000000000000000000000000000000000001681526001600160a01b039384166004820152602481019290925290911660448201523360648201526084810188905260a401602060405180830381600087803b15801561392e57600080fd5b505af1158015613942573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139669190614f15565b6139b25760405162461bcd60e51b815260206004820152601960248201527f637573746f6469616c20696e697469617465206661696c6564000000000000006044820152606401610552565b6001600160a01b038216633cf9a4e36139d160608c0160408d01614da0565b60405160e083811b7fffffffff000000000000000000000000000000000000000000000000000000001682526001600160a01b03929092166004820152908c0135602482015233604482015260648101879052608401602060405180830381600087803b158015613a4157600080fd5b505af1158015613a55573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a799190614f15565b613ac55760405162461bcd60e51b815260206004820152601c60248201527f6e6f74696f6e616c20666565207472616e73666572206661696c6564000000006044820152606401610552565b33613ad660408b0160208c01614da0565b6001600160a01b03168a600001357f32bc401d77ffde781b234d480866e0c360e724770a30ea3299309f9171e400ef898d6060016020810190612dbc9190614ef9565b6000613b258483611d01565b600081815260016020526040902054909150613b459060a08601356150fb565b831115613b945760405162461bcd60e51b815260206004820152601f60248201527f74616b657220616d6f756e74203e20617661696c61626c6520766f6c756d65006044820152606401610552565b60008181526001602052604081208054859290613bb2908490615086565b9091555060009050670de0b6b3a764000060c086013560a0870135613bd787846150be565b613be1919061509e565b613beb91906150be565b613bf5919061509e565b90506000670de0b6b3a76400006003600081548110613c2457634e487b7160e01b600052603260045260246000fd5b60009182526020909120601082040154600f9091166002026101000a900461ffff16613c5884670de0b6b3a76400006150be565b613c62919061509e565b613c6c919061509e565b90506000613c806060880160408901614da0565b90506001600160a01b0381166323b872dd613ca160408a0160208b01614da0565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b03909116600482015233602482015260448101869052606401602060405180830381600087803b158015613d0757600080fd5b505af1158015613d1b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613d3f9190614f15565b506001600160a01b0381166323b872dd3330613d5b868b615086565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b1681526001600160a01b0393841660048201529290911660248301526044820152606401602060405180830381600087803b158015613dc257600080fd5b505af1158015613dd6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613dfa9190614f15565b507f000000000000000000000000000000000000000000000000000000000000000060006001600160a01b0382166305e1dc25613e3d60608c0160408d01614da0565b60405160e083811b7fffffffff000000000000000000000000000000000000000000000000000000001682526001600160a01b03929092166004820152908c01356024820152604401602060405180830381600087803b158015613ea057600080fd5b505af1158015613eb4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ed89190614dbc565b6040517f095ea7b30000000000000000000000000000000000000000000000000000000081526001600160a01b038083166004830152602482018b90529192509084169063095ea7b390604401602060405180830381600087803b158015613f3f57600080fd5b505af1158015613f53573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f779190614f15565b506040517fa0712d68000000000000000000000000000000000000000000000000000000008152600481018990526001600160a01b0382169063a0712d6890602401602060405180830381600087803b158015613fd357600080fd5b505af1158015613fe7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061400b9190614fdc565b156140585760405162461bcd60e51b815260206004820152601560248201527f6d696e74696e672043546f6b656e204661696c656400000000000000000000006044820152606401610552565b6001600160a01b03821663f8e51bcb61407760608c0160408d01614da0565b8b60e00135338d60200160208101906140909190614da0565b60405160e086901b7fffffffff000000000000000000000000000000000000000000000000000000001681526001600160a01b039485166004820152602481019390935290831660448301529091166064820152608481018b905260a401602060405180830381600087803b15801561410857600080fd5b505af115801561411c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141409190614f15565b613ac55760405162461bcd60e51b815260206004820152601960248201527f637573746f6469616c20696e697469617465206661696c6564000000000000006044820152606401610552565b60006141988483611d01565b6000818152600160205260409020549091506141b89060a08601356150fb565b8311156142075760405162461bcd60e51b815260206004820152601f60248201527f74616b657220616d6f756e74203e20617661696c61626c6520766f6c756d65006044820152606401610552565b60008181526001602052604081208054859290614225908490615086565b9091555060009050670de0b6b3a764000060c086013560a087013561424a87846150be565b614254919061509e565b61425e91906150be565b614268919061509e565b90506000670de0b6b3a7640000600360008154811061429757634e487b7160e01b600052603260045260246000fd5b60009182526020909120601082040154600f9091166002026101000a900461ffff166142cb84670de0b6b3a76400006150be565b6142d5919061509e565b6142df919061509e565b90506142f16060870160408801614da0565b6001600160a01b03166323b872dd3361431060408a0160208b01614da0565b8461431b878b6150fb565b6143259190615086565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b1681526001600160a01b0393841660048201529290911660248301526044820152606401602060405180830381600087803b15801561438c57600080fd5b505af11580156143a0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906143c49190614f15565b506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166365a963aa6144046060890160408a01614da0565b60e089013561441960408b0160208c01614da0565b60405160e085901b7fffffffff000000000000000000000000000000000000000000000000000000001681526001600160a01b039384166004820152602481019290925290911660448201523360648201526084810188905260a401602060405180830381600087803b15801561448f57600080fd5b505af11580156144a3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906144c79190614f15565b6145135760405162461bcd60e51b815260206004820152601760248201527f7a63546f6b656e2065786368616e6765206661696c65640000000000000000006044820152606401610552565b336145246040880160208901614da0565b6001600160a01b031687357f32bc401d77ffde781b234d480866e0c360e724770a30ea3299309f9171e400ef8661456160808c0160608d01614ef9565b61457160a08d0160808e01614ef9565b604080519384529115156020840152151590820152606081018a90526080810187905260a00160405180910390a4505050505050565b60006145b38483611d01565b6000818152600160205260409020549091506145d39060c08601356150fb565b8311156146225760405162461bcd60e51b815260206004820152601f60248201527f74616b657220616d6f756e74203e20617661696c61626c6520766f6c756d65006044820152606401610552565b60008181526001602052604081208054859290614640908490615086565b9091555060009050670de0b6b3a764000060a086013560c087013561466587846150be565b61466f919061509e565b61467991906150be565b614683919061509e565b90506000670de0b6b3a764000060036002815481106146b257634e487b7160e01b600052603260045260246000fd5b60009182526020909120601082040154600f9091166002026101000a900461ffff166146e684670de0b6b3a76400006150be565b6146f0919061509e565b6146fa919061509e565b905061470c6060870160408801614da0565b6001600160a01b03166323b872dd3361472b60408a0160208b01614da0565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b1681526001600160a01b0392831660048201529116602482015260448101889052606401602060405180830381600087803b15801561479257600080fd5b505af11580156147a6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906147ca9190614f15565b507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03811663bddbfbe461480b60608a0160408b01614da0565b60e08a013561482060408c0160208d01614da0565b60405160e085901b7fffffffff000000000000000000000000000000000000000000000000000000001681526001600160a01b039384166004820152602481019290925290911660448201523360648201526084810186905260a401602060405180830381600087803b15801561489657600080fd5b505af11580156148aa573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906148ce9190614f15565b61491a5760405162461bcd60e51b815260206004820152601560248201527f7661756c742065786368616e6765206661696c656400000000000000000000006044820152606401610552565b6001600160a01b038116633cf9a4e361493960608a0160408b01614da0565b60405160e083811b7fffffffff000000000000000000000000000000000000000000000000000000001682526001600160a01b03929092166004820152908a0135602482015233604482015260648101859052608401602060405180830381600087803b1580156149a957600080fd5b505af11580156149bd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906149e19190614f15565b614a2d5760405162461bcd60e51b815260206004820152601c60248201527f6e6f74696f6e616c20666565207472616e73666572206661696c6564000000006044820152606401610552565b33614a3e6040890160208a01614da0565b6001600160a01b031688357f32bc401d77ffde781b234d480866e0c360e724770a30ea3299309f9171e400ef8761233660808d0160608e01614ef9565b60007f7ddd38ab5ed1c16b61ca90eeb9579e29da1ba821cf42d8cdef8f30a31a6a41468235614ab06040850160208601614da0565b614ac06060860160408701614da0565b614ad06080870160608801614ef9565b614ae060a0880160808901614ef9565b8760a001358860c001358960e001358a6101000135604051602001614b5c9a99989796959493929190998a5260208a01989098526001600160a01b0396871660408a01529490951660608801529115156080870152151560a086015260c085015260e08401919091526101008301526101208201526101400190565b604051602081830303815290604052805190602001209050919050565b60007f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a060408301351115614bef5760405162461bcd60e51b815260206004820152601b60248201527f696e76616c6964207369676e6174757265202273222076616c756500000000006044820152606401610552565b614bfc6020830183614ff4565b60ff16601b1480614c1c5750614c156020830183614ff4565b60ff16601c145b614c685760405162461bcd60e51b815260206004820152601b60248201527f696e76616c6964207369676e6174757265202276222076616c756500000000006044820152606401610552565b600183614c786020850185614ff4565b604080516000815260208181018084529490945260ff9092168282015291850135606082015290840135608082015260a0016020604051602081039080840390855afa158015614ccc573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00151949350505050565b60008083601f840112614d0d578182fd5b50813567ffffffffffffffff811115614d24578182fd5b602083019150836020606083028501011115614d3f57600080fd5b9250929050565b60008083601f840112614d57578182fd5b50813567ffffffffffffffff811115614d6e578182fd5b6020830191508360208260051b8501011115614d3f57600080fd5b803561ffff81168114614d9b57600080fd5b919050565b600060208284031215614db1578081fd5b8135611e9481615161565b600060208284031215614dcd578081fd5b8151611e9481615161565b60008060408385031215614dea578081fd5b8235614df581615161565b946020939093013593505050565b600080600060608486031215614e17578081fd5b8335614e2281615161565b95602085013595506040909401359392505050565b60008060008060008060608789031215614e4f578182fd5b863567ffffffffffffffff80821115614e66578384fd5b818901915089601f830112614e79578384fd5b813581811115614e87578485fd5b8a602061012083028501011115614e9c578485fd5b602092830198509650908801359080821115614eb6578384fd5b614ec28a838b01614d46565b90965094506040890135915080821115614eda578384fd5b50614ee789828a01614cfc565b979a9699509497509295939492505050565b600060208284031215614f0a578081fd5b8135611e9481615179565b600060208284031215614f26578081fd5b8151611e9481615179565b600060208284031215614f42578081fd5b5035919050565b600080828403610180811215614f5d578283fd5b61012080821215614f6c578384fd5b84935060607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee083011215614f9e578283fd5b92959390920193505050565b60008060408385031215614fbc578182fd5b614fc583614d89565b9150614fd360208401614d89565b90509250929050565b600060208284031215614fed578081fd5b5051919050565b600060208284031215615005578081fd5b813560ff81168114611e94578182fd5b6000602080835283518082850152825b8181101561504157858101830151858201604001528201615025565b818111156150525783604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016929092016040019392505050565b600082198211156150995761509961514b565b500190565b6000826150b957634e487b7160e01b81526012600452602481fd5b500490565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156150f6576150f661514b565b500290565b60008282101561510d5761510d61514b565b500390565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8214156151445761514461514b565b5060010190565b634e487b7160e01b600052601160045260246000fd5b6001600160a01b038116811461517657600080fd5b50565b801515811461517657600080fdfea26469706673582212205f378ff9258482fd3585160b580b3ee430a16e6be0e73bb225aedf404ea77ccf64736f6c63430008040033" + +// DeploySwivel deploys a new Ethereum contract, binding an instance of Swivel to it. +func DeploySwivel(auth *bind.TransactOpts, backend bind.ContractBackend, m common.Address) (common.Address, *types.Transaction, *Swivel, error) { + parsed, err := abi.JSON(strings.NewReader(SwivelABI)) + if err != nil { + return common.Address{}, nil, nil, err + } + + address, tx, contract, err := bind.DeployContract(auth, parsed, common.FromHex(SwivelBin), backend, m) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &Swivel{SwivelCaller: SwivelCaller{contract: contract}, SwivelTransactor: SwivelTransactor{contract: contract}, SwivelFilterer: SwivelFilterer{contract: contract}}, nil +} + +// Swivel is an auto generated Go binding around an Ethereum contract. +type Swivel struct { + SwivelCaller // Read-only binding to the contract + SwivelTransactor // Write-only binding to the contract + SwivelFilterer // Log filterer for contract events +} + +// SwivelCaller is an auto generated read-only Go binding around an Ethereum contract. +type SwivelCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// SwivelTransactor is an auto generated write-only Go binding around an Ethereum contract. +type SwivelTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// SwivelFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type SwivelFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// SwivelSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type SwivelSession struct { + Contract *Swivel // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// SwivelCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type SwivelCallerSession struct { + Contract *SwivelCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// SwivelTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type SwivelTransactorSession struct { + Contract *SwivelTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// SwivelRaw is an auto generated low-level Go binding around an Ethereum contract. +type SwivelRaw struct { + Contract *Swivel // Generic contract binding to access the raw methods on +} + +// SwivelCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type SwivelCallerRaw struct { + Contract *SwivelCaller // Generic read-only contract binding to access the raw methods on +} + +// SwivelTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type SwivelTransactorRaw struct { + Contract *SwivelTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewSwivel creates a new instance of Swivel, bound to a specific deployed contract. +func NewSwivel(address common.Address, backend bind.ContractBackend) (*Swivel, error) { + contract, err := bindSwivel(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &Swivel{SwivelCaller: SwivelCaller{contract: contract}, SwivelTransactor: SwivelTransactor{contract: contract}, SwivelFilterer: SwivelFilterer{contract: contract}}, nil +} + +// NewSwivelCaller creates a new read-only instance of Swivel, bound to a specific deployed contract. +func NewSwivelCaller(address common.Address, caller bind.ContractCaller) (*SwivelCaller, error) { + contract, err := bindSwivel(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &SwivelCaller{contract: contract}, nil +} + +// NewSwivelTransactor creates a new write-only instance of Swivel, bound to a specific deployed contract. +func NewSwivelTransactor(address common.Address, transactor bind.ContractTransactor) (*SwivelTransactor, error) { + contract, err := bindSwivel(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &SwivelTransactor{contract: contract}, nil +} + +// NewSwivelFilterer creates a new log filterer instance of Swivel, bound to a specific deployed contract. +func NewSwivelFilterer(address common.Address, filterer bind.ContractFilterer) (*SwivelFilterer, error) { + contract, err := bindSwivel(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &SwivelFilterer{contract: contract}, nil +} + +// bindSwivel binds a generic wrapper to an already deployed contract. +func bindSwivel(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := abi.JSON(strings.NewReader(SwivelABI)) + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_Swivel *SwivelRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _Swivel.Contract.SwivelCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_Swivel *SwivelRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Swivel.Contract.SwivelTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_Swivel *SwivelRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _Swivel.Contract.SwivelTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_Swivel *SwivelCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _Swivel.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_Swivel *SwivelTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Swivel.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_Swivel *SwivelTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _Swivel.Contract.contract.Transact(opts, method, params...) +} + +// HOLD is a free data retrieval call binding the contract method 0xd0886f97. +// +// Solidity: function HOLD() view returns(uint256) +func (_Swivel *SwivelCaller) HOLD(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _Swivel.contract.Call(opts, &out, "HOLD") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// HOLD is a free data retrieval call binding the contract method 0xd0886f97. +// +// Solidity: function HOLD() view returns(uint256) +func (_Swivel *SwivelSession) HOLD() (*big.Int, error) { + return _Swivel.Contract.HOLD(&_Swivel.CallOpts) +} + +// HOLD is a free data retrieval call binding the contract method 0xd0886f97. +// +// Solidity: function HOLD() view returns(uint256) +func (_Swivel *SwivelCallerSession) HOLD() (*big.Int, error) { + return _Swivel.Contract.HOLD(&_Swivel.CallOpts) +} + +// NAME is a free data retrieval call binding the contract method 0xa3f4df7e. +// +// Solidity: function NAME() view returns(string) +func (_Swivel *SwivelCaller) NAME(opts *bind.CallOpts) (string, error) { + var out []interface{} + err := _Swivel.contract.Call(opts, &out, "NAME") + + if err != nil { + return *new(string), err + } + + out0 := *abi.ConvertType(out[0], new(string)).(*string) + + return out0, err + +} + +// NAME is a free data retrieval call binding the contract method 0xa3f4df7e. +// +// Solidity: function NAME() view returns(string) +func (_Swivel *SwivelSession) NAME() (string, error) { + return _Swivel.Contract.NAME(&_Swivel.CallOpts) +} + +// NAME is a free data retrieval call binding the contract method 0xa3f4df7e. +// +// Solidity: function NAME() view returns(string) +func (_Swivel *SwivelCallerSession) NAME() (string, error) { + return _Swivel.Contract.NAME(&_Swivel.CallOpts) +} + +// VERSION is a free data retrieval call binding the contract method 0xffa1ad74. +// +// Solidity: function VERSION() view returns(string) +func (_Swivel *SwivelCaller) VERSION(opts *bind.CallOpts) (string, error) { + var out []interface{} + err := _Swivel.contract.Call(opts, &out, "VERSION") + + if err != nil { + return *new(string), err + } + + out0 := *abi.ConvertType(out[0], new(string)).(*string) + + return out0, err + +} + +// VERSION is a free data retrieval call binding the contract method 0xffa1ad74. +// +// Solidity: function VERSION() view returns(string) +func (_Swivel *SwivelSession) VERSION() (string, error) { + return _Swivel.Contract.VERSION(&_Swivel.CallOpts) +} + +// VERSION is a free data retrieval call binding the contract method 0xffa1ad74. +// +// Solidity: function VERSION() view returns(string) +func (_Swivel *SwivelCallerSession) VERSION() (string, error) { + return _Swivel.Contract.VERSION(&_Swivel.CallOpts) +} + +// Admin is a free data retrieval call binding the contract method 0xf851a440. +// +// Solidity: function admin() view returns(address) +func (_Swivel *SwivelCaller) Admin(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _Swivel.contract.Call(opts, &out, "admin") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// Admin is a free data retrieval call binding the contract method 0xf851a440. +// +// Solidity: function admin() view returns(address) +func (_Swivel *SwivelSession) Admin() (common.Address, error) { + return _Swivel.Contract.Admin(&_Swivel.CallOpts) +} + +// Admin is a free data retrieval call binding the contract method 0xf851a440. +// +// Solidity: function admin() view returns(address) +func (_Swivel *SwivelCallerSession) Admin() (common.Address, error) { + return _Swivel.Contract.Admin(&_Swivel.CallOpts) +} + +// Cancelled is a free data retrieval call binding the contract method 0x2ac12622. +// +// Solidity: function cancelled(bytes32 ) view returns(bool) +func (_Swivel *SwivelCaller) Cancelled(opts *bind.CallOpts, arg0 [32]byte) (bool, error) { + var out []interface{} + err := _Swivel.contract.Call(opts, &out, "cancelled", arg0) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// Cancelled is a free data retrieval call binding the contract method 0x2ac12622. +// +// Solidity: function cancelled(bytes32 ) view returns(bool) +func (_Swivel *SwivelSession) Cancelled(arg0 [32]byte) (bool, error) { + return _Swivel.Contract.Cancelled(&_Swivel.CallOpts, arg0) +} + +// Cancelled is a free data retrieval call binding the contract method 0x2ac12622. +// +// Solidity: function cancelled(bytes32 ) view returns(bool) +func (_Swivel *SwivelCallerSession) Cancelled(arg0 [32]byte) (bool, error) { + return _Swivel.Contract.Cancelled(&_Swivel.CallOpts, arg0) +} + +// Domain is a free data retrieval call binding the contract method 0xc2fb26a6. +// +// Solidity: function domain() view returns(bytes32) +func (_Swivel *SwivelCaller) Domain(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _Swivel.contract.Call(opts, &out, "domain") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// Domain is a free data retrieval call binding the contract method 0xc2fb26a6. +// +// Solidity: function domain() view returns(bytes32) +func (_Swivel *SwivelSession) Domain() ([32]byte, error) { + return _Swivel.Contract.Domain(&_Swivel.CallOpts) +} + +// Domain is a free data retrieval call binding the contract method 0xc2fb26a6. +// +// Solidity: function domain() view returns(bytes32) +func (_Swivel *SwivelCallerSession) Domain() ([32]byte, error) { + return _Swivel.Contract.Domain(&_Swivel.CallOpts) +} + +// Fenominator is a free data retrieval call binding the contract method 0x33c810e9. +// +// Solidity: function fenominator(uint256 ) view returns(uint16) +func (_Swivel *SwivelCaller) Fenominator(opts *bind.CallOpts, arg0 *big.Int) (uint16, error) { + var out []interface{} + err := _Swivel.contract.Call(opts, &out, "fenominator", arg0) + + if err != nil { + return *new(uint16), err + } + + out0 := *abi.ConvertType(out[0], new(uint16)).(*uint16) + + return out0, err + +} + +// Fenominator is a free data retrieval call binding the contract method 0x33c810e9. +// +// Solidity: function fenominator(uint256 ) view returns(uint16) +func (_Swivel *SwivelSession) Fenominator(arg0 *big.Int) (uint16, error) { + return _Swivel.Contract.Fenominator(&_Swivel.CallOpts, arg0) +} + +// Fenominator is a free data retrieval call binding the contract method 0x33c810e9. +// +// Solidity: function fenominator(uint256 ) view returns(uint16) +func (_Swivel *SwivelCallerSession) Fenominator(arg0 *big.Int) (uint16, error) { + return _Swivel.Contract.Fenominator(&_Swivel.CallOpts, arg0) +} + +// Filled is a free data retrieval call binding the contract method 0x288cdc91. +// +// Solidity: function filled(bytes32 ) view returns(uint256) +func (_Swivel *SwivelCaller) Filled(opts *bind.CallOpts, arg0 [32]byte) (*big.Int, error) { + var out []interface{} + err := _Swivel.contract.Call(opts, &out, "filled", arg0) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// Filled is a free data retrieval call binding the contract method 0x288cdc91. +// +// Solidity: function filled(bytes32 ) view returns(uint256) +func (_Swivel *SwivelSession) Filled(arg0 [32]byte) (*big.Int, error) { + return _Swivel.Contract.Filled(&_Swivel.CallOpts, arg0) +} + +// Filled is a free data retrieval call binding the contract method 0x288cdc91. +// +// Solidity: function filled(bytes32 ) view returns(uint256) +func (_Swivel *SwivelCallerSession) Filled(arg0 [32]byte) (*big.Int, error) { + return _Swivel.Contract.Filled(&_Swivel.CallOpts, arg0) +} + +// MarketPlace is a free data retrieval call binding the contract method 0x2e25d2a6. +// +// Solidity: function marketPlace() view returns(address) +func (_Swivel *SwivelCaller) MarketPlace(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _Swivel.contract.Call(opts, &out, "marketPlace") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// MarketPlace is a free data retrieval call binding the contract method 0x2e25d2a6. +// +// Solidity: function marketPlace() view returns(address) +func (_Swivel *SwivelSession) MarketPlace() (common.Address, error) { + return _Swivel.Contract.MarketPlace(&_Swivel.CallOpts) +} + +// MarketPlace is a free data retrieval call binding the contract method 0x2e25d2a6. +// +// Solidity: function marketPlace() view returns(address) +func (_Swivel *SwivelCallerSession) MarketPlace() (common.Address, error) { + return _Swivel.Contract.MarketPlace(&_Swivel.CallOpts) +} + +// Withdrawals is a free data retrieval call binding the contract method 0x7a9262a2. +// +// Solidity: function withdrawals(address ) view returns(uint256) +func (_Swivel *SwivelCaller) Withdrawals(opts *bind.CallOpts, arg0 common.Address) (*big.Int, error) { + var out []interface{} + err := _Swivel.contract.Call(opts, &out, "withdrawals", arg0) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// Withdrawals is a free data retrieval call binding the contract method 0x7a9262a2. +// +// Solidity: function withdrawals(address ) view returns(uint256) +func (_Swivel *SwivelSession) Withdrawals(arg0 common.Address) (*big.Int, error) { + return _Swivel.Contract.Withdrawals(&_Swivel.CallOpts, arg0) +} + +// Withdrawals is a free data retrieval call binding the contract method 0x7a9262a2. +// +// Solidity: function withdrawals(address ) view returns(uint256) +func (_Swivel *SwivelCallerSession) Withdrawals(arg0 common.Address) (*big.Int, error) { + return _Swivel.Contract.Withdrawals(&_Swivel.CallOpts, arg0) +} + +// BlockWithdrawal is a paid mutator transaction binding the contract method 0xa102e384. +// +// Solidity: function blockWithdrawal(address e) returns() +func (_Swivel *SwivelTransactor) BlockWithdrawal(opts *bind.TransactOpts, e common.Address) (*types.Transaction, error) { + return _Swivel.contract.Transact(opts, "blockWithdrawal", e) +} + +// BlockWithdrawal is a paid mutator transaction binding the contract method 0xa102e384. +// +// Solidity: function blockWithdrawal(address e) returns() +func (_Swivel *SwivelSession) BlockWithdrawal(e common.Address) (*types.Transaction, error) { + return _Swivel.Contract.BlockWithdrawal(&_Swivel.TransactOpts, e) +} + +// BlockWithdrawal is a paid mutator transaction binding the contract method 0xa102e384. +// +// Solidity: function blockWithdrawal(address e) returns() +func (_Swivel *SwivelTransactorSession) BlockWithdrawal(e common.Address) (*types.Transaction, error) { + return _Swivel.Contract.BlockWithdrawal(&_Swivel.TransactOpts, e) +} + +// Cancel is a paid mutator transaction binding the contract method 0x3e1608b4. +// +// Solidity: function cancel((bytes32,address,address,bool,bool,uint256,uint256,uint256,uint256) o, (uint8,bytes32,bytes32) c) returns(bool) +func (_Swivel *SwivelTransactor) Cancel(opts *bind.TransactOpts, o HashOrder, c SigComponents) (*types.Transaction, error) { + return _Swivel.contract.Transact(opts, "cancel", o, c) +} + +// Cancel is a paid mutator transaction binding the contract method 0x3e1608b4. +// +// Solidity: function cancel((bytes32,address,address,bool,bool,uint256,uint256,uint256,uint256) o, (uint8,bytes32,bytes32) c) returns(bool) +func (_Swivel *SwivelSession) Cancel(o HashOrder, c SigComponents) (*types.Transaction, error) { + return _Swivel.Contract.Cancel(&_Swivel.TransactOpts, o, c) +} + +// Cancel is a paid mutator transaction binding the contract method 0x3e1608b4. +// +// Solidity: function cancel((bytes32,address,address,bool,bool,uint256,uint256,uint256,uint256) o, (uint8,bytes32,bytes32) c) returns(bool) +func (_Swivel *SwivelTransactorSession) Cancel(o HashOrder, c SigComponents) (*types.Transaction, error) { + return _Swivel.Contract.Cancel(&_Swivel.TransactOpts, o, c) +} + +// CombineTokens is a paid mutator transaction binding the contract method 0x0908ff2d. +// +// Solidity: function combineTokens(address u, uint256 m, uint256 a) returns(bool) +func (_Swivel *SwivelTransactor) CombineTokens(opts *bind.TransactOpts, u common.Address, m *big.Int, a *big.Int) (*types.Transaction, error) { + return _Swivel.contract.Transact(opts, "combineTokens", u, m, a) +} + +// CombineTokens is a paid mutator transaction binding the contract method 0x0908ff2d. +// +// Solidity: function combineTokens(address u, uint256 m, uint256 a) returns(bool) +func (_Swivel *SwivelSession) CombineTokens(u common.Address, m *big.Int, a *big.Int) (*types.Transaction, error) { + return _Swivel.Contract.CombineTokens(&_Swivel.TransactOpts, u, m, a) +} + +// CombineTokens is a paid mutator transaction binding the contract method 0x0908ff2d. +// +// Solidity: function combineTokens(address u, uint256 m, uint256 a) returns(bool) +func (_Swivel *SwivelTransactorSession) CombineTokens(u common.Address, m *big.Int, a *big.Int) (*types.Transaction, error) { + return _Swivel.Contract.CombineTokens(&_Swivel.TransactOpts, u, m, a) +} + +// Exit is a paid mutator transaction binding the contract method 0xaba28701. +// +// Solidity: function exit((bytes32,address,address,bool,bool,uint256,uint256,uint256,uint256)[] o, uint256[] a, (uint8,bytes32,bytes32)[] c) returns(bool) +func (_Swivel *SwivelTransactor) Exit(opts *bind.TransactOpts, o []HashOrder, a []*big.Int, c []SigComponents) (*types.Transaction, error) { + return _Swivel.contract.Transact(opts, "exit", o, a, c) +} + +// Exit is a paid mutator transaction binding the contract method 0xaba28701. +// +// Solidity: function exit((bytes32,address,address,bool,bool,uint256,uint256,uint256,uint256)[] o, uint256[] a, (uint8,bytes32,bytes32)[] c) returns(bool) +func (_Swivel *SwivelSession) Exit(o []HashOrder, a []*big.Int, c []SigComponents) (*types.Transaction, error) { + return _Swivel.Contract.Exit(&_Swivel.TransactOpts, o, a, c) +} + +// Exit is a paid mutator transaction binding the contract method 0xaba28701. +// +// Solidity: function exit((bytes32,address,address,bool,bool,uint256,uint256,uint256,uint256)[] o, uint256[] a, (uint8,bytes32,bytes32)[] c) returns(bool) +func (_Swivel *SwivelTransactorSession) Exit(o []HashOrder, a []*big.Int, c []SigComponents) (*types.Transaction, error) { + return _Swivel.Contract.Exit(&_Swivel.TransactOpts, o, a, c) +} + +// Initiate is a paid mutator transaction binding the contract method 0xd2144f58. +// +// Solidity: function initiate((bytes32,address,address,bool,bool,uint256,uint256,uint256,uint256)[] o, uint256[] a, (uint8,bytes32,bytes32)[] c) returns(bool) +func (_Swivel *SwivelTransactor) Initiate(opts *bind.TransactOpts, o []HashOrder, a []*big.Int, c []SigComponents) (*types.Transaction, error) { + return _Swivel.contract.Transact(opts, "initiate", o, a, c) +} + +// Initiate is a paid mutator transaction binding the contract method 0xd2144f58. +// +// Solidity: function initiate((bytes32,address,address,bool,bool,uint256,uint256,uint256,uint256)[] o, uint256[] a, (uint8,bytes32,bytes32)[] c) returns(bool) +func (_Swivel *SwivelSession) Initiate(o []HashOrder, a []*big.Int, c []SigComponents) (*types.Transaction, error) { + return _Swivel.Contract.Initiate(&_Swivel.TransactOpts, o, a, c) +} + +// Initiate is a paid mutator transaction binding the contract method 0xd2144f58. +// +// Solidity: function initiate((bytes32,address,address,bool,bool,uint256,uint256,uint256,uint256)[] o, uint256[] a, (uint8,bytes32,bytes32)[] c) returns(bool) +func (_Swivel *SwivelTransactorSession) Initiate(o []HashOrder, a []*big.Int, c []SigComponents) (*types.Transaction, error) { + return _Swivel.Contract.Initiate(&_Swivel.TransactOpts, o, a, c) +} + +// RedeemVaultInterest is a paid mutator transaction binding the contract method 0x40d37cdf. +// +// Solidity: function redeemVaultInterest(address u, uint256 m) returns(bool) +func (_Swivel *SwivelTransactor) RedeemVaultInterest(opts *bind.TransactOpts, u common.Address, m *big.Int) (*types.Transaction, error) { + return _Swivel.contract.Transact(opts, "redeemVaultInterest", u, m) +} + +// RedeemVaultInterest is a paid mutator transaction binding the contract method 0x40d37cdf. +// +// Solidity: function redeemVaultInterest(address u, uint256 m) returns(bool) +func (_Swivel *SwivelSession) RedeemVaultInterest(u common.Address, m *big.Int) (*types.Transaction, error) { + return _Swivel.Contract.RedeemVaultInterest(&_Swivel.TransactOpts, u, m) +} + +// RedeemVaultInterest is a paid mutator transaction binding the contract method 0x40d37cdf. +// +// Solidity: function redeemVaultInterest(address u, uint256 m) returns(bool) +func (_Swivel *SwivelTransactorSession) RedeemVaultInterest(u common.Address, m *big.Int) (*types.Transaction, error) { + return _Swivel.Contract.RedeemVaultInterest(&_Swivel.TransactOpts, u, m) +} + +// RedeemZcToken is a paid mutator transaction binding the contract method 0x154e0f2e. +// +// Solidity: function redeemZcToken(address u, uint256 m, uint256 a) returns(bool) +func (_Swivel *SwivelTransactor) RedeemZcToken(opts *bind.TransactOpts, u common.Address, m *big.Int, a *big.Int) (*types.Transaction, error) { + return _Swivel.contract.Transact(opts, "redeemZcToken", u, m, a) +} + +// RedeemZcToken is a paid mutator transaction binding the contract method 0x154e0f2e. +// +// Solidity: function redeemZcToken(address u, uint256 m, uint256 a) returns(bool) +func (_Swivel *SwivelSession) RedeemZcToken(u common.Address, m *big.Int, a *big.Int) (*types.Transaction, error) { + return _Swivel.Contract.RedeemZcToken(&_Swivel.TransactOpts, u, m, a) +} + +// RedeemZcToken is a paid mutator transaction binding the contract method 0x154e0f2e. +// +// Solidity: function redeemZcToken(address u, uint256 m, uint256 a) returns(bool) +func (_Swivel *SwivelTransactorSession) RedeemZcToken(u common.Address, m *big.Int, a *big.Int) (*types.Transaction, error) { + return _Swivel.Contract.RedeemZcToken(&_Swivel.TransactOpts, u, m, a) +} + +// ScheduleWithdrawal is a paid mutator transaction binding the contract method 0xf8eaad35. +// +// Solidity: function scheduleWithdrawal(address e) returns() +func (_Swivel *SwivelTransactor) ScheduleWithdrawal(opts *bind.TransactOpts, e common.Address) (*types.Transaction, error) { + return _Swivel.contract.Transact(opts, "scheduleWithdrawal", e) +} + +// ScheduleWithdrawal is a paid mutator transaction binding the contract method 0xf8eaad35. +// +// Solidity: function scheduleWithdrawal(address e) returns() +func (_Swivel *SwivelSession) ScheduleWithdrawal(e common.Address) (*types.Transaction, error) { + return _Swivel.Contract.ScheduleWithdrawal(&_Swivel.TransactOpts, e) +} + +// ScheduleWithdrawal is a paid mutator transaction binding the contract method 0xf8eaad35. +// +// Solidity: function scheduleWithdrawal(address e) returns() +func (_Swivel *SwivelTransactorSession) ScheduleWithdrawal(e common.Address) (*types.Transaction, error) { + return _Swivel.Contract.ScheduleWithdrawal(&_Swivel.TransactOpts, e) +} + +// SetFee is a paid mutator transaction binding the contract method 0x99b64de1. +// +// Solidity: function setFee(uint16 t, uint16 d) returns(bool) +func (_Swivel *SwivelTransactor) SetFee(opts *bind.TransactOpts, t uint16, d uint16) (*types.Transaction, error) { + return _Swivel.contract.Transact(opts, "setFee", t, d) +} + +// SetFee is a paid mutator transaction binding the contract method 0x99b64de1. +// +// Solidity: function setFee(uint16 t, uint16 d) returns(bool) +func (_Swivel *SwivelSession) SetFee(t uint16, d uint16) (*types.Transaction, error) { + return _Swivel.Contract.SetFee(&_Swivel.TransactOpts, t, d) +} + +// SetFee is a paid mutator transaction binding the contract method 0x99b64de1. +// +// Solidity: function setFee(uint16 t, uint16 d) returns(bool) +func (_Swivel *SwivelTransactorSession) SetFee(t uint16, d uint16) (*types.Transaction, error) { + return _Swivel.Contract.SetFee(&_Swivel.TransactOpts, t, d) +} + +// SplitUnderlying is a paid mutator transaction binding the contract method 0x92ae3764. +// +// Solidity: function splitUnderlying(address u, uint256 m, uint256 a) returns(bool) +func (_Swivel *SwivelTransactor) SplitUnderlying(opts *bind.TransactOpts, u common.Address, m *big.Int, a *big.Int) (*types.Transaction, error) { + return _Swivel.contract.Transact(opts, "splitUnderlying", u, m, a) +} + +// SplitUnderlying is a paid mutator transaction binding the contract method 0x92ae3764. +// +// Solidity: function splitUnderlying(address u, uint256 m, uint256 a) returns(bool) +func (_Swivel *SwivelSession) SplitUnderlying(u common.Address, m *big.Int, a *big.Int) (*types.Transaction, error) { + return _Swivel.Contract.SplitUnderlying(&_Swivel.TransactOpts, u, m, a) +} + +// SplitUnderlying is a paid mutator transaction binding the contract method 0x92ae3764. +// +// Solidity: function splitUnderlying(address u, uint256 m, uint256 a) returns(bool) +func (_Swivel *SwivelTransactorSession) SplitUnderlying(u common.Address, m *big.Int, a *big.Int) (*types.Transaction, error) { + return _Swivel.Contract.SplitUnderlying(&_Swivel.TransactOpts, u, m, a) +} + +// Withdraw is a paid mutator transaction binding the contract method 0x51cff8d9. +// +// Solidity: function withdraw(address e) returns() +func (_Swivel *SwivelTransactor) Withdraw(opts *bind.TransactOpts, e common.Address) (*types.Transaction, error) { + return _Swivel.contract.Transact(opts, "withdraw", e) +} + +// Withdraw is a paid mutator transaction binding the contract method 0x51cff8d9. +// +// Solidity: function withdraw(address e) returns() +func (_Swivel *SwivelSession) Withdraw(e common.Address) (*types.Transaction, error) { + return _Swivel.Contract.Withdraw(&_Swivel.TransactOpts, e) +} + +// Withdraw is a paid mutator transaction binding the contract method 0x51cff8d9. +// +// Solidity: function withdraw(address e) returns() +func (_Swivel *SwivelTransactorSession) Withdraw(e common.Address) (*types.Transaction, error) { + return _Swivel.Contract.Withdraw(&_Swivel.TransactOpts, e) +} + +// SwivelCancelIterator is returned from FilterCancel and is used to iterate over the raw logs and unpacked data for Cancel events raised by the Swivel contract. +type SwivelCancelIterator struct { + Event *SwivelCancel // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *SwivelCancelIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(SwivelCancel) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(SwivelCancel) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *SwivelCancelIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *SwivelCancelIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// SwivelCancel represents a Cancel event raised by the Swivel contract. +type SwivelCancel struct { + Key [32]byte + Hash [32]byte + Raw types.Log // Blockchain specific contextual infos +} + +// FilterCancel is a free log retrieval operation binding the contract event 0x9e5d8891dc1b047de610617bc9bc2d8ccffebbc3d63363431a546831245858a6. +// +// Solidity: event Cancel(bytes32 indexed key, bytes32 hash) +func (_Swivel *SwivelFilterer) FilterCancel(opts *bind.FilterOpts, key [][32]byte) (*SwivelCancelIterator, error) { + + var keyRule []interface{} + for _, keyItem := range key { + keyRule = append(keyRule, keyItem) + } + + logs, sub, err := _Swivel.contract.FilterLogs(opts, "Cancel", keyRule) + if err != nil { + return nil, err + } + return &SwivelCancelIterator{contract: _Swivel.contract, event: "Cancel", logs: logs, sub: sub}, nil +} + +// WatchCancel is a free log subscription operation binding the contract event 0x9e5d8891dc1b047de610617bc9bc2d8ccffebbc3d63363431a546831245858a6. +// +// Solidity: event Cancel(bytes32 indexed key, bytes32 hash) +func (_Swivel *SwivelFilterer) WatchCancel(opts *bind.WatchOpts, sink chan<- *SwivelCancel, key [][32]byte) (event.Subscription, error) { + + var keyRule []interface{} + for _, keyItem := range key { + keyRule = append(keyRule, keyItem) + } + + logs, sub, err := _Swivel.contract.WatchLogs(opts, "Cancel", keyRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(SwivelCancel) + if err := _Swivel.contract.UnpackLog(event, "Cancel", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseCancel is a log parse operation binding the contract event 0x9e5d8891dc1b047de610617bc9bc2d8ccffebbc3d63363431a546831245858a6. +// +// Solidity: event Cancel(bytes32 indexed key, bytes32 hash) +func (_Swivel *SwivelFilterer) ParseCancel(log types.Log) (*SwivelCancel, error) { + event := new(SwivelCancel) + if err := _Swivel.contract.UnpackLog(event, "Cancel", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// SwivelExitIterator is returned from FilterExit and is used to iterate over the raw logs and unpacked data for Exit events raised by the Swivel contract. +type SwivelExitIterator struct { + Event *SwivelExit // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *SwivelExitIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(SwivelExit) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(SwivelExit) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *SwivelExitIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *SwivelExitIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// SwivelExit represents a Exit event raised by the Swivel contract. +type SwivelExit struct { + Key [32]byte + Hash [32]byte + Maker common.Address + Vault bool + Exit bool + Sender common.Address + Amount *big.Int + Filled *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterExit is a free log retrieval operation binding the contract event 0x51cad9177cf46d59109ae978bb3cf5ffed2bb3d53fb3682fa56fbd9266712834. +// +// Solidity: event Exit(bytes32 indexed key, bytes32 hash, address indexed maker, bool vault, bool exit, address indexed sender, uint256 amount, uint256 filled) +func (_Swivel *SwivelFilterer) FilterExit(opts *bind.FilterOpts, key [][32]byte, maker []common.Address, sender []common.Address) (*SwivelExitIterator, error) { + + var keyRule []interface{} + for _, keyItem := range key { + keyRule = append(keyRule, keyItem) + } + + var makerRule []interface{} + for _, makerItem := range maker { + makerRule = append(makerRule, makerItem) + } + + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _Swivel.contract.FilterLogs(opts, "Exit", keyRule, makerRule, senderRule) + if err != nil { + return nil, err + } + return &SwivelExitIterator{contract: _Swivel.contract, event: "Exit", logs: logs, sub: sub}, nil +} + +// WatchExit is a free log subscription operation binding the contract event 0x51cad9177cf46d59109ae978bb3cf5ffed2bb3d53fb3682fa56fbd9266712834. +// +// Solidity: event Exit(bytes32 indexed key, bytes32 hash, address indexed maker, bool vault, bool exit, address indexed sender, uint256 amount, uint256 filled) +func (_Swivel *SwivelFilterer) WatchExit(opts *bind.WatchOpts, sink chan<- *SwivelExit, key [][32]byte, maker []common.Address, sender []common.Address) (event.Subscription, error) { + + var keyRule []interface{} + for _, keyItem := range key { + keyRule = append(keyRule, keyItem) + } + + var makerRule []interface{} + for _, makerItem := range maker { + makerRule = append(makerRule, makerItem) + } + + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _Swivel.contract.WatchLogs(opts, "Exit", keyRule, makerRule, senderRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(SwivelExit) + if err := _Swivel.contract.UnpackLog(event, "Exit", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseExit is a log parse operation binding the contract event 0x51cad9177cf46d59109ae978bb3cf5ffed2bb3d53fb3682fa56fbd9266712834. +// +// Solidity: event Exit(bytes32 indexed key, bytes32 hash, address indexed maker, bool vault, bool exit, address indexed sender, uint256 amount, uint256 filled) +func (_Swivel *SwivelFilterer) ParseExit(log types.Log) (*SwivelExit, error) { + event := new(SwivelExit) + if err := _Swivel.contract.UnpackLog(event, "Exit", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// SwivelInitiateIterator is returned from FilterInitiate and is used to iterate over the raw logs and unpacked data for Initiate events raised by the Swivel contract. +type SwivelInitiateIterator struct { + Event *SwivelInitiate // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *SwivelInitiateIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(SwivelInitiate) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(SwivelInitiate) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *SwivelInitiateIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *SwivelInitiateIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// SwivelInitiate represents a Initiate event raised by the Swivel contract. +type SwivelInitiate struct { + Key [32]byte + Hash [32]byte + Maker common.Address + Vault bool + Exit bool + Sender common.Address + Amount *big.Int + Filled *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterInitiate is a free log retrieval operation binding the contract event 0x32bc401d77ffde781b234d480866e0c360e724770a30ea3299309f9171e400ef. +// +// Solidity: event Initiate(bytes32 indexed key, bytes32 hash, address indexed maker, bool vault, bool exit, address indexed sender, uint256 amount, uint256 filled) +func (_Swivel *SwivelFilterer) FilterInitiate(opts *bind.FilterOpts, key [][32]byte, maker []common.Address, sender []common.Address) (*SwivelInitiateIterator, error) { + + var keyRule []interface{} + for _, keyItem := range key { + keyRule = append(keyRule, keyItem) + } + + var makerRule []interface{} + for _, makerItem := range maker { + makerRule = append(makerRule, makerItem) + } + + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _Swivel.contract.FilterLogs(opts, "Initiate", keyRule, makerRule, senderRule) + if err != nil { + return nil, err + } + return &SwivelInitiateIterator{contract: _Swivel.contract, event: "Initiate", logs: logs, sub: sub}, nil +} + +// WatchInitiate is a free log subscription operation binding the contract event 0x32bc401d77ffde781b234d480866e0c360e724770a30ea3299309f9171e400ef. +// +// Solidity: event Initiate(bytes32 indexed key, bytes32 hash, address indexed maker, bool vault, bool exit, address indexed sender, uint256 amount, uint256 filled) +func (_Swivel *SwivelFilterer) WatchInitiate(opts *bind.WatchOpts, sink chan<- *SwivelInitiate, key [][32]byte, maker []common.Address, sender []common.Address) (event.Subscription, error) { + + var keyRule []interface{} + for _, keyItem := range key { + keyRule = append(keyRule, keyItem) + } + + var makerRule []interface{} + for _, makerItem := range maker { + makerRule = append(makerRule, makerItem) + } + + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _Swivel.contract.WatchLogs(opts, "Initiate", keyRule, makerRule, senderRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(SwivelInitiate) + if err := _Swivel.contract.UnpackLog(event, "Initiate", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseInitiate is a log parse operation binding the contract event 0x32bc401d77ffde781b234d480866e0c360e724770a30ea3299309f9171e400ef. +// +// Solidity: event Initiate(bytes32 indexed key, bytes32 hash, address indexed maker, bool vault, bool exit, address indexed sender, uint256 amount, uint256 filled) +func (_Swivel *SwivelFilterer) ParseInitiate(log types.Log) (*SwivelInitiate, error) { + event := new(SwivelInitiate) + if err := _Swivel.contract.UnpackLog(event, "Initiate", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// SwivelWithdrawalScheduledIterator is returned from FilterWithdrawalScheduled and is used to iterate over the raw logs and unpacked data for WithdrawalScheduled events raised by the Swivel contract. +type SwivelWithdrawalScheduledIterator struct { + Event *SwivelWithdrawalScheduled // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *SwivelWithdrawalScheduledIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(SwivelWithdrawalScheduled) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(SwivelWithdrawalScheduled) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *SwivelWithdrawalScheduledIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *SwivelWithdrawalScheduledIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// SwivelWithdrawalScheduled represents a WithdrawalScheduled event raised by the Swivel contract. +type SwivelWithdrawalScheduled struct { + Token common.Address + Hold *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterWithdrawalScheduled is a free log retrieval operation binding the contract event 0xd9cf0116e5bb6fbe3d257dc8d1ee7ae76c303efeae77f1e93024d2cb218bedd3. +// +// Solidity: event WithdrawalScheduled(address indexed token, uint256 hold) +func (_Swivel *SwivelFilterer) FilterWithdrawalScheduled(opts *bind.FilterOpts, token []common.Address) (*SwivelWithdrawalScheduledIterator, error) { + + var tokenRule []interface{} + for _, tokenItem := range token { + tokenRule = append(tokenRule, tokenItem) + } + + logs, sub, err := _Swivel.contract.FilterLogs(opts, "WithdrawalScheduled", tokenRule) + if err != nil { + return nil, err + } + return &SwivelWithdrawalScheduledIterator{contract: _Swivel.contract, event: "WithdrawalScheduled", logs: logs, sub: sub}, nil +} + +// WatchWithdrawalScheduled is a free log subscription operation binding the contract event 0xd9cf0116e5bb6fbe3d257dc8d1ee7ae76c303efeae77f1e93024d2cb218bedd3. +// +// Solidity: event WithdrawalScheduled(address indexed token, uint256 hold) +func (_Swivel *SwivelFilterer) WatchWithdrawalScheduled(opts *bind.WatchOpts, sink chan<- *SwivelWithdrawalScheduled, token []common.Address) (event.Subscription, error) { + + var tokenRule []interface{} + for _, tokenItem := range token { + tokenRule = append(tokenRule, tokenItem) + } + + logs, sub, err := _Swivel.contract.WatchLogs(opts, "WithdrawalScheduled", tokenRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(SwivelWithdrawalScheduled) + if err := _Swivel.contract.UnpackLog(event, "WithdrawalScheduled", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseWithdrawalScheduled is a log parse operation binding the contract event 0xd9cf0116e5bb6fbe3d257dc8d1ee7ae76c303efeae77f1e93024d2cb218bedd3. +// +// Solidity: event WithdrawalScheduled(address indexed token, uint256 hold) +func (_Swivel *SwivelFilterer) ParseWithdrawalScheduled(log types.Log) (*SwivelWithdrawalScheduled, error) { + event := new(SwivelWithdrawalScheduled) + if err := _Swivel.contract.UnpackLog(event, "WithdrawalScheduled", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} diff --git a/gost/go.mod b/gost/go.mod new file mode 100644 index 0000000..0b5eb84 --- /dev/null +++ b/gost/go.mod @@ -0,0 +1,8 @@ +module github.com/swivel-finance/gost + +go 1.15 + +require ( + github.com/ethereum/go-ethereum v1.9.25 + github.com/stretchr/testify v1.4.0 +) diff --git a/gost/go.sum b/gost/go.sum new file mode 100644 index 0000000..1c3aa54 --- /dev/null +++ b/gost/go.sum @@ -0,0 +1,235 @@ +github.com/Azure/azure-pipeline-go v0.2.1/go.mod h1:UGSo8XybXnIGZ3epmeBw7Jdz+HiUVpqIlpz/HKHylF4= +github.com/Azure/azure-pipeline-go v0.2.2/go.mod h1:4rQ/NZncSvGqNkkOsNpOU1tgoNuIlp9AfUH5G1tvCHc= +github.com/Azure/azure-storage-blob-go v0.7.0/go.mod h1:f9YQKtsG1nMisotuTPpO0tjNuEjKRYAcJU8/ydDI++4= +github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= +github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= +github.com/Azure/go-autorest/autorest/adal v0.8.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc= +github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= +github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g= +github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= +github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= +github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM= +github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= +github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= +github.com/VictoriaMetrics/fastcache v1.5.7 h1:4y6y0G8PRzszQUYIQHHssv/jgPHAb5qQuuDNdCbyAgw= +github.com/VictoriaMetrics/fastcache v1.5.7/go.mod h1:ptDBkNMQI4RtmVo8VS/XwRY6RoTu1dAWCbrk+6WsEM8= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= +github.com/aristanetworks/goarista v0.0.0-20170210015632-ea17b1a17847 h1:rtI0fD4oG/8eVokGVPYJEW1F88p1ZNgXiEIs9thEE4A= +github.com/aristanetworks/goarista v0.0.0-20170210015632-ea17b1a17847/go.mod h1:D/tb0zPVXnP7fmsLZjtdUhSsumbK/ij54UXjjVgMGxQ= +github.com/aws/aws-sdk-go v1.25.48/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/btcsuite/btcd v0.0.0-20171128150713-2e60448ffcc6/go.mod h1:Dmm/EzmjnCiweXmzRIAiUWCInVmPgjkzgv5k4tVyXiQ= +github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s= +github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cloudflare/cloudflare-go v0.10.2-0.20190916151808-a80f83b9add9/go.mod h1:1MxXX1Ux4x6mqPmjkUgTP1CdXIBXKX7T+Jk9Gxrmx+U= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea h1:j4317fAZh7X6GqbFowYdYdI0L9bwxL07jyPZIdepyZ0= +github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= +github.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/dop251/goja v0.0.0-20200721192441-a695b0cdd498/go.mod h1:Mw6PkjjMXWbTj+nnj4s3QPXq1jaT0s5pC0iFD4+BOAA= +github.com/dvyukov/go-fuzz v0.0.0-20200318091601-be3528f3a813/go.mod h1:11Gm+ccJnvAhCNLlf5+cS9KjtbaD5I5zaZpFMsTHWTw= +github.com/edsrzf/mmap-go v0.0.0-20160512033002-935e0e8a636c h1:JHHhtb9XWJrGNMcrVP6vyzO4dusgi/HnceHTgxSejUM= +github.com/edsrzf/mmap-go v0.0.0-20160512033002-935e0e8a636c/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= +github.com/ethereum/go-ethereum v1.9.25 h1:mMiw/zOOtCLdGLWfcekua0qPrJTe7FVIiHJ4IKNTfR0= +github.com/ethereum/go-ethereum v1.9.25/go.mod h1:vMkFiYLHI4tgPw4k2j4MHKoovchFE8plZ0M9VMk4/oM= +github.com/fatih/color v1.3.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fjl/memsize v0.0.0-20180418122429-ca190fb6ffbc/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff h1:tY80oXqGNY4FhTFhk+o9oFHGINQ/+vhlm8HFzi6znCI= +github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8= +github.com/go-sourcemap/sourcemap v2.1.2+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg= +github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.3-0.20201103224600-674baa8c7fc3 h1:ur2rms48b3Ep1dxh7aUV2FZEQ8jEVO2F6ILKx8ofkAg= +github.com/golang/snappy v0.0.3-0.20201103224600-674baa8c7fc3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/gorilla/websocket v1.4.1-0.20190629185528-ae1634f6a989 h1:giknQ4mEuDFmmHSrGcbargOuLHQGtywqo4mheITex54= +github.com/gorilla/websocket v1.4.1-0.20190629185528-ae1634f6a989/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/graph-gophers/graphql-go v0.0.0-20191115155744-f33e81362277/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/holiman/uint256 v1.1.1 h1:4JywC80b+/hSfljFlEBLHrrh+CIONLDz9NuFl0af4Mw= +github.com/holiman/uint256 v1.1.1/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/huin/goupnp v1.0.0 h1:wg75sLpL6DZqwHQN6E1Cfk6mtfzS45z8OV+ic+DtHRo= +github.com/huin/goupnp v1.0.0/go.mod h1:n9v9KO1tAxYH82qOn+UTIFQDmx5n1Zxd/ClZDMX7Bnc= +github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= +github.com/influxdata/influxdb v1.2.3-0.20180221223340-01288bdb0883/go.mod h1:qZna6X/4elxqT3yI9iZYdZrWWdeFOOprn86kgg4+IzY= +github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458 h1:6OvNmYgJyexcZ3pYbTI9jWx5tHo1Dee/tWbLMfPe2TA= +github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= +github.com/jedisct1/go-minisign v0.0.0-20190909160543-45766022959e/go.mod h1:G1CVv03EnqU1wYL2dFwXxW2An0az9JTl/ZsqXQeBlkU= +github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/julienschmidt/httprouter v1.1.1-0.20170430222011-975b5c4c7c21/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/karalabe/usb v0.0.0-20190919080040-51dc0efba356 h1:I/yrLt2WilKxlQKCM52clh5rGzTKpVctGT1lH4Dc8Jw= +github.com/karalabe/usb v0.0.0-20190919080040-51dc0efba356/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/mattn/go-colorable v0.1.0/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-ieproxy v0.0.0-20190610004146-91bb50d98149/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc= +github.com/mattn/go-ieproxy v0.0.0-20190702010315-6dee0af9227d/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc= +github.com/mattn/go-isatty v0.0.5-0.20180830101745-3fb116b82035/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-runewidth v0.0.4 h1:2BvfKmzob6Bmd4YsL0zygOqfdFnK7GR4QL06Do4/p7Y= +github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0= +github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/olekukonko/tablewriter v0.0.2-0.20190409134802-7e037d187b0c h1:1RHs3tNxjXGHeul8z2t6H2N2TlAqpKe5yryJztRx4Jk= +github.com/olekukonko/tablewriter v0.0.2-0.20190409134802-7e037d187b0c/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/pborman/uuid v0.0.0-20170112150404-1b00554d8222 h1:goeTyGkArOZIVOMA0dQbyuPWGNQJZGPwPu/QS9GlpnA= +github.com/pborman/uuid v0.0.0-20170112150404-1b00554d8222/go.mod h1:VyrYX9gd7irzKovcSS6BIIEwPRkP2Wm2m9ufcdFSJ34= +github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7 h1:oYW+YCJ1pachXTQmzR3rNLYGGz4g/UgFcjb28p/viDM= +github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/tsdb v0.6.2-0.20190402121629-4f204dcbc150 h1:ZeU+auZj1iNzN8iVhff6M38Mfu73FQiJve/GEXYJBjE= +github.com/prometheus/tsdb v0.6.2-0.20190402121629-4f204dcbc150/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/rjeczalik/notify v0.9.1 h1:CLCKso/QK1snAlnhNR/CNvNiFU2saUtjV0bx3EwNeCE= +github.com/rjeczalik/notify v0.9.1/go.mod h1:rKwnCoCGeuQnwBtTSPL9Dad03Vh2n40ePRrjvIXnJho= +github.com/rs/cors v0.0.0-20160617231935-a62a804a8a00/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= +github.com/rs/xhandler v0.0.0-20160618193221-ed27b6fd6521/go.mod h1:RvLn4FgxWubrpZHtQLnOf6EwhN2hEMusxZOhcW9H3UQ= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/shirou/gopsutil v2.20.5+incompatible h1:tYH07UPoQt0OCQdgWWMgYHy3/a9bcxNpBIysykNIP7I= +github.com/shirou/gopsutil v2.20.5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4 h1:Gb2Tyox57NRNuZ2d3rmvB3pcmbu7O1RS3m8WRx7ilrg= +github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q= +github.com/steakknife/bloomfilter v0.0.0-20180922174646-6819c0d2a570 h1:gIlAHnH1vJb5vwEjIp5kBj/eu99p/bl0Ay2goiPe5xE= +github.com/steakknife/bloomfilter v0.0.0-20180922174646-6819c0d2a570/go.mod h1:8OR4w3TdeIHIh1g6EMY5p0gVNOovcWC+1vpc7naMuAw= +github.com/steakknife/hamming v0.0.0-20180906055917-c99c65617cd3 h1:njlZPzLwU639dk2kqnCPPv+wNjq7Xb6EfUxe/oX0/NM= +github.com/steakknife/hamming v0.0.0-20180906055917-c99c65617cd3/go.mod h1:hpGUWaI9xL8pRQCTXQgocU38Qw1g0Us7n5PxxTwTCYU= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/syndtr/goleveldb v1.0.1-0.20200815110645-5c35d600f0ca h1:Ld/zXl5t4+D69SiV4JoN7kkfvJdOWlPpfxrzxpLMoUk= +github.com/syndtr/goleveldb v1.0.1-0.20200815110645-5c35d600f0ca/go.mod h1:u2MKkTVTVJWe5D1rCvame8WqhBd88EuIwODJZ1VHCPM= +github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef h1:wHSqTBrZW24CsNJDfeh9Ex6Pm0Rcpc7qrgKBiL44vF4= +github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs= +github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/wsddn/go-ecdh v0.0.0-20161211032359-48726bab9208 h1:1cngl9mPEoITZG8s8cVcUy5CeIBYhEESkOB7m6Gmkrk= +github.com/wsddn/go-ecdh v0.0.0-20161211032359-48726bab9208/go.mod h1:IotVbo4F+mw0EzQ08zFqg7pK3FebNXpaMsRy2RT+Ees= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190909091759-094676da4a83/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20200801112145-973feb4309de/go.mod h1:skQtrUTUwhdJvXM/2KKJzY8pDgNr9I/FOMqDVRPBUS4= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191209134235-331c550502dd/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202 h1:VvcQYSHwXgi7W+TpUR6A9g6Up98WAHf3f/ulnJ62IyA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200824131525-c12d262b63d8 h1:AvbQYmiaaaza3cW3QXRyPo5kYgpFIzOAfeAAN7m3qQ4= +golang.org/x/sys v0.0.0-20200824131525-c12d262b63d8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200117012304-6edc0a871e69/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c= +gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6/go.mod h1:uAJfkITjFhyEEuUfm7bsmCZRbW5WRq8s9EY8HZ6hCns= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/urfave/cli.v1 v1.20.0/go.mod h1:vuBzUtMdQeixQj8LVd+/98pzhxNGQoyuPBlsXHOQNO0= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= diff --git a/gost/internal/helpers/helpers.go b/gost/internal/helpers/helpers.go new file mode 100644 index 0000000..adfcc4f --- /dev/null +++ b/gost/internal/helpers/helpers.go @@ -0,0 +1,90 @@ +// this file can be split up into foo_helper, bar_helpers etc to prevent ye olde monolith + +package helpers + +import ( + "crypto/ecdsa" + "fmt" + "math/big" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" + "github.com/swivel-finance/gost/test/fakes" +) + +func NewAuth() (*ecdsa.PrivateKey, *bind.TransactOpts) { + pk, _ := crypto.GenerateKey() + return pk, bind.NewKeyedTransactor(pk) +} + +// GenBytes32 is a convenience function for some tests where a "GetHash" method is not available. +// Returns a type compatible with bytes32, given a string 32 chars or less. +func GenBytes32(s string) [32]byte { + bytes := [32]byte{} + copy(bytes[:], []byte(s)) + return bytes +} + +// NewCallOpts is a function which allows us to more succinctly place Call options +func NewCallOpts(a common.Address) *bind.CallOpts { + return &bind.CallOpts{ + // TODO: Should this be a settable argument? + Pending: false, + From: a, + } +} + +// NewTxOpts is a function which allows us to more succintly get a hydrated TransactOpts object +func NewTransactOpts(a *bind.TransactOpts, v *big.Int, p *big.Int, l uint64) *bind.TransactOpts { + return &bind.TransactOpts{ + From: a.From, + Signer: a.Signer, + Value: v, + GasPrice: p, + GasLimit: l, + } +} + +// Commafy will take a big integer and return a string with commas so that logging +// big integers is human readable +func Commafy(n *big.Int) string { + in := fmt.Sprintf("%d", n) + out := make([]byte, len(in)+(len(in)-2+int(in[0]/'0'))/3) + + for i, j, k := len(in)-1, len(out)-1, 0; ; i, j = i-1, j-1 { + out[j] = in[i] + if i == 0 { + return string(out) + } + if k++; k == 3 { + j, k = j-1, 0 + out[j] = ',' + } + } +} + +// NewHashOrder will take args to hydrate a Hash.Order and return it +func NewHashOrder( + k [32]byte, + maker common.Address, + u common.Address, + v bool, + exit bool, + principal int64, + premium int64, + maturity int64, + expiry int64, +) fakes.HashOrder { + return fakes.HashOrder{ + Key: k, + Maker: maker, + Underlying: u, + Vault: v, + Exit: exit, + Principal: big.NewInt(principal), + Premium: big.NewInt(premium), + Maturity: big.NewInt(maturity), + Expiry: big.NewInt(expiry), + } +} diff --git a/gost/pkg/.DS_Store b/gost/pkg/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..d0942dde5ccee139ed824ffc35cb66e1e4233b7c GIT binary patch literal 6148 zcmeHK%}T>S5T4b7r6Lr2=|$M1*Wz7ci5ETg1^P=B6H{ud;3;Rl_#!@r;ME84E&2d{ zv%5_bV?*>HQf6T1+id2`&U_@hSt3&H`LIP)C!#7EW2FZ7jq!bMIoon0OjhO@Bbw2K z0_xEq7cB##fGF_a6yR@npF(`GQ@W<~_sjhe-NIkd4UL0wt22ngi7jC9QkEA+zTXd` zKH{rS!TIAy^Yyemclc}WS9XTLpArP<_>iQ1=Xn>%l03gWCyZ9Pt&hs&gGCn_0ONiZZifT$^xG zo<;GZfGChvVB22SdH+9KfBw&sR26MMHse h+p+2JR@_80hI^VjK+j=p5hF195il}{69xWMflt(G!sq}1 literal 0 HcmV?d00001 diff --git a/gost/pkg/marketplacetesting/constants.go b/gost/pkg/marketplacetesting/constants.go new file mode 100644 index 0000000..fb1b442 --- /dev/null +++ b/gost/pkg/marketplacetesting/constants.go @@ -0,0 +1,15 @@ +package marketplacetesting + +import "math/big" + +const ONE_ETH = 1000000000000000000 +const ONE_GWEI = 1000000000 +const ONE_WEI = 1 + +var ZERO = big.NewInt(0) + +// MATURITY is one day, in seconds +const MATURITY = 86400 + +// MATURE_EVENT_SIG = crypto.Keccak256Hash([]byte("Mature(address,uint256,uint256,uint256))").Hex() +const MATURE_EVENT_SIG = "0x0080e09d7b4544aa5a923873be1df3e31945593d40cb1c874d99259ec3ac43a4" \ No newline at end of file diff --git a/gost/pkg/marketplacetesting/construction_test.go b/gost/pkg/marketplacetesting/construction_test.go new file mode 100644 index 0000000..be19c14 --- /dev/null +++ b/gost/pkg/marketplacetesting/construction_test.go @@ -0,0 +1,51 @@ +package marketplacetesting + +import ( + "math/big" + test "testing" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + // "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" + "github.com/swivel-finance/gost/test/marketplace" +) + +type marketCtorSuite struct { + suite.Suite + Env *Env + Dep *Dep + MarketPlace *marketplace.MarketPlaceSession // *Session objects are created by the go bindings +} + +func (s *marketCtorSuite) SetupSuite() { + var err error + + s.Env = NewEnv(big.NewInt(ONE_ETH)) // each of the wallets in the env will begin with this balance + s.Dep, err = Deploy(s.Env) + + if err != nil { + panic(err) + } + + // binding owner to both, kind of why it exists - but could be any of the env wallets + s.MarketPlace = &marketplace.MarketPlaceSession{ + Contract: s.Dep.MarketPlace, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } +} + +func (s *marketCtorSuite) TestAdmin() { + assert := assert.New(s.T()) + addr, err := s.MarketPlace.Admin() + assert.Nil(err) + assert.Equal(addr, s.Env.Owner.Opts.From) +} + +func TestMarketCtorSuite(t *test.T) { + suite.Run(t, &marketCtorSuite{}) +} diff --git a/gost/pkg/marketplacetesting/create_market_test.go b/gost/pkg/marketplacetesting/create_market_test.go new file mode 100644 index 0000000..a7212f9 --- /dev/null +++ b/gost/pkg/marketplacetesting/create_market_test.go @@ -0,0 +1,135 @@ +package marketplacetesting + +import ( + "math/big" + test "testing" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" + "github.com/swivel-finance/gost/test/marketplace" + "github.com/swivel-finance/gost/test/mocks" +) + +type createMarketSuite struct { + suite.Suite + Env *Env + Dep *Dep + MarketPlace *marketplace.MarketPlaceSession // *Session objects are created by the go bindings +} + +func (s *createMarketSuite) SetupSuite() { + var err error + + s.Env = NewEnv(big.NewInt(ONE_ETH)) // each of the wallets in the env will begin with this balance + s.Dep, err = Deploy(s.Env) + + if err != nil { + panic(err) + } + + // binding owner to both, kind of why it exists - but could be any of the env wallets + s.MarketPlace = &marketplace.MarketPlaceSession{ + Contract: s.Dep.MarketPlace, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } +} + +func (s *createMarketSuite) TestCreateMarket18Decimals() { + assert := assert.New(s.T()) + // the swivel address must be set + _, err := s.MarketPlace.SetSwivelAddress(s.Dep.SwivelAddress) + assert.Nil(err) + s.Env.Blockchain.Commit() + // addresses can be BS in this test... + underlying := common.HexToAddress("0x123") + maturity := big.NewInt(123456789) + ctoken := common.HexToAddress("0x456") + + tx, err := s.MarketPlace.CreateMarket( + underlying, + maturity, + ctoken, + "awesome market", + "AM", + uint8(18), + ) + + assert.Nil(err) + assert.NotNil(tx) + s.Env.Blockchain.Commit() + + // we should be able to fetch the market now... + market, err := s.MarketPlace.Markets(underlying, maturity) + assert.Nil(err) + assert.Equal(market.CTokenAddr, ctoken) + assert.NotEqual(market.ZcTokenAddr, common.HexToAddress("0x0")) + assert.NotEqual(market.VaultAddr, common.HexToAddress("0x0")) + + zcTokenContract, err := mocks.NewZcToken(market.ZcTokenAddr, s.Env.Blockchain) + zcToken := &mocks.ZcTokenSession{ + Contract: zcTokenContract, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } + + decimals, err := zcToken.Decimals() + assert.Equal(decimals, uint8(18)) +} + +func (s *createMarketSuite) TestCreateMarket6Decimals() { + assert := assert.New(s.T()) + // the swivel address must be set + _, err := s.MarketPlace.SetSwivelAddress(s.Dep.SwivelAddress) + assert.Nil(err) + s.Env.Blockchain.Commit() + // addresses can be BS in this test... + underlying := common.HexToAddress("0x234") + maturity := big.NewInt(123456781) + ctoken := common.HexToAddress("0x567") + + tx, err := s.MarketPlace.CreateMarket( + underlying, + maturity, + ctoken, + "awesomer market", + "ARM", + uint8(6), + ) + + assert.Nil(err) + assert.NotNil(tx) + s.Env.Blockchain.Commit() + + // we should be able to fetch the market now... + market, err := s.MarketPlace.Markets(underlying, maturity) + assert.Nil(err) + assert.Equal(market.CTokenAddr, ctoken) + assert.NotEqual(market.ZcTokenAddr, common.HexToAddress("0x0")) + assert.NotEqual(market.VaultAddr, common.HexToAddress("0x0")) + + zcTokenContract, err := mocks.NewZcToken(market.ZcTokenAddr, s.Env.Blockchain) + zcToken := &mocks.ZcTokenSession{ + Contract: zcTokenContract, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } + + decimals, err := zcToken.Decimals() + assert.Equal(decimals, uint8(6)) +} + +func TestCreateMarketSuite(t *test.T) { + suite.Run(t, &createMarketSuite{}) +} diff --git a/gost/pkg/marketplacetesting/custodial_exit_test.go b/gost/pkg/marketplacetesting/custodial_exit_test.go new file mode 100644 index 0000000..1e0cf7b --- /dev/null +++ b/gost/pkg/marketplacetesting/custodial_exit_test.go @@ -0,0 +1,290 @@ +package marketplacetesting + +import ( + "math/big" + test "testing" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + assertions "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" + "github.com/swivel-finance/gost/test/marketplace" + "github.com/swivel-finance/gost/test/mocks" +) + +type custodialExitSuite struct { + suite.Suite + Env *Env + Dep *Dep + Erc20 *mocks.Erc20Session + CErc20 *mocks.CErc20Session + MarketPlace *marketplace.MarketPlaceSession // *Session objects are created by the go bindings +} + +func (s *custodialExitSuite) SetupTest() { + var err error + assert := assertions.New(s.T()) + + s.Env = NewEnv(big.NewInt(ONE_ETH)) // each of the wallets in the env will begin with this balance + s.Dep, err = Deploy(s.Env) + assert.Nil(err) + + err = s.Env.Blockchain.AdjustTime(0) // set bc timestamp to 0 + assert.Nil(err) + + s.Env.Blockchain.Commit() + + s.Erc20 = &mocks.Erc20Session{ + Contract: s.Dep.Erc20, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } + + s.CErc20 = &mocks.CErc20Session{ + Contract: s.Dep.CErc20, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } + + // binding owner to both, kind of why it exists - but could be any of the env wallets + s.MarketPlace = &marketplace.MarketPlaceSession{ + Contract: s.Dep.MarketPlace, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } + + // the Marketplace needs to have a swivel addr set, we'll use the owner addr so as not to have to generate a new signer + // and re-do all the calls... + s.MarketPlace.SetSwivelAddress(s.Env.Owner.Opts.From) + s.Env.Blockchain.Commit() +} + +func (s *custodialExitSuite) TestCustodialExit() { + assert := assertions.New(s.T()) + underlying := s.Dep.Erc20Address + maturity := s.Dep.Maturity + ctoken := s.Dep.CErc20Address + + tx, err := s.MarketPlace.CreateMarket( + underlying, + maturity, + ctoken, + "awesome market", + "AM", + 18, + ) + + assert.Nil(err) + assert.NotNil(tx) + s.Env.Blockchain.Commit() + + ownerOpts := s.Env.Owner.Opts + user1Opts := s.Env.User1.Opts + + // we should be able to fetch the market now... + market, err := s.MarketPlace.Markets(underlying, maturity) + assert.Nil(err) + assert.Equal(market.CTokenAddr, ctoken) + + zcTokenContract, err := mocks.NewZcToken(market.ZcTokenAddr, s.Env.Blockchain) + zcToken := &mocks.ZcTokenSession{ + Contract: zcTokenContract, + CallOpts: bind.CallOpts{From: ownerOpts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: ownerOpts.From, + Signer: ownerOpts.Signer, + }, + } + + zcMaturity, err := zcToken.Maturity() + assert.Equal(maturity, zcMaturity) + + tx, err = zcToken.BurnReturns(true) + assert.Nil(err) + assert.NotNil(tx) + + vaultTrackerContract, err := mocks.NewVaultTracker(market.VaultAddr, s.Env.Blockchain) + vaultTracker := &mocks.VaultTrackerSession{ + Contract: vaultTrackerContract, + CallOpts: bind.CallOpts{From: ownerOpts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: ownerOpts.From, + Signer: ownerOpts.Signer, + }, + } + + tx, err = vaultTracker.RemoveNotionalReturns(true) + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + amount := big.NewInt(100) + tx, err = s.MarketPlace.CustodialExit(underlying, maturity, ownerOpts.From, user1Opts.From, amount) + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + mintAmount, err := zcToken.BurnCalled(ownerOpts.From) + assert.Nil(err) + assert.Equal(amount, mintAmount) + + s.Env.Blockchain.Commit() + + addNotionalAmount, err := vaultTracker.RemoveNotionalCalled(user1Opts.From) + assert.Nil(err) + assert.Equal(amount, addNotionalAmount) + + s.Env.Blockchain.Commit() +} + +func (s *custodialExitSuite) TestCustodialInitiateBurnFails() { + assert := assertions.New(s.T()) + underlying := s.Dep.Erc20Address + maturity := s.Dep.Maturity + ctoken := s.Dep.CErc20Address + + tx, err := s.MarketPlace.CreateMarket( + underlying, + maturity, + ctoken, + "awesome market", + "AM", + 18, + ) + + assert.Nil(err) + assert.NotNil(tx) + s.Env.Blockchain.Commit() + + ownerOpts := s.Env.Owner.Opts + user1Opts := s.Env.User1.Opts + + // we should be able to fetch the market now... + market, err := s.MarketPlace.Markets(underlying, maturity) + assert.Nil(err) + assert.Equal(market.CTokenAddr, ctoken) + + zcTokenContract, err := mocks.NewZcToken(market.ZcTokenAddr, s.Env.Blockchain) + zcToken := &mocks.ZcTokenSession{ + Contract: zcTokenContract, + CallOpts: bind.CallOpts{From: ownerOpts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: ownerOpts.From, + Signer: ownerOpts.Signer, + }, + } + + zcMaturity, err := zcToken.Maturity() + assert.Equal(maturity, zcMaturity) + + tx, err = zcToken.BurnReturns(false) + assert.Nil(err) + assert.NotNil(tx) + + vaultTrackerContract, err := mocks.NewVaultTracker(market.VaultAddr, s.Env.Blockchain) + vaultTracker := &mocks.VaultTrackerSession{ + Contract: vaultTrackerContract, + CallOpts: bind.CallOpts{From: ownerOpts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: ownerOpts.From, + Signer: ownerOpts.Signer, + }, + } + + tx, err = vaultTracker.AddNotionalReturns(true) + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + amount := big.NewInt(100) + tx, err = s.MarketPlace.CustodialExit(underlying, maturity, ownerOpts.From, user1Opts.From, amount) + assert.NotNil(err) + assert.Regexp("burn failed", err.Error()) + assert.Nil(tx) + + s.Env.Blockchain.Commit() +} + +func (s *custodialExitSuite) TestCustodialInitiateRemoveNotionalFails() { + assert := assertions.New(s.T()) + underlying := s.Dep.Erc20Address + maturity := s.Dep.Maturity + ctoken := s.Dep.CErc20Address + + tx, err := s.MarketPlace.CreateMarket( + underlying, + maturity, + ctoken, + "awesome market", + "AM", + 18, + ) + + assert.Nil(err) + assert.NotNil(tx) + s.Env.Blockchain.Commit() + + ownerOpts := s.Env.Owner.Opts + user1Opts := s.Env.User1.Opts + + // we should be able to fetch the market now... + market, err := s.MarketPlace.Markets(underlying, maturity) + assert.Nil(err) + assert.Equal(market.CTokenAddr, ctoken) + + zcTokenContract, err := mocks.NewZcToken(market.ZcTokenAddr, s.Env.Blockchain) + zcToken := &mocks.ZcTokenSession{ + Contract: zcTokenContract, + CallOpts: bind.CallOpts{From: ownerOpts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: ownerOpts.From, + Signer: ownerOpts.Signer, + }, + } + + zcMaturity, err := zcToken.Maturity() + assert.Equal(maturity, zcMaturity) + + tx, err = zcToken.BurnReturns(true) + assert.Nil(err) + assert.NotNil(tx) + + vaultTrackerContract, err := mocks.NewVaultTracker(market.VaultAddr, s.Env.Blockchain) + vaultTracker := &mocks.VaultTrackerSession{ + Contract: vaultTrackerContract, + CallOpts: bind.CallOpts{From: ownerOpts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: ownerOpts.From, + Signer: ownerOpts.Signer, + }, + } + + tx, err = vaultTracker.RemoveNotionalReturns(false) + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + amount := big.NewInt(100) + tx, err = s.MarketPlace.CustodialExit(underlying, maturity, ownerOpts.From, user1Opts.From, amount) + assert.NotNil(err) + assert.Regexp("remove notional failed", err.Error()) + assert.Nil(tx) + + s.Env.Blockchain.Commit() +} + +func TestCustodialExitSuite(t *test.T) { + suite.Run(t, &custodialExitSuite{}) +} diff --git a/gost/pkg/marketplacetesting/custodial_initiate_test.go b/gost/pkg/marketplacetesting/custodial_initiate_test.go new file mode 100644 index 0000000..7977ffb --- /dev/null +++ b/gost/pkg/marketplacetesting/custodial_initiate_test.go @@ -0,0 +1,288 @@ +package marketplacetesting + +import ( + "math/big" + test "testing" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + assertions "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" + "github.com/swivel-finance/gost/test/marketplace" + "github.com/swivel-finance/gost/test/mocks" +) + +type custodialInitiateSuite struct { + suite.Suite + Env *Env + Dep *Dep + Erc20 *mocks.Erc20Session + CErc20 *mocks.CErc20Session + MarketPlace *marketplace.MarketPlaceSession // *Session objects are created by the go bindings +} + +func (s *custodialInitiateSuite) SetupTest() { + var err error + assert := assertions.New(s.T()) + + s.Env = NewEnv(big.NewInt(ONE_ETH)) // each of the wallets in the env will begin with this balance + s.Dep, err = Deploy(s.Env) + assert.Nil(err) + + err = s.Env.Blockchain.AdjustTime(0) // set bc timestamp to 0 + assert.Nil(err) + + s.Env.Blockchain.Commit() + + s.Erc20 = &mocks.Erc20Session{ + Contract: s.Dep.Erc20, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } + + s.CErc20 = &mocks.CErc20Session{ + Contract: s.Dep.CErc20, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } + + // binding owner to both, kind of why it exists - but could be any of the env wallets + s.MarketPlace = &marketplace.MarketPlaceSession{ + Contract: s.Dep.MarketPlace, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } + + s.MarketPlace.SetSwivelAddress(s.Env.Owner.Opts.From) + s.Env.Blockchain.Commit() +} + +func (s *custodialInitiateSuite) TestCustodialInitiate() { + assert := assertions.New(s.T()) + underlying := s.Dep.Erc20Address + maturity := s.Dep.Maturity + ctoken := s.Dep.CErc20Address + + tx, err := s.MarketPlace.CreateMarket( + underlying, + maturity, + ctoken, + "awesome market", + "AM", + 18, + ) + + assert.Nil(err) + assert.NotNil(tx) + s.Env.Blockchain.Commit() + + ownerOpts := s.Env.Owner.Opts + user1Opts := s.Env.User1.Opts + + // we should be able to fetch the market now... + market, err := s.MarketPlace.Markets(underlying, maturity) + assert.Nil(err) + assert.Equal(market.CTokenAddr, ctoken) + + zcTokenContract, err := mocks.NewZcToken(market.ZcTokenAddr, s.Env.Blockchain) + zcToken := &mocks.ZcTokenSession{ + Contract: zcTokenContract, + CallOpts: bind.CallOpts{From: ownerOpts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: ownerOpts.From, + Signer: ownerOpts.Signer, + }, + } + + zcMaturity, err := zcToken.Maturity() + assert.Equal(maturity, zcMaturity) + + tx, err = zcToken.MintReturns(true) + assert.Nil(err) + assert.NotNil(tx) + + vaultTrackerContract, err := mocks.NewVaultTracker(market.VaultAddr, s.Env.Blockchain) + vaultTracker := &mocks.VaultTrackerSession{ + Contract: vaultTrackerContract, + CallOpts: bind.CallOpts{From: ownerOpts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: ownerOpts.From, + Signer: ownerOpts.Signer, + }, + } + + tx, err = vaultTracker.AddNotionalReturns(true) + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + amount := big.NewInt(100) + tx, err = s.MarketPlace.CustodialInitiate(underlying, maturity, ownerOpts.From, user1Opts.From, amount) + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + mintAmount, err := zcToken.MintCalled(ownerOpts.From) + assert.Nil(err) + assert.Equal(amount, mintAmount) + + s.Env.Blockchain.Commit() + + addNotionalAmount, err := vaultTracker.AddNotionalCalled(user1Opts.From) + assert.Nil(err) + assert.Equal(amount, addNotionalAmount) + + s.Env.Blockchain.Commit() +} + +func (s *custodialInitiateSuite) TestCustodialInitiateMintFails() { + assert := assertions.New(s.T()) + underlying := s.Dep.Erc20Address + maturity := s.Dep.Maturity + ctoken := s.Dep.CErc20Address + + tx, err := s.MarketPlace.CreateMarket( + underlying, + maturity, + ctoken, + "awesome market", + "AM", + 18, + ) + + assert.Nil(err) + assert.NotNil(tx) + s.Env.Blockchain.Commit() + + ownerOpts := s.Env.Owner.Opts + user1Opts := s.Env.User1.Opts + + // we should be able to fetch the market now... + market, err := s.MarketPlace.Markets(underlying, maturity) + assert.Nil(err) + assert.Equal(market.CTokenAddr, ctoken) + + zcTokenContract, err := mocks.NewZcToken(market.ZcTokenAddr, s.Env.Blockchain) + zcToken := &mocks.ZcTokenSession{ + Contract: zcTokenContract, + CallOpts: bind.CallOpts{From: ownerOpts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: ownerOpts.From, + Signer: ownerOpts.Signer, + }, + } + + zcMaturity, err := zcToken.Maturity() + assert.Equal(maturity, zcMaturity) + + tx, err = zcToken.MintReturns(false) + assert.Nil(err) + assert.NotNil(tx) + + vaultTrackerContract, err := mocks.NewVaultTracker(market.VaultAddr, s.Env.Blockchain) + vaultTracker := &mocks.VaultTrackerSession{ + Contract: vaultTrackerContract, + CallOpts: bind.CallOpts{From: ownerOpts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: ownerOpts.From, + Signer: ownerOpts.Signer, + }, + } + + tx, err = vaultTracker.AddNotionalReturns(true) + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + amount := big.NewInt(100) + tx, err = s.MarketPlace.CustodialInitiate(underlying, maturity, ownerOpts.From, user1Opts.From, amount) + assert.NotNil(err) + assert.Regexp("mint failed", err.Error()) + assert.Nil(tx) + + s.Env.Blockchain.Commit() +} + +func (s *custodialInitiateSuite) TestCustodialInitiateAddNotionalFails() { + assert := assertions.New(s.T()) + underlying := s.Dep.Erc20Address + maturity := s.Dep.Maturity + ctoken := s.Dep.CErc20Address + + tx, err := s.MarketPlace.CreateMarket( + underlying, + maturity, + ctoken, + "awesome market", + "AM", + 18, + ) + + assert.Nil(err) + assert.NotNil(tx) + s.Env.Blockchain.Commit() + + ownerOpts := s.Env.Owner.Opts + user1Opts := s.Env.User1.Opts + + // we should be able to fetch the market now... + market, err := s.MarketPlace.Markets(underlying, maturity) + assert.Nil(err) + assert.Equal(market.CTokenAddr, ctoken) + + zcTokenContract, err := mocks.NewZcToken(market.ZcTokenAddr, s.Env.Blockchain) + zcToken := &mocks.ZcTokenSession{ + Contract: zcTokenContract, + CallOpts: bind.CallOpts{From: ownerOpts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: ownerOpts.From, + Signer: ownerOpts.Signer, + }, + } + + zcMaturity, err := zcToken.Maturity() + assert.Equal(maturity, zcMaturity) + + tx, err = zcToken.MintReturns(true) + assert.Nil(err) + assert.NotNil(tx) + + vaultTrackerContract, err := mocks.NewVaultTracker(market.VaultAddr, s.Env.Blockchain) + vaultTracker := &mocks.VaultTrackerSession{ + Contract: vaultTrackerContract, + CallOpts: bind.CallOpts{From: ownerOpts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: ownerOpts.From, + Signer: ownerOpts.Signer, + }, + } + + tx, err = vaultTracker.AddNotionalReturns(false) + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + amount := big.NewInt(100) + tx, err = s.MarketPlace.CustodialInitiate(underlying, maturity, ownerOpts.From, user1Opts.From, amount) + assert.NotNil(err) + assert.Regexp("add notional failed", err.Error()) + assert.Nil(tx) + + s.Env.Blockchain.Commit() +} + +func TestCustodialInitiateSuite(t *test.T) { + suite.Run(t, &custodialInitiateSuite{}) +} diff --git a/gost/pkg/marketplacetesting/dep.go b/gost/pkg/marketplacetesting/dep.go new file mode 100644 index 0000000..349e077 --- /dev/null +++ b/gost/pkg/marketplacetesting/dep.go @@ -0,0 +1,63 @@ +package marketplacetesting + +import ( + "math/big" + + "github.com/ethereum/go-ethereum/common" + "github.com/swivel-finance/gost/test/marketplace" + "github.com/swivel-finance/gost/test/mocks" +) + +type Dep struct { + Erc20 *mocks.Erc20 + Erc20Address common.Address + + CErc20 *mocks.CErc20 + CErc20Address common.Address + + MarketPlaceAddress common.Address + MarketPlace *marketplace.MarketPlace + + Maturity *big.Int + + SwivelAddress common.Address +} + +func Deploy(e *Env) (*Dep, error) { + maturity := big.NewInt(MATURITY) + cercAddress, _, cercContract, cercErr := mocks.DeployCErc20(e.Owner.Opts, e.Blockchain) + + if cercErr != nil { + return nil, cercErr + } + + e.Blockchain.Commit() + + ercAddress, _, ercContract, ercErr := mocks.DeployErc20(e.Owner.Opts, e.Blockchain) + + if ercErr != nil { + return nil, ercErr + } + + e.Blockchain.Commit() + + // deploy contract... + marketAddress, _, marketContract, marketErr := marketplace.DeployMarketPlace(e.Owner.Opts, e.Blockchain) + + if marketErr != nil { + return nil, marketErr + } + + e.Blockchain.Commit() + + return &Dep{ + MarketPlaceAddress: marketAddress, + MarketPlace: marketContract, + CErc20Address: cercAddress, + CErc20: cercContract, + Erc20Address: ercAddress, + Erc20: ercContract, + SwivelAddress: common.HexToAddress("0xAbC123"), + Maturity: maturity, + }, nil +} diff --git a/gost/pkg/marketplacetesting/env.go b/gost/pkg/marketplacetesting/env.go new file mode 100644 index 0000000..20f7f01 --- /dev/null +++ b/gost/pkg/marketplacetesting/env.go @@ -0,0 +1,52 @@ +package marketplacetesting + +import ( + "crypto/ecdsa" + "math/big" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/accounts/abi/bind/backends" + "github.com/ethereum/go-ethereum/core" + "github.com/swivel-finance/gost/internal/helpers" +) + +// Auth is a custom type which allows us easy access to the dynamically generated +// ecdsa.PrivateKey along with the bind.TransactOpts +type Auth struct { + PK *ecdsa.PrivateKey + Opts *bind.TransactOpts +} + +// Env, holds Auth objects capable of signing transactions. +// Also holds the Geth simulated backend. +type Env struct { + Alloc core.GenesisAlloc + // TODO maybe change to Admin to fit v2 contract terms... + Owner *Auth + User1 *Auth + User2 *Auth + Blockchain *backends.SimulatedBackend +} + +// NewEnv returns a hydrated Env struct, ready for use. +// Given a balance argument, it assigns this as the wallet balance for +// each authorization object in the Ctx +func NewEnv(b *big.Int) *Env { + pk, owner := helpers.NewAuth() + pk1, u1 := helpers.NewAuth() + pk2, u2 := helpers.NewAuth() + alloc := make(core.GenesisAlloc) + alloc[owner.From] = core.GenesisAccount{Balance: b} + alloc[u1.From] = core.GenesisAccount{Balance: b} + alloc[u2.From] = core.GenesisAccount{Balance: b} + // 2nd arg is a gas limit, a uint64. we'll use... + bc := backends.NewSimulatedBackend(alloc, 6700000) + + return &Env{ + Alloc: alloc, + Owner: &Auth{PK: pk, Opts: owner}, + User1: &Auth{PK: pk1, Opts: u1}, + User2: &Auth{PK: pk2, Opts: u2}, + Blockchain: bc, + } +} diff --git a/gost/pkg/marketplacetesting/get_ctoken_address_address_test.go b/gost/pkg/marketplacetesting/get_ctoken_address_address_test.go new file mode 100644 index 0000000..989717c --- /dev/null +++ b/gost/pkg/marketplacetesting/get_ctoken_address_address_test.go @@ -0,0 +1,72 @@ +package marketplacetesting + +import ( + "math/big" + test "testing" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + assertions "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" + "github.com/swivel-finance/gost/test/marketplace" +) + +type cTokenAddrSuite struct { + suite.Suite + Env *Env + Dep *Dep + MarketPlace *marketplace.MarketPlaceSession // *Session objects are created by the go bindings +} + +func (s *cTokenAddrSuite) SetupSuite() { + var err error + + s.Env = NewEnv(big.NewInt(ONE_ETH)) // each of the wallets in the env will begin with this balance + s.Dep, err = Deploy(s.Env) + + if err != nil { + panic(err) + } + + s.MarketPlace = &marketplace.MarketPlaceSession{ + Contract: s.Dep.MarketPlace, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } +} + +func (s *cTokenAddrSuite) TestSetCTokenAddr() { + assert := assertions.New(s.T()) + // the swivel address must be set + _, err := s.MarketPlace.SetSwivelAddress(s.Dep.SwivelAddress) + assert.Nil(err) + s.Env.Blockchain.Commit() + // addresses can be BS in this test... + underlying := common.HexToAddress("0x123") + maturity := big.NewInt(123456789) + cTokenAddr := common.HexToAddress("0x456") + + tx, err := s.MarketPlace.CreateMarket( + underlying, + maturity, + cTokenAddr, + "awesome market", + "AM", + 18, + ) + + assert.Nil(err) + assert.NotNil(tx) + s.Env.Blockchain.Commit() + + cTokenAddrC, err := s.MarketPlace.CTokenAddress(underlying, maturity) + assert.Nil(err) + assert.Equal(cTokenAddr, cTokenAddrC) +} + +func TestCTokenAddrSuite(t *test.T) { + suite.Run(t, &cTokenAddrSuite{}) +} diff --git a/gost/pkg/marketplacetesting/mature_market_test.go b/gost/pkg/marketplacetesting/mature_market_test.go new file mode 100644 index 0000000..bc8fafb --- /dev/null +++ b/gost/pkg/marketplacetesting/mature_market_test.go @@ -0,0 +1,277 @@ +package marketplacetesting + +import ( + "context" + "math/big" + test "testing" + "time" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + assertions "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" + "github.com/swivel-finance/gost/test/marketplace" + "github.com/swivel-finance/gost/test/mocks" +) + +type matureMarketSuite struct { + suite.Suite + Env *Env + Dep *Dep + CErc20 *mocks.CErc20Session + MarketPlace *marketplace.MarketPlaceSession // *Session objects are created by the go bindings +} + +func (s *matureMarketSuite) SetupTest() { + var err error + assert := assertions.New(s.T()) + + s.Env = NewEnv(big.NewInt(ONE_ETH)) // each of the wallets in the env will begin with this balance + s.Dep, err = Deploy(s.Env) + assert.Nil(err) + + err = s.Env.Blockchain.AdjustTime(0) // set bc timestamp to 0 + assert.Nil(err) + s.Env.Blockchain.Commit() + + s.CErc20 = &mocks.CErc20Session{ + Contract: s.Dep.CErc20, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } + + // binding owner to both, kind of why it exists - but could be any of the env wallets + s.MarketPlace = &marketplace.MarketPlaceSession{ + Contract: s.Dep.MarketPlace, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } + + // the swivel address must be set + _, err = s.MarketPlace.SetSwivelAddress(s.Dep.SwivelAddress) + assert.Nil(err) + s.Env.Blockchain.Commit() +} + +func (s *matureMarketSuite) TestMaturityNotReached() { + assert := assertions.New(s.T()) + // addresses can be BS in this test as well... + underlying := common.HexToAddress("0x123") + maturity := s.Dep.Maturity + ctoken := s.Dep.CErc20Address + + tx, err := s.MarketPlace.CreateMarket( + underlying, + maturity, + ctoken, + "awesome market", + "AM", + 18, + ) + + assert.Nil(err) + assert.NotNil(tx) + s.Env.Blockchain.Commit() + + // we should be able to fetch the market now... + market, err := s.MarketPlace.Markets(underlying, maturity) + assert.Nil(err) + assert.Equal(market.CTokenAddr, ctoken) + + zcTokenContract, err := mocks.NewZcToken(market.ZcTokenAddr, s.Env.Blockchain) + zcToken := &mocks.ZcTokenSession{ + Contract: zcTokenContract, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } + + zcMaturity, err := zcToken.Maturity() + assert.Equal(maturity, zcMaturity) + + tx, err = s.MarketPlace.MatureMarket(underlying, maturity) + assert.NotNil(err) + assert.Regexp("maturity not reached", err.Error()) + assert.Nil(tx) + + s.Env.Blockchain.Commit() +} + +func (s *matureMarketSuite) TestMaturityReached() { + assert := assertions.New(s.T()) + // addresses can be BS in this test as well... + underlying := common.HexToAddress("0x123") + maturity := s.Dep.Maturity + ctoken := s.Dep.CErc20Address + + tx, err := s.MarketPlace.CreateMarket( + underlying, + maturity, + ctoken, + "awesome market", + "AM", + 18, + ) + + assert.Nil(err) + assert.NotNil(tx) + s.Env.Blockchain.Commit() + + // we should be able to fetch the market now... + market, err := s.MarketPlace.Markets(underlying, maturity) + assert.Nil(err) + assert.Equal(market.CTokenAddr, ctoken) + + zcTokenContract, err := mocks.NewZcToken(market.ZcTokenAddr, s.Env.Blockchain) + zcToken := &mocks.ZcTokenSession{ + Contract: zcTokenContract, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } + + zcMaturity, err := zcToken.Maturity() + assert.Equal(maturity, zcMaturity) + + vaultTrackerContract, err := mocks.NewVaultTracker(market.VaultAddr, s.Env.Blockchain) + vaultTracker := &mocks.VaultTrackerSession{ + Contract: vaultTrackerContract, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } + + tx, err = vaultTracker.MatureVaultReturns(true) + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + // move past the maturity + err = s.Env.Blockchain.AdjustTime(MATURITY * time.Second) + assert.Nil(err) + s.Env.Blockchain.Commit() + + rate := big.NewInt(123456789) + tx, err = s.CErc20.ExchangeRateCurrentReturns(rate) + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + tx, err = s.MarketPlace.MatureMarket(underlying, maturity) + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + maturityRate, err := s.MarketPlace.MaturityRate(underlying, maturity) + assert.Nil(err) + assert.Equal(rate, maturityRate) + + mature, err := s.MarketPlace.Mature(underlying, maturity) + assert.Nil(err) + assert.Equal(true, mature) + + receipt, err := s.Env.Blockchain.TransactionReceipt(context.Background(), tx.Hash()) + assert.Nil(err) + assert.NotNil(receipt) + + logs := receipt.Logs + assert.NotNil(logs) + assert.Equal(1, len(logs)) + + assert.Equal(MATURE_EVENT_SIG, logs[0].Topics[0].Hex()) + assert.Equal(underlying.Hex(), common.HexToAddress(logs[0].Topics[1].Hex()).String()) + assert.Equal(maturity, logs[0].Topics[2].Big()) +} + +func (s *matureMarketSuite) TestVaultMaturityNotReachedRequireFail() { + assert := assertions.New(s.T()) + // addresses can be BS in this test as well... + underlying := common.HexToAddress("0x123") + maturity := s.Dep.Maturity + ctoken := s.Dep.CErc20Address + + tx, err := s.MarketPlace.CreateMarket( + underlying, + maturity, + ctoken, + "awesome market", + "AM", + 18, + ) + + assert.Nil(err) + assert.NotNil(tx) + s.Env.Blockchain.Commit() + + // we should be able to fetch the market now... + market, err := s.MarketPlace.Markets(underlying, maturity) + assert.Nil(err) + assert.Equal(market.CTokenAddr, ctoken) + + zcTokenContract, err := mocks.NewZcToken(market.ZcTokenAddr, s.Env.Blockchain) + zcToken := &mocks.ZcTokenSession{ + Contract: zcTokenContract, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } + + zcMaturity, err := zcToken.Maturity() + assert.Equal(maturity, zcMaturity) + + vaultTrackerContract, err := mocks.NewVaultTracker(market.VaultAddr, s.Env.Blockchain) + vaultTracker := &mocks.VaultTrackerSession{ + Contract: vaultTrackerContract, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } + + tx, err = vaultTracker.MatureVaultReturns(false) + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + // move past the maturity + err = s.Env.Blockchain.AdjustTime(MATURITY * time.Second) + assert.Nil(err) + s.Env.Blockchain.Commit() + + rate := big.NewInt(123456789) + tx, err = s.CErc20.ExchangeRateCurrentReturns(rate) + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + tx, err = s.MarketPlace.MatureMarket(underlying, maturity) + assert.NotNil(err) + assert.Regexp("maturity not reached", err.Error()) + assert.Nil(tx) + + s.Env.Blockchain.Commit() +} + +func TestMatureMarketSuite(t *test.T) { + suite.Run(t, &matureMarketSuite{}) +} diff --git a/gost/pkg/marketplacetesting/p2p_vault_exchange_test.go b/gost/pkg/marketplacetesting/p2p_vault_exchange_test.go new file mode 100644 index 0000000..cbbdf9f --- /dev/null +++ b/gost/pkg/marketplacetesting/p2p_vault_exchange_test.go @@ -0,0 +1,187 @@ +package marketplacetesting + +import ( + "math/big" + test "testing" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + assertions "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" + "github.com/swivel-finance/gost/test/marketplace" + "github.com/swivel-finance/gost/test/mocks" +) + +type p2pVaultExchangeSuite struct { + suite.Suite + Env *Env + Dep *Dep + Erc20 *mocks.Erc20Session + CErc20 *mocks.CErc20Session + MarketPlace *marketplace.MarketPlaceSession // *Session objects are created by the go bindings +} + +func (s *p2pVaultExchangeSuite) SetupTest() { + var err error + + s.Env = NewEnv(big.NewInt(ONE_ETH)) // each of the wallets in the env will begin with this balance + s.Dep, err = Deploy(s.Env) + + if err != nil { + panic(err) + } + + err = s.Env.Blockchain.AdjustTime(0) // set bc timestamp to 0 + if err != nil { + panic(err) + } + + s.Env.Blockchain.Commit() + + s.Erc20 = &mocks.Erc20Session{ + Contract: s.Dep.Erc20, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } + + s.CErc20 = &mocks.CErc20Session{ + Contract: s.Dep.CErc20, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } + + // binding owner to both, kind of why it exists - but could be any of the env wallets + s.MarketPlace = &marketplace.MarketPlaceSession{ + Contract: s.Dep.MarketPlace, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } + + s.MarketPlace.SetSwivelAddress(s.Env.Owner.Opts.From) + s.Env.Blockchain.Commit() +} + +func (s *p2pVaultExchangeSuite) TestP2PVaultExchange() { + assert := assertions.New(s.T()) + underlying := s.Dep.Erc20Address + maturity := s.Dep.Maturity + ctoken := s.Dep.CErc20Address + + tx, err := s.MarketPlace.CreateMarket( + underlying, + maturity, + ctoken, + "awesome market", + "AM", + 18, + ) + + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + ownerOpts := s.Env.Owner.Opts + user1Opts := s.Env.User1.Opts + + // we should be able to fetch the market now... + market, err := s.MarketPlace.Markets(underlying, maturity) + assert.Nil(err) + assert.Equal(market.CTokenAddr, ctoken) + + s.Env.Blockchain.Commit() + + vaultTrackerContract, err := mocks.NewVaultTracker(market.VaultAddr, s.Env.Blockchain) + vaultTracker := &mocks.VaultTrackerSession{ + Contract: vaultTrackerContract, + CallOpts: bind.CallOpts{From: ownerOpts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: ownerOpts.From, + Signer: ownerOpts.Signer, + }, + } + + tx, err = vaultTracker.TransferNotionalFromReturns(true) + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + amount := big.NewInt(100) + tx, err = s.MarketPlace.P2pVaultExchange(underlying, maturity, ownerOpts.From, user1Opts.From, amount) + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + transferNotionalFromArgs, err := vaultTracker.TransferNotionalFromCalled(ownerOpts.From) + assert.Nil(err) + assert.Equal(user1Opts.From, transferNotionalFromArgs.To) + assert.Equal(amount, transferNotionalFromArgs.Amount) + + s.Env.Blockchain.Commit() +} + +func (s *p2pVaultExchangeSuite) TestP2PVaultExchangeTransferNotionalFromFails() { + assert := assertions.New(s.T()) + underlying := s.Dep.Erc20Address + maturity := s.Dep.Maturity + ctoken := s.Dep.CErc20Address + + tx, err := s.MarketPlace.CreateMarket( + underlying, + maturity, + ctoken, + "awesome market", + "AM", + 18, + ) + + assert.Nil(err) + assert.NotNil(tx) + s.Env.Blockchain.Commit() + + ownerOpts := s.Env.Owner.Opts + user1Opts := s.Env.User1.Opts + + // we should be able to fetch the market now... + market, err := s.MarketPlace.Markets(underlying, maturity) + assert.Nil(err) + assert.Equal(market.CTokenAddr, ctoken) + + vaultTrackerContract, err := mocks.NewVaultTracker(market.VaultAddr, s.Env.Blockchain) + vaultTracker := &mocks.VaultTrackerSession{ + Contract: vaultTrackerContract, + CallOpts: bind.CallOpts{From: ownerOpts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: ownerOpts.From, + Signer: ownerOpts.Signer, + }, + } + + tx, err = vaultTracker.TransferNotionalFromReturns(false) + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + amount := big.NewInt(100) + tx, err = s.MarketPlace.P2pVaultExchange(underlying, maturity, ownerOpts.From, user1Opts.From, amount) + assert.NotNil(err) + assert.Regexp("transfer notional failed", err.Error()) + assert.Nil(tx) + + s.Env.Blockchain.Commit() +} + +func TestP2PVaultExchangeSuite(t *test.T) { + suite.Run(t, &p2pVaultExchangeSuite{}) +} diff --git a/gost/pkg/marketplacetesting/p2p_zc_token_exchange_test.go b/gost/pkg/marketplacetesting/p2p_zc_token_exchange_test.go new file mode 100644 index 0000000..609d24b --- /dev/null +++ b/gost/pkg/marketplacetesting/p2p_zc_token_exchange_test.go @@ -0,0 +1,147 @@ +package marketplacetesting + +import ( + "math/big" + test "testing" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + assertions "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" + "github.com/swivel-finance/gost/test/marketplace" + "github.com/swivel-finance/gost/test/mocks" +) + +type p2pZCTokenExchangeSuite struct { + suite.Suite + Env *Env + Dep *Dep + Erc20 *mocks.Erc20Session + CErc20 *mocks.CErc20Session + MarketPlace *marketplace.MarketPlaceSession // *Session objects are created by the go bindings +} + +func (s *p2pZCTokenExchangeSuite) SetupTest() { + var err error + + s.Env = NewEnv(big.NewInt(ONE_ETH)) // each of the wallets in the env will begin with this balance + s.Dep, err = Deploy(s.Env) + + if err != nil { + panic(err) + } + + err = s.Env.Blockchain.AdjustTime(0) // set bc timestamp to 0 + if err != nil { + panic(err) + } + + s.Env.Blockchain.Commit() + + s.Erc20 = &mocks.Erc20Session{ + Contract: s.Dep.Erc20, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } + + s.CErc20 = &mocks.CErc20Session{ + Contract: s.Dep.CErc20, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } + + // binding owner to both, kind of why it exists - but could be any of the env wallets + s.MarketPlace = &marketplace.MarketPlaceSession{ + Contract: s.Dep.MarketPlace, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } + + s.MarketPlace.SetSwivelAddress(s.Env.Owner.Opts.From) + s.Env.Blockchain.Commit() +} + +func (s *p2pZCTokenExchangeSuite) TestP2PZCTokenExchange() { + assert := assertions.New(s.T()) + underlying := s.Dep.Erc20Address + maturity := s.Dep.Maturity + ctoken := s.Dep.CErc20Address + + tx, err := s.MarketPlace.CreateMarket( + underlying, + maturity, + ctoken, + "awesome market", + "AM", + 18, + ) + + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + ownerOpts := s.Env.Owner.Opts + user1Opts := s.Env.User1.Opts + + // we should be able to fetch the market now... + market, err := s.MarketPlace.Markets(underlying, maturity) + assert.Nil(err) + assert.Equal(market.CTokenAddr, ctoken) + + s.Env.Blockchain.Commit() + + zcTokenContract, err := mocks.NewZcToken(market.ZcTokenAddr, s.Env.Blockchain) + zcToken := &mocks.ZcTokenSession{ + Contract: zcTokenContract, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } + + zcMaturity, err := zcToken.Maturity() + assert.Equal(maturity, zcMaturity) + + s.Env.Blockchain.Commit() + + tx, err = zcToken.BurnReturns(true) + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + tx, err = zcToken.MintReturns(true) + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + amount := big.NewInt(100) + tx, err = s.MarketPlace.P2pZcTokenExchange(underlying, maturity, ownerOpts.From, user1Opts.From, amount) + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + burnAmt, err := zcToken.BurnCalled(ownerOpts.From) + assert.Nil(err) + assert.Equal(amount, burnAmt) + + mintAmt, err := zcToken.MintCalled(user1Opts.From) + assert.Nil(err) + assert.Equal(amount, mintAmt) +} + +func TestP2PZCTokenExchangeSuite(t *test.T) { + suite.Run(t, &p2pZCTokenExchangeSuite{}) +} diff --git a/gost/pkg/marketplacetesting/redeem_vault_interest_test.go b/gost/pkg/marketplacetesting/redeem_vault_interest_test.go new file mode 100644 index 0000000..d13e2f6 --- /dev/null +++ b/gost/pkg/marketplacetesting/redeem_vault_interest_test.go @@ -0,0 +1,116 @@ +package marketplacetesting + +import ( + "math/big" + test "testing" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + assertions "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" + "github.com/swivel-finance/gost/test/marketplace" + "github.com/swivel-finance/gost/test/mocks" +) + +type redeemVaultInterestSuite struct { + suite.Suite + Env *Env + Dep *Dep + MarketPlace *marketplace.MarketPlaceSession // *Session objects are created by the go bindings +} + +func (s *redeemVaultInterestSuite) SetupTest() { + var err error + assert := assertions.New(s.T()) + + s.Env = NewEnv(big.NewInt(ONE_ETH)) // each of the wallets in the env will begin with this balance + s.Dep, err = Deploy(s.Env) + assert.Nil(err) + + err = s.Env.Blockchain.AdjustTime(0) // set bc timestamp to 0 + assert.Nil(err) + s.Env.Blockchain.Commit() + + s.MarketPlace = &marketplace.MarketPlaceSession{ + Contract: s.Dep.MarketPlace, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } + + // the swivel address must be set (set to owner accomodating the onlySwivel calls) + _, err = s.MarketPlace.SetSwivelAddress(s.Env.Owner.Opts.From) + assert.Nil(err) + s.Env.Blockchain.Commit() +} + +func (s *redeemVaultInterestSuite) TestRedeemVaultInterest() { + assert := assertions.New(s.T()) + maturity := s.Dep.Maturity + ctokenAddr := s.Dep.CErc20Address + + tx, err := s.MarketPlace.CreateMarket( + s.Dep.Erc20Address, + maturity, + ctokenAddr, + "awesome market", + "AM", + 18, + ) + + assert.Nil(err) + assert.NotNil(tx) + s.Env.Blockchain.Commit() + + // we should be able to fetch the market now... + market, err := s.MarketPlace.Markets(s.Dep.Erc20Address, maturity) + assert.Nil(err) + assert.Equal(market.CTokenAddr, ctokenAddr) + + zcTokenContract, err := mocks.NewZcToken(market.ZcTokenAddr, s.Env.Blockchain) + zcToken := &mocks.ZcTokenSession{ + Contract: zcTokenContract, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } + + zcMaturity, err := zcToken.Maturity() + assert.Equal(maturity, zcMaturity) + + vaultTrackerContract, err := mocks.NewVaultTracker(market.VaultAddr, s.Env.Blockchain) + vaultTracker := &mocks.VaultTrackerSession{ + Contract: vaultTrackerContract, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } + + vaultInterest := big.NewInt(123456789) + tx, err = vaultTracker.RedeemInterestReturns(vaultInterest) + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + tx, err = s.MarketPlace.RedeemVaultInterest(s.Dep.Erc20Address, maturity, s.Env.Owner.Opts.From) + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + // the vaulttracker mock should now retain the address it was passed + address, err := vaultTracker.RedeemInterestCalled() + assert.Nil(err) + assert.NotNil(address) + assert.Equal(address, s.Env.Owner.Opts.From) +} + +func TestRedeemVaultInterestSuite(t *test.T) { + suite.Run(t, &redeemVaultInterestSuite{}) +} diff --git a/gost/pkg/marketplacetesting/redeem_zc_token_test.go b/gost/pkg/marketplacetesting/redeem_zc_token_test.go new file mode 100644 index 0000000..df848ec --- /dev/null +++ b/gost/pkg/marketplacetesting/redeem_zc_token_test.go @@ -0,0 +1,453 @@ +package marketplacetesting + +import ( + "math/big" + test "testing" + "time" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + assertions "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" + "github.com/swivel-finance/gost/test/marketplace" + "github.com/swivel-finance/gost/test/mocks" +) + +type redeemZcTokenSuite struct { + suite.Suite + Env *Env + Dep *Dep + CErc20 *mocks.CErc20Session + MarketPlace *marketplace.MarketPlaceSession // *Session objects are created by the go bindings +} + +func (s *redeemZcTokenSuite) SetupTest() { + var err error + assert := assertions.New(s.T()) + + s.Env = NewEnv(big.NewInt(ONE_ETH)) // each of the wallets in the env will begin with this balance + s.Dep, err = Deploy(s.Env) + assert.Nil(err) + + err = s.Env.Blockchain.AdjustTime(0) // set bc timestamp to 0 + assert.Nil(err) + + s.Env.Blockchain.Commit() + + s.CErc20 = &mocks.CErc20Session{ + Contract: s.Dep.CErc20, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } + + // binding owner to both, kind of why it exists - but could be any of the env wallets + s.MarketPlace = &marketplace.MarketPlaceSession{ + Contract: s.Dep.MarketPlace, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } + + // the swivel address must be set, use owner to accomodate onlySwivel calls... + _, err = s.MarketPlace.SetSwivelAddress(s.Env.Owner.Opts.From) + assert.Nil(err) + s.Env.Blockchain.Commit() +} + +func (s *redeemZcTokenSuite) TestRedeemZcTokenMaturedRequirementFails() { + assert := assertions.New(s.T()) + underlying := s.Dep.Erc20Address + maturity := s.Dep.Maturity + ctoken := s.Dep.CErc20Address + + tx, err := s.MarketPlace.CreateMarket( + underlying, + maturity, + ctoken, + "awesome market", + "AM", + 18, + ) + + assert.Nil(err) + assert.NotNil(tx) + s.Env.Blockchain.Commit() + + // we should be able to fetch the market now... + market, err := s.MarketPlace.Markets(underlying, maturity) + assert.Nil(err) + assert.Equal(market.CTokenAddr, ctoken) + + zcTokenContract, err := mocks.NewZcToken(market.ZcTokenAddr, s.Env.Blockchain) + zcToken := &mocks.ZcTokenSession{ + Contract: zcTokenContract, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } + + zcMaturity, err := zcToken.Maturity() + assert.Equal(maturity, zcMaturity) + + vaultTrackerContract, err := mocks.NewVaultTracker(market.VaultAddr, s.Env.Blockchain) + vaultTracker := &mocks.VaultTrackerSession{ + Contract: vaultTrackerContract, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } + + tx, err = vaultTracker.MatureVaultReturns(true) + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + amount := big.NewInt(123456789) + tx, err = s.MarketPlace.RedeemZcToken(underlying, maturity, s.Env.Owner.Opts.From, amount) + assert.NotNil(err) + assert.Regexp("maturity not reached", err.Error()) + assert.Nil(tx) + + s.Env.Blockchain.Commit() +} + +func (s *redeemZcTokenSuite) TestRedeemZcTokenNotMatured() { + assert := assertions.New(s.T()) + underlying := s.Dep.Erc20Address + maturity := s.Dep.Maturity + ctoken := s.Dep.CErc20Address + + tx, err := s.MarketPlace.CreateMarket( + underlying, + maturity, + ctoken, + "awesome market", + "AM", + 18, + ) + + assert.Nil(err) + assert.NotNil(tx) + s.Env.Blockchain.Commit() + + // we should be able to fetch the market now... + market, err := s.MarketPlace.Markets(underlying, maturity) + assert.Nil(err) + assert.Equal(market.CTokenAddr, ctoken) + + zcTokenContract, err := mocks.NewZcToken(market.ZcTokenAddr, s.Env.Blockchain) + zcToken := &mocks.ZcTokenSession{ + Contract: zcTokenContract, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } + + zcMaturity, err := zcToken.Maturity() + assert.Equal(maturity, zcMaturity) + + tx, err = zcToken.BurnReturns(true) + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + vaultTrackerContract, err := mocks.NewVaultTracker(market.VaultAddr, s.Env.Blockchain) + vaultTracker := &mocks.VaultTrackerSession{ + Contract: vaultTrackerContract, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } + + tx, err = vaultTracker.MatureVaultReturns(true) + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + // move past the maturity + err = s.Env.Blockchain.AdjustTime(MATURITY * time.Second) + assert.Nil(err) + s.Env.Blockchain.Commit() + + amount := big.NewInt(123456789) + tx, err = s.MarketPlace.RedeemZcToken(underlying, maturity, s.Env.Owner.Opts.From, amount) + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + burnAmount, err := zcToken.BurnCalled(s.Env.Owner.Opts.From) + assert.Nil(err) + assert.Equal(amount, burnAmount) +} + +func (s *redeemZcTokenSuite) TestRedeemZcTokenNotMaturedBurnFails() { + assert := assertions.New(s.T()) + underlying := s.Dep.Erc20Address + maturity := s.Dep.Maturity + ctoken := s.Dep.CErc20Address + + tx, err := s.MarketPlace.CreateMarket( + underlying, + maturity, + ctoken, + "awesome market", + "AM", + 18, + ) + + assert.Nil(err) + assert.NotNil(tx) + s.Env.Blockchain.Commit() + + // we should be able to fetch the market now... + market, err := s.MarketPlace.Markets(underlying, maturity) + assert.Nil(err) + assert.Equal(market.CTokenAddr, ctoken) + + zcTokenContract, err := mocks.NewZcToken(market.ZcTokenAddr, s.Env.Blockchain) + zcToken := &mocks.ZcTokenSession{ + Contract: zcTokenContract, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } + + zcMaturity, err := zcToken.Maturity() + assert.Equal(maturity, zcMaturity) + + tx, err = zcToken.BurnReturns(false) + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + vaultTrackerContract, err := mocks.NewVaultTracker(market.VaultAddr, s.Env.Blockchain) + vaultTracker := &mocks.VaultTrackerSession{ + Contract: vaultTrackerContract, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } + + tx, err = vaultTracker.MatureVaultReturns(true) + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + // move past the maturity + err = s.Env.Blockchain.AdjustTime(MATURITY * time.Second) + assert.Nil(err) + s.Env.Blockchain.Commit() + + amount := big.NewInt(123456789) + tx, err = s.MarketPlace.RedeemZcToken(underlying, maturity, s.Env.Owner.Opts.From, amount) + assert.NotNil(err) + assert.Regexp("could not burn", err.Error()) + assert.Nil(tx) + + s.Env.Blockchain.Commit() +} + +func (s *redeemZcTokenSuite) TestRedeemZcTokenMatured() { + assert := assertions.New(s.T()) + underlying := s.Dep.Erc20Address + maturity := s.Dep.Maturity + ctoken := s.Dep.CErc20Address + + tx, err := s.MarketPlace.CreateMarket( + underlying, + maturity, + ctoken, + "awesome market", + "AM", + 18, + ) + + assert.Nil(err) + assert.NotNil(tx) + s.Env.Blockchain.Commit() + + // we should be able to fetch the market now... + market, err := s.MarketPlace.Markets(underlying, maturity) + assert.Nil(err) + assert.Equal(market.CTokenAddr, ctoken) + + zcTokenContract, err := mocks.NewZcToken(market.ZcTokenAddr, s.Env.Blockchain) + zcToken := &mocks.ZcTokenSession{ + Contract: zcTokenContract, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } + + zcMaturity, err := zcToken.Maturity() + assert.Equal(maturity, zcMaturity) + + tx, err = zcToken.BurnReturns(true) + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + vaultTrackerContract, err := mocks.NewVaultTracker(market.VaultAddr, s.Env.Blockchain) + vaultTracker := &mocks.VaultTrackerSession{ + Contract: vaultTrackerContract, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } + + tx, err = vaultTracker.MatureVaultReturns(true) + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + // move past the maturity + err = s.Env.Blockchain.AdjustTime(MATURITY * time.Second) + assert.Nil(err) + + s.Env.Blockchain.Commit() + + rate := big.NewInt(223456789) + tx, err = s.CErc20.ExchangeRateCurrentReturns(rate) + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + tx, err = s.MarketPlace.MatureMarket(underlying, maturity) + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + amount := big.NewInt(123456789) + tx, err = s.MarketPlace.RedeemZcToken(underlying, maturity, s.Env.Owner.Opts.From, amount) + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + burnAmount, err := zcToken.BurnCalled(s.Env.Owner.Opts.From) + assert.Nil(err) + assert.Equal(amount, burnAmount) + + s.Env.Blockchain.Commit() +} + +func (s *redeemZcTokenSuite) TestRedeemZcTokenMaturedBurnFails() { + assert := assertions.New(s.T()) + underlying := s.Dep.Erc20Address + maturity := s.Dep.Maturity + ctoken := s.Dep.CErc20Address + + tx, err := s.MarketPlace.CreateMarket( + underlying, + maturity, + ctoken, + "awesome market", + "AM", + 18, + ) + + assert.Nil(err) + assert.NotNil(tx) + s.Env.Blockchain.Commit() + + // we should be able to fetch the market now... + market, err := s.MarketPlace.Markets(underlying, maturity) + assert.Nil(err) + assert.Equal(market.CTokenAddr, ctoken) + + zcTokenContract, err := mocks.NewZcToken(market.ZcTokenAddr, s.Env.Blockchain) + zcToken := &mocks.ZcTokenSession{ + Contract: zcTokenContract, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } + + zcMaturity, err := zcToken.Maturity() + assert.Equal(maturity, zcMaturity) + + tx, err = zcToken.BurnReturns(false) + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + vaultTrackerContract, err := mocks.NewVaultTracker(market.VaultAddr, s.Env.Blockchain) + vaultTracker := &mocks.VaultTrackerSession{ + Contract: vaultTrackerContract, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } + + tx, err = vaultTracker.MatureVaultReturns(true) + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + // move past the maturity + err = s.Env.Blockchain.AdjustTime(MATURITY * time.Second) + assert.Nil(err) + + s.Env.Blockchain.Commit() + + rate := big.NewInt(223456789) + tx, err = s.CErc20.ExchangeRateCurrentReturns(rate) + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + tx, err = s.MarketPlace.MatureMarket(underlying, maturity) + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + amount := big.NewInt(123456789) + tx, err = s.MarketPlace.RedeemZcToken(underlying, maturity, s.Env.Owner.Opts.From, amount) + assert.NotNil(err) + assert.Regexp("could not burn", err.Error()) + assert.Nil(tx) + + s.Env.Blockchain.Commit() +} + +func TestRedeemZcTokenSuite(t *test.T) { + suite.Run(t, &redeemZcTokenSuite{}) +} diff --git a/gost/pkg/marketplacetesting/set_swivel_address_test.go b/gost/pkg/marketplacetesting/set_swivel_address_test.go new file mode 100644 index 0000000..e280205 --- /dev/null +++ b/gost/pkg/marketplacetesting/set_swivel_address_test.go @@ -0,0 +1,56 @@ +package marketplacetesting + +import ( + "math/big" + test "testing" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" + "github.com/swivel-finance/gost/test/marketplace" +) + +type swivelAddrSuite struct { + suite.Suite + Env *Env + Dep *Dep + MarketPlace *marketplace.MarketPlaceSession // *Session objects are created by the go bindings +} + +func (s *swivelAddrSuite) SetupSuite() { + var err error + + s.Env = NewEnv(big.NewInt(ONE_ETH)) // each of the wallets in the env will begin with this balance + s.Dep, err = Deploy(s.Env) + + if err != nil { + panic(err) + } + + s.MarketPlace = &marketplace.MarketPlaceSession{ + Contract: s.Dep.MarketPlace, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } +} + +func (s *swivelAddrSuite) TestSetSwivelAddr() { + assert := assert.New(s.T()) + bsAddr := common.HexToAddress("0x123456789") + tx, err := s.MarketPlace.SetSwivelAddress(bsAddr) + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + addr, _ := s.MarketPlace.Swivel() + assert.Equal(bsAddr, addr) +} + +func TestSwivelAddrSuite(t *test.T) { + suite.Run(t, &swivelAddrSuite{}) +} diff --git a/gost/pkg/marketplacetesting/transfer_vault_notional_fee_test.go b/gost/pkg/marketplacetesting/transfer_vault_notional_fee_test.go new file mode 100644 index 0000000..9c6d2b9 --- /dev/null +++ b/gost/pkg/marketplacetesting/transfer_vault_notional_fee_test.go @@ -0,0 +1,106 @@ +package marketplacetesting + +import ( + "math/big" + test "testing" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + assertions "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" + "github.com/swivel-finance/gost/test/marketplace" + "github.com/swivel-finance/gost/test/mocks" +) + +type vaultTransferFeeSuite struct { + suite.Suite + Env *Env + Dep *Dep + MarketPlace *marketplace.MarketPlaceSession +} + +func (s *vaultTransferFeeSuite) SetupTest() { + var err error + assert := assertions.New(s.T()) + + s.Env = NewEnv(big.NewInt(ONE_ETH)) // each of the wallets in the env will begin with this balance + s.Dep, err = Deploy(s.Env) + assert.Nil(err) + + s.MarketPlace = &marketplace.MarketPlaceSession{ + Contract: s.Dep.MarketPlace, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } + + // the swivel address must be set, using owner here for ease of mocking + _, err = s.MarketPlace.SetSwivelAddress(s.Env.Owner.Opts.From) + assert.Nil(err) + s.Env.Blockchain.Commit() +} + +func (s *vaultTransferFeeSuite) TestVaultTransferFee() { + assert := assertions.New(s.T()) + + ownerOpts := s.Env.Owner.Opts + user1Opts := s.Env.User1.Opts + + // make a market so that a vault is deployed + underlying := common.HexToAddress("0x234567891") + maturity := big.NewInt(1234567) + ctoken := common.HexToAddress("0x456xyz") + + tx, err := s.MarketPlace.CreateMarket( + underlying, + maturity, + ctoken, + "awesome market", + "AM", + 18, + ) + + assert.Nil(err) + assert.NotNil(tx) + s.Env.Blockchain.Commit() + + // find that vault, wrap it in a mock... + market, err := s.MarketPlace.Markets(underlying, maturity) + assert.Nil(err) + assert.Equal(market.CTokenAddr, ctoken) + + vaultTrackerContract, err := mocks.NewVaultTracker(market.VaultAddr, s.Env.Blockchain) + vaultTracker := &mocks.VaultTrackerSession{ + Contract: vaultTrackerContract, + CallOpts: bind.CallOpts{From: ownerOpts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: ownerOpts.From, + Signer: ownerOpts.Signer, + }, + } + + // stub the mock vaulttracker... + tx, err = vaultTracker.TransferNotionalFeeReturns(true) + assert.Nil(err) + assert.NotNil(tx) + s.Env.Blockchain.Commit() + + amount := big.NewInt(100) + + tx, err = s.MarketPlace.TransferVaultNotionalFee(underlying, maturity, user1Opts.From, amount) + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + // marketplace should simply have passed the args thru... + transferFee, err := vaultTracker.TransferNotionalFeeCalled(user1Opts.From) + assert.Nil(err) + assert.Equal(big.NewInt(100), transferFee) +} + +func TestVaultTransferFeeSuite(t *test.T) { + suite.Run(t, &vaultTransferFeeSuite{}) +} diff --git a/gost/pkg/marketplacetesting/transfer_vault_notional_test.go b/gost/pkg/marketplacetesting/transfer_vault_notional_test.go new file mode 100644 index 0000000..e7fa5da --- /dev/null +++ b/gost/pkg/marketplacetesting/transfer_vault_notional_test.go @@ -0,0 +1,107 @@ +package marketplacetesting + +import ( + "math/big" + test "testing" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + assertions "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" + "github.com/swivel-finance/gost/test/marketplace" + "github.com/swivel-finance/gost/test/mocks" +) + +type vaultTransferSuite struct { + suite.Suite + Env *Env + Dep *Dep + MarketPlace *marketplace.MarketPlaceSession // *Session objects are created by the go bindings +} + +func (s *vaultTransferSuite) SetupTest() { + var err error + assert := assertions.New(s.T()) + + s.Env = NewEnv(big.NewInt(ONE_ETH)) // each of the wallets in the env will begin with this balance + s.Dep, err = Deploy(s.Env) + assert.Nil(err) + + s.MarketPlace = &marketplace.MarketPlaceSession{ + Contract: s.Dep.MarketPlace, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } + + // the swivel address must be set + _, err = s.MarketPlace.SetSwivelAddress(s.Dep.SwivelAddress) + assert.Nil(err) + s.Env.Blockchain.Commit() +} + +func (s *vaultTransferSuite) TestVaultTransfer() { + assert := assertions.New(s.T()) + + ownerOpts := s.Env.Owner.Opts + user1Opts := s.Env.User1.Opts + + // make a market so that a vault is deployed + underlying := common.HexToAddress("0x234567891") + maturity := big.NewInt(1234567) + ctoken := common.HexToAddress("0x456") + + tx, err := s.MarketPlace.CreateMarket( + underlying, + maturity, + ctoken, + "awesome market", + "AM", + 18, + ) + + assert.Nil(err) + assert.NotNil(tx) + s.Env.Blockchain.Commit() + + // find that vault, wrap it in a mock... + market, err := s.MarketPlace.Markets(underlying, maturity) + assert.Nil(err) + assert.Equal(market.CTokenAddr, ctoken) + + vaultTrackerContract, err := mocks.NewVaultTracker(market.VaultAddr, s.Env.Blockchain) + vaultTracker := &mocks.VaultTrackerSession{ + Contract: vaultTrackerContract, + CallOpts: bind.CallOpts{From: ownerOpts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: ownerOpts.From, + Signer: ownerOpts.Signer, + }, + } + + // stub the mock vaulttracker... + tx, err = vaultTracker.TransferNotionalFromReturns(true) + assert.Nil(err) + assert.NotNil(tx) + s.Env.Blockchain.Commit() + + amount := big.NewInt(100) + + tx, err = s.MarketPlace.TransferVaultNotional(underlying, maturity, user1Opts.From, amount) + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + // marketplace should have called transfer with the msg.sender as owner + transferArgs, err := vaultTracker.TransferNotionalFromCalled(ownerOpts.From) + assert.Nil(err) + assert.Equal(user1Opts.From, transferArgs.To) + assert.Equal(amount, transferArgs.Amount) +} + +func TestVaultTransferSuite(t *test.T) { + suite.Run(t, &vaultTransferSuite{}) +} diff --git a/gost/pkg/swiveltesting/constants.go b/gost/pkg/swiveltesting/constants.go new file mode 100644 index 0000000..a3b900d --- /dev/null +++ b/gost/pkg/swiveltesting/constants.go @@ -0,0 +1,12 @@ +package swiveltesting + +import "math/big" + +const ONE_ETH = 1000000000000000000 +const ONE_GWEI = 1000000000 +const ONE_WEI = 1 + +var ZERO = big.NewInt(0) + +// MATURITY is one day, in seconds +const MATURITY = 86400 diff --git a/gost/pkg/swiveltesting/dep.go b/gost/pkg/swiveltesting/dep.go new file mode 100644 index 0000000..b6a37cc --- /dev/null +++ b/gost/pkg/swiveltesting/dep.go @@ -0,0 +1,99 @@ +package swiveltesting + +import ( + "math/big" + + "github.com/ethereum/go-ethereum/common" + "github.com/swivel-finance/gost/test/fakes" + "github.com/swivel-finance/gost/test/mocks" + "github.com/swivel-finance/gost/test/swivel" +) + +// TODO mock for marketplace... +type Dep struct { + SigFakeAddress common.Address + SigFake *fakes.SigFake // fake sig lib test contract + HashFakeAddress common.Address + HashFake *fakes.HashFake // fake hash lib test contract + Erc20Address common.Address + Erc20 *mocks.Erc20 // mock erc20 + CErc20Address common.Address + CErc20 *mocks.CErc20 // mock erc20 + MarketPlaceAddress common.Address + MarketPlace *mocks.MarketPlace // mock marketplace + Maturity *big.Int + SwivelAddress common.Address + Swivel *swivel.Swivel +} + +func Deploy(e *Env) (*Dep, error) { + maturity := big.NewInt(MATURITY) + // deploy the fakes so we can access the libs from tests + sigAddress, _, sigContract, sigErr := fakes.DeploySigFake(e.Owner.Opts, e.Blockchain) + + if sigErr != nil { + return nil, sigErr + } + + e.Blockchain.Commit() + + hashAddress, _, hashContract, hashErr := fakes.DeployHashFake(e.Owner.Opts, e.Blockchain) + + if hashErr != nil { + return nil, hashErr + } + + e.Blockchain.Commit() + + // deploy the two mock tokens. + ercAddress, _, ercContract, ercErr := mocks.DeployErc20(e.Owner.Opts, e.Blockchain) + + if ercErr != nil { + return nil, ercErr + } + + e.Blockchain.Commit() + + cercAddress, _, cercContract, cercErr := mocks.DeployCErc20(e.Owner.Opts, e.Blockchain) + + if cercErr != nil { + return nil, cercErr + } + + e.Blockchain.Commit() + + marketAddress, _, marketContract, marketErr := mocks.DeployMarketPlace(e.Owner.Opts, e.Blockchain) + + if marketErr != nil { + return nil, marketErr + } + + e.Blockchain.Commit() + + // deploy swivel contract... + swivelAddress, _, swivelContract, swivelErr := swivel.DeploySwivel(e.Owner.Opts, e.Blockchain, marketAddress) + + // TODO call marketPlace swivel contract address setter when implemented... + + if swivelErr != nil { + return nil, swivelErr + } + + e.Blockchain.Commit() + + return &Dep{ + SigFakeAddress: sigAddress, + SigFake: sigContract, + HashFakeAddress: hashAddress, + HashFake: hashContract, + Erc20Address: ercAddress, + Erc20: ercContract, + CErc20Address: cercAddress, + CErc20: cercContract, + MarketPlaceAddress: marketAddress, + MarketPlace: marketContract, + Maturity: maturity, + SwivelAddress: swivelAddress, + Swivel: swivelContract, + }, nil +} diff --git a/gost/pkg/swiveltesting/env.go b/gost/pkg/swiveltesting/env.go new file mode 100644 index 0000000..4fa7458 --- /dev/null +++ b/gost/pkg/swiveltesting/env.go @@ -0,0 +1,52 @@ +package swiveltesting + +import ( + "crypto/ecdsa" + "math/big" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/accounts/abi/bind/backends" + "github.com/ethereum/go-ethereum/core" + "github.com/swivel-finance/gost/internal/helpers" +) + +// Auth is a custom type which allows us easy access to the dynamically generated +// ecdsa.PrivateKey along with the bind.TransactOpts +type Auth struct { + PK *ecdsa.PrivateKey + Opts *bind.TransactOpts +} + +// Env, holds Auth objects capable of signing transactions. +// Also holds the Geth simulated backend. +type Env struct { + Alloc core.GenesisAlloc + // TODO maybe change to Admin to fit v2 contract terms... + Owner *Auth + User1 *Auth + User2 *Auth + Blockchain *backends.SimulatedBackend +} + +// NewEnv returns a hydrated Env struct, ready for use. +// Given a balance argument, it assigns this as the wallet balance for +// each authorization object in the Ctx +func NewEnv(b *big.Int) *Env { + pk, owner := helpers.NewAuth() + pk1, u1 := helpers.NewAuth() + pk2, u2 := helpers.NewAuth() + alloc := make(core.GenesisAlloc) + alloc[owner.From] = core.GenesisAccount{Balance: b} + alloc[u1.From] = core.GenesisAccount{Balance: b} + alloc[u2.From] = core.GenesisAccount{Balance: b} + // 2nd arg is a gas limit, a uint64. we'll use... + bc := backends.NewSimulatedBackend(alloc, 5700000) + + return &Env{ + Alloc: alloc, + Owner: &Auth{PK: pk, Opts: owner}, + User1: &Auth{PK: pk1, Opts: u1}, + User2: &Auth{PK: pk2, Opts: u2}, + Blockchain: bc, + } +} diff --git a/gost/pkg/swiveltesting/exit_vault_filling_vault_initiate_test.go b/gost/pkg/swiveltesting/exit_vault_filling_vault_initiate_test.go new file mode 100644 index 0000000..8c5a343 --- /dev/null +++ b/gost/pkg/swiveltesting/exit_vault_filling_vault_initiate_test.go @@ -0,0 +1,194 @@ +package swiveltesting + +import ( + "math/big" + test "testing" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/crypto" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" + "github.com/swivel-finance/gost/internal/helpers" + "github.com/swivel-finance/gost/test/fakes" + "github.com/swivel-finance/gost/test/mocks" + "github.com/swivel-finance/gost/test/swivel" +) + +// yeah, just make it an acronym... +type EVFVISuite struct { + suite.Suite + Env *Env + Dep *Dep + Erc20 *mocks.Erc20Session + MarketPlace *mocks.MarketPlaceSession + Swivel *swivel.SwivelSession +} + +func (s *EVFVISuite) SetupTest() { + var err error + + s.Env = NewEnv(big.NewInt(ONE_ETH)) + s.Dep, err = Deploy(s.Env) + + if err != nil { + panic(err) + } + + s.Erc20 = &mocks.Erc20Session{ + Contract: s.Dep.Erc20, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } + + s.MarketPlace = &mocks.MarketPlaceSession{ + Contract: s.Dep.MarketPlace, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } + + // binding owner to both, kind of why it exists - but could be any of the env wallets + s.Swivel = &swivel.SwivelSession{ + Contract: s.Dep.Swivel, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } +} + +func (s *EVFVISuite) TestEVFVI() { + assert := assert.New(s.T()) + + // stub underlying (erc20) transferfrom to return true + tx, err := s.Erc20.TransferFromReturns(true) + assert.Nil(err) + assert.NotNil(tx) + s.Env.Blockchain.Commit() + + // and the marketplace api methods... + tx, err = s.MarketPlace.P2pVaultExchangeReturns(true) + assert.Nil(err) + assert.NotNil(tx) + s.Env.Blockchain.Commit() + + // hashed order... + orderKey := helpers.GenBytes32("order") + principal := big.NewInt(5000) + principal = principal.Mul(principal, big.NewInt(1e18)) + premium := big.NewInt(50) + premium = premium.Mul(premium, big.NewInt(1e18)) + maturity := big.NewInt(10000) + expiry := big.NewInt(20000) + + // TODO preparing an order _may_ be relocated to a helper. Possibly per package? Discuss... + hashOrder := fakes.HashOrder{ + Key: orderKey, + Maker: s.Env.User1.Opts.From, + Underlying: s.Dep.Erc20Address, + Vault: true, + Exit: false, + Principal: principal, + Premium: premium, + Maturity: maturity, + Expiry: expiry, + } + + // signature... + orderHash, err := s.Dep.HashFake.OrderTest(nil, hashOrder) + assert.Nil(err) + assert.NotNil(orderHash) + + // put the hashed order together with the eip712 domain and hash those + separator, _ := s.Swivel.Domain() + messageHash, err := s.Dep.HashFake.MessageTest(nil, separator, orderHash) + assert.Nil(err) + assert.NotNil(messageHash) + + // sign it with User1 private key + sig, err := crypto.Sign(messageHash[:], s.Env.User1.PK) + assert.Nil(err) + assert.NotNil(sig) + + // get the sig components + vrs, err := s.Dep.SigFake.SplitTest(nil, sig) + assert.Nil(err) + assert.NotNil(vrs) + + // see sig_test.go + if vrs.V < 27 { + vrs.V += 27 + } + + // the order passed to the swivel contract must be of the swivel package type... + order := swivel.HashOrder{ + Key: orderKey, + Maker: s.Env.User1.Opts.From, + Underlying: s.Dep.Erc20Address, + Vault: true, + Exit: false, + Principal: principal, + Premium: premium, + Maturity: maturity, + Expiry: expiry, + } + + // like order the signature components must ref swivel + components := swivel.SigComponents{ + V: vrs.V, + R: vrs.R, + S: vrs.S, + } + + // call it (finally)... + amount := big.NewInt(2500) // 1/2 the principal + amount = amount.Mul(amount, big.NewInt(1e18)) + // initiate wants slices... + orders := []swivel.HashOrder{order} + amounts := []*big.Int{amount} + componentses := []swivel.SigComponents{components} // yeah, i liek it... + + // vault true && exit false will force the call to EVFVI + tx, err = s.Swivel.Exit(orders, amounts, componentses) + + assert.Nil(err) + assert.NotNil(tx) + s.Env.Blockchain.Commit() + + // we should have a filled amount for orderKey + amt, err := s.Swivel.Filled(orderHash) + assert.Equal(amt, amount) + + // first call to utoken transferfrom 'from' should be maker here... + args, err := s.Erc20.TransferFromCalled(order.Maker) + assert.Nil(err) + assert.NotNil(args) + assert.Equal(args.To, s.Env.Owner.Opts.From) + assert.Equal(amt.Cmp(args.Amount), 1) // amt should be greater than computed pFilled + + // 2nd call from is sender (owner) + args2, err := s.Erc20.TransferFromCalled(s.Env.Owner.Opts.From) + assert.Nil(err) + assert.NotNil(args2) + assert.Equal(args2.To, s.Dep.SwivelAddress) // should go to swivel + assert.Equal(args2.Amount.Cmp(big.NewInt(0)), 1) // fee should be non zero + + // market zctoken transfer from call... + noTransferArgs, err := s.MarketPlace.P2pVaultExchangeCalled(order.Underlying) + assert.Nil(err) + assert.NotNil(noTransferArgs) + assert.Equal(noTransferArgs.Maturity, order.Maturity) + assert.Equal(amt.Cmp(noTransferArgs.Amount), 0) // .Amount is passed in amt + assert.Equal(noTransferArgs.Two, order.Maker) + assert.Equal(noTransferArgs.One, s.Env.Owner.Opts.From) +} + +func TestEVFVISuite(t *test.T) { + suite.Run(t, &EVFVISuite{}) +} diff --git a/gost/pkg/swiveltesting/exit_vault_filling_zctoken_exit_test.go b/gost/pkg/swiveltesting/exit_vault_filling_zctoken_exit_test.go new file mode 100644 index 0000000..13b79c0 --- /dev/null +++ b/gost/pkg/swiveltesting/exit_vault_filling_zctoken_exit_test.go @@ -0,0 +1,218 @@ +package swiveltesting + +import ( + "math/big" + test "testing" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/crypto" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" + "github.com/swivel-finance/gost/internal/helpers" + "github.com/swivel-finance/gost/test/fakes" + "github.com/swivel-finance/gost/test/mocks" + "github.com/swivel-finance/gost/test/swivel" +) + +// yeah, just make it an acronym... +type EVFZESuite struct { + suite.Suite + Env *Env + Dep *Dep + Erc20 *mocks.Erc20Session + CErc20 *mocks.CErc20Session + MarketPlace *mocks.MarketPlaceSession + Swivel *swivel.SwivelSession +} + +func (s *EVFZESuite) SetupTest() { + var err error + + s.Env = NewEnv(big.NewInt(ONE_ETH)) + s.Dep, err = Deploy(s.Env) + + if err != nil { + panic(err) + } + + s.Erc20 = &mocks.Erc20Session{ + Contract: s.Dep.Erc20, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } + + s.CErc20 = &mocks.CErc20Session{ + Contract: s.Dep.CErc20, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } + + s.MarketPlace = &mocks.MarketPlaceSession{ + Contract: s.Dep.MarketPlace, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } + + // binding owner to both, kind of why it exists - but could be any of the env wallets + s.Swivel = &swivel.SwivelSession{ + Contract: s.Dep.Swivel, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } +} + +func (s *EVFZESuite) TestEVFZE() { + assert := assert.New(s.T()) + + // stub underlying (erc20) transfer and transferfrom to return true + tx, err := s.Erc20.TransferReturns(true) + assert.Nil(err) + assert.NotNil(tx) + s.Env.Blockchain.Commit() + + tx, err = s.Erc20.TransferFromReturns(true) + assert.Nil(err) + assert.NotNil(tx) + s.Env.Blockchain.Commit() + + // and the ctoken redeem... + tx, err = s.CErc20.RedeemUnderlyingReturns(big.NewInt(0)) + assert.NotNil(tx) + assert.Nil(err) + s.Env.Blockchain.Commit() + + // and the marketplace api methods... + tx, err = s.MarketPlace.CTokenAddressReturns(s.Dep.CErc20Address) // must use the actual dep addr here + assert.Nil(err) + assert.NotNil(tx) + s.Env.Blockchain.Commit() + + tx, err = s.MarketPlace.CustodialExitReturns(true) + assert.Nil(err) + assert.NotNil(tx) + s.Env.Blockchain.Commit() + + // hashed order... + orderKey := helpers.GenBytes32("order") + principal := big.NewInt(5000) + principal = principal.Mul(principal, big.NewInt(1e18)) + premium := big.NewInt(50) + premium = premium.Mul(premium, big.NewInt(1e18)) + maturity := big.NewInt(10000) + expiry := big.NewInt(20000) + + // TODO preparing an order _may_ be relocated to a helper. Possibly per package? Discuss... + hashOrder := fakes.HashOrder{ + Key: orderKey, + Maker: s.Env.User1.Opts.From, + Underlying: s.Dep.Erc20Address, + Vault: false, + Exit: true, + Principal: principal, + Premium: premium, + Maturity: maturity, + Expiry: expiry, + } + + // signature... + orderHash, err := s.Dep.HashFake.OrderTest(nil, hashOrder) + assert.Nil(err) + assert.NotNil(orderHash) + + // put the hashed order together with the eip712 domain and hash those + separator, _ := s.Swivel.Domain() + messageHash, err := s.Dep.HashFake.MessageTest(nil, separator, orderHash) + assert.Nil(err) + assert.NotNil(messageHash) + + // sign it with User1 private key + sig, err := crypto.Sign(messageHash[:], s.Env.User1.PK) + assert.Nil(err) + assert.NotNil(sig) + + // get the sig components + vrs, err := s.Dep.SigFake.SplitTest(nil, sig) + assert.Nil(err) + assert.NotNil(vrs) + + // see sig_test.go + if vrs.V < 27 { + vrs.V += 27 + } + + // the order passed to the swivel contract must be of the swivel package type... + order := swivel.HashOrder{ + Key: orderKey, + Maker: s.Env.User1.Opts.From, + Underlying: s.Dep.Erc20Address, + Vault: false, + Exit: true, + Principal: principal, + Premium: premium, + Maturity: maturity, + Expiry: expiry, + } + + // like order the signature components must ref swivel + components := swivel.SigComponents{ + V: vrs.V, + R: vrs.R, + S: vrs.S, + } + + // call it (finally)... + amount := big.NewInt(2500) // 1/2 the principal + amount = amount.Mul(amount, big.NewInt(1e18)) + // initiate wants slices... + orders := []swivel.HashOrder{order} + amounts := []*big.Int{amount} + componentses := []swivel.SigComponents{components} // yeah, i liek it... + + // vault false && exit true will force the call to EVFZE + tx, err = s.Swivel.Exit(orders, amounts, componentses) + + assert.Nil(err) + assert.NotNil(tx) + s.Env.Blockchain.Commit() + + // we should have a filled amount for orderKey + amt, err := s.Swivel.Filled(orderHash) + assert.Equal(amt, amount) + + // first call to utoken transfer... (maker) + amt1, err := s.Erc20.TransferCalled(order.Maker) + assert.Nil(err) + assert.NotNil(amt1) + assert.Equal(amount.Cmp(amt1), 1) // should be less than amount + + // 2nd call to utoken transfer...(sender) + amt2, err := s.Erc20.TransferCalled(s.Env.Owner.Opts.From) + assert.Nil(err) + assert.NotNil(amt1) + assert.Equal(amt2.Cmp(big.NewInt(0)), 1) // should be non zero + + // market zctoken burn... + burnArgs, err := s.MarketPlace.CustodialExitCalled(order.Underlying) + assert.Nil(err) + assert.NotNil(burnArgs) + assert.Equal(burnArgs.Maturity, order.Maturity) + assert.Equal(amt.Cmp(burnArgs.Amount), 0) // .Amount is passed in amt + assert.Equal(burnArgs.One, order.Maker) + assert.Equal(burnArgs.Two, s.Env.Owner.Opts.From) +} + +func TestEVFZESuite(t *test.T) { + suite.Run(t, &EVFZESuite{}) +} diff --git a/gost/pkg/swiveltesting/exit_zctoken_filling_vault_exit_test.go b/gost/pkg/swiveltesting/exit_zctoken_filling_vault_exit_test.go new file mode 100644 index 0000000..61ece49 --- /dev/null +++ b/gost/pkg/swiveltesting/exit_zctoken_filling_vault_exit_test.go @@ -0,0 +1,218 @@ +package swiveltesting + +import ( + "math/big" + test "testing" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/crypto" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" + "github.com/swivel-finance/gost/internal/helpers" + "github.com/swivel-finance/gost/test/fakes" + "github.com/swivel-finance/gost/test/mocks" + "github.com/swivel-finance/gost/test/swivel" +) + +// yeah, just make it an acronym... +type EZFVESuite struct { + suite.Suite + Env *Env + Dep *Dep + Erc20 *mocks.Erc20Session + CErc20 *mocks.CErc20Session + MarketPlace *mocks.MarketPlaceSession + Swivel *swivel.SwivelSession +} + +func (s *EZFVESuite) SetupTest() { + var err error + + s.Env = NewEnv(big.NewInt(ONE_ETH)) + s.Dep, err = Deploy(s.Env) + + if err != nil { + panic(err) + } + + s.Erc20 = &mocks.Erc20Session{ + Contract: s.Dep.Erc20, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } + + s.CErc20 = &mocks.CErc20Session{ + Contract: s.Dep.CErc20, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } + + s.MarketPlace = &mocks.MarketPlaceSession{ + Contract: s.Dep.MarketPlace, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } + + // binding owner to both, kind of why it exists - but could be any of the env wallets + s.Swivel = &swivel.SwivelSession{ + Contract: s.Dep.Swivel, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } +} + +func (s *EZFVESuite) TestEZFVE() { + assert := assert.New(s.T()) + + // stub underlying (erc20) transfer and transferfrom to return true + tx, err := s.Erc20.TransferReturns(true) + assert.Nil(err) + assert.NotNil(tx) + s.Env.Blockchain.Commit() + + tx, err = s.Erc20.TransferFromReturns(true) + assert.Nil(err) + assert.NotNil(tx) + s.Env.Blockchain.Commit() + + // and the ctoken redeem... + tx, err = s.CErc20.RedeemUnderlyingReturns(big.NewInt(0)) + assert.NotNil(tx) + assert.Nil(err) + s.Env.Blockchain.Commit() + + // and the marketplace api methods... + tx, err = s.MarketPlace.CTokenAddressReturns(s.Dep.CErc20Address) // must use the actual dep addr here + assert.Nil(err) + assert.NotNil(tx) + s.Env.Blockchain.Commit() + + tx, err = s.MarketPlace.CustodialExitReturns(true) + assert.Nil(err) + assert.NotNil(tx) + s.Env.Blockchain.Commit() + + // hashed order... + orderKey := helpers.GenBytes32("order") + principal := big.NewInt(5000) + principal = principal.Mul(principal, big.NewInt(1e18)) + premium := big.NewInt(50) + premium = premium.Mul(premium, big.NewInt(1e18)) + maturity := big.NewInt(10000) + expiry := big.NewInt(20000) + + // TODO preparing an order _may_ be relocated to a helper. Possibly per package? Discuss... + hashOrder := fakes.HashOrder{ + Key: orderKey, + Maker: s.Env.User1.Opts.From, + Underlying: s.Dep.Erc20Address, + Vault: true, + Exit: true, + Principal: principal, + Premium: premium, + Maturity: maturity, + Expiry: expiry, + } + + // signature... + orderHash, err := s.Dep.HashFake.OrderTest(nil, hashOrder) + assert.Nil(err) + assert.NotNil(orderHash) + + // put the hashed order together with the eip712 domain and hash those + separator, _ := s.Swivel.Domain() + messageHash, err := s.Dep.HashFake.MessageTest(nil, separator, orderHash) + assert.Nil(err) + assert.NotNil(messageHash) + + // sign it with User1 private key + sig, err := crypto.Sign(messageHash[:], s.Env.User1.PK) + assert.Nil(err) + assert.NotNil(sig) + + // get the sig components + vrs, err := s.Dep.SigFake.SplitTest(nil, sig) + assert.Nil(err) + assert.NotNil(vrs) + + // see sig_test.go + if vrs.V < 27 { + vrs.V += 27 + } + + // the order passed to the swivel contract must be of the swivel package type... + order := swivel.HashOrder{ + Key: orderKey, + Maker: s.Env.User1.Opts.From, + Underlying: s.Dep.Erc20Address, + Vault: true, + Exit: true, + Principal: principal, + Premium: premium, + Maturity: maturity, + Expiry: expiry, + } + + // like order the signature components must ref swivel + components := swivel.SigComponents{ + V: vrs.V, + R: vrs.R, + S: vrs.S, + } + + // call it (finally)... + amount := big.NewInt(25) // l/2 the premium + amount = amount.Mul(amount, big.NewInt(1e18)) + // initiate wants slices... + orders := []swivel.HashOrder{order} + amounts := []*big.Int{amount} + componentses := []swivel.SigComponents{components} // yeah, i liek it... + + // vault false && exit true will force the call to EZFVE + tx, err = s.Swivel.Exit(orders, amounts, componentses) + + assert.Nil(err) + assert.NotNil(tx) + s.Env.Blockchain.Commit() + + // we should have a filled amount for orderKey + amt, err := s.Swivel.Filled(orderHash) + assert.Equal(amt, amount) + + // first call to utoken transfer..(sender) + amt1, err := s.Erc20.TransferCalled(s.Env.Owner.Opts.From) + assert.Nil(err) + assert.NotNil(amt1) + assert.Equal(amt1.Cmp(big.NewInt(0)), 1) // should be non-zero + + // second call to utoken transfer..(maker) + amt2, err := s.Erc20.TransferCalled(order.Maker) + assert.Nil(err) + assert.NotNil(amt2) + assert.Equal(amt2, amount) // should be amount + + // market zctoken burn... + burnArgs, err := s.MarketPlace.CustodialExitCalled(order.Underlying) + assert.Nil(err) + assert.NotNil(burnArgs) + assert.Equal(burnArgs.Maturity, order.Maturity) + assert.Equal(amt.Cmp(burnArgs.Amount), -1) // .Amount is passed in amt + assert.Equal(burnArgs.Two, order.Maker) + assert.Equal(burnArgs.One, s.Env.Owner.Opts.From) +} + +func TestEZFVESuite(t *test.T) { + suite.Run(t, &EZFVESuite{}) +} diff --git a/gost/pkg/swiveltesting/exit_zctoken_filling_zctoken_initiate_test.go b/gost/pkg/swiveltesting/exit_zctoken_filling_zctoken_initiate_test.go new file mode 100644 index 0000000..70628fe --- /dev/null +++ b/gost/pkg/swiveltesting/exit_zctoken_filling_zctoken_initiate_test.go @@ -0,0 +1,196 @@ +package swiveltesting + +import ( + "math/big" + test "testing" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/crypto" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" + "github.com/swivel-finance/gost/internal/helpers" + "github.com/swivel-finance/gost/test/fakes" + "github.com/swivel-finance/gost/test/mocks" + "github.com/swivel-finance/gost/test/swivel" +) + +// yeah, just make it an acronym... +type EZFZISuite struct { + suite.Suite + Env *Env + Dep *Dep + Erc20 *mocks.Erc20Session + MarketPlace *mocks.MarketPlaceSession + Swivel *swivel.SwivelSession +} + +func (s *EZFZISuite) SetupTest() { + var err error + + s.Env = NewEnv(big.NewInt(ONE_ETH)) + s.Dep, err = Deploy(s.Env) + + if err != nil { + panic(err) + } + + s.Erc20 = &mocks.Erc20Session{ + Contract: s.Dep.Erc20, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } + + s.MarketPlace = &mocks.MarketPlaceSession{ + Contract: s.Dep.MarketPlace, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } + + // binding owner to both, kind of why it exists - but could be any of the env wallets + s.Swivel = &swivel.SwivelSession{ + Contract: s.Dep.Swivel, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } +} + +func (s *EZFZISuite) TestEZFZI() { + assert := assert.New(s.T()) + + // stub underlying (erc20) transferfrom to return true + tx, err := s.Erc20.TransferFromReturns(true) + assert.Nil(err) + assert.NotNil(tx) + s.Env.Blockchain.Commit() + + // and the marketplace api methods... + tx, err = s.MarketPlace.P2pZcTokenExchangeReturns(true) + assert.Nil(err) + assert.NotNil(tx) + s.Env.Blockchain.Commit() + + // hashed order... + orderKey := helpers.GenBytes32("order") + principal := big.NewInt(5000) + principal = principal.Mul(principal, big.NewInt(1e18)) + premium := big.NewInt(50) + premium = premium.Mul(premium, big.NewInt(1e18)) + maturity := big.NewInt(10000) + expiry := big.NewInt(20000) + + // TODO preparing an order _may_ be relocated to a helper. Possibly per package? Discuss... + hashOrder := fakes.HashOrder{ + Key: orderKey, + Maker: s.Env.User1.Opts.From, + Underlying: s.Dep.Erc20Address, + Vault: false, + Exit: false, + Principal: principal, + Premium: premium, + Maturity: maturity, + Expiry: expiry, + } + + // signature... + orderHash, err := s.Dep.HashFake.OrderTest(nil, hashOrder) + assert.Nil(err) + assert.NotNil(orderHash) + + // put the hashed order together with the eip712 domain and hash those + separator, _ := s.Swivel.Domain() + messageHash, err := s.Dep.HashFake.MessageTest(nil, separator, orderHash) + assert.Nil(err) + assert.NotNil(messageHash) + + // sign it with User1 private key + sig, err := crypto.Sign(messageHash[:], s.Env.User1.PK) + assert.Nil(err) + assert.NotNil(sig) + + // get the sig components + vrs, err := s.Dep.SigFake.SplitTest(nil, sig) + assert.Nil(err) + assert.NotNil(vrs) + + // see sig_test.go + if vrs.V < 27 { + vrs.V += 27 + } + + // the order passed to the swivel contract must be of the swivel package type... + order := swivel.HashOrder{ + Key: orderKey, + Maker: s.Env.User1.Opts.From, + Underlying: s.Dep.Erc20Address, + Vault: false, + Exit: false, + Principal: principal, + Premium: premium, + Maturity: maturity, + Expiry: expiry, + } + + // like order the signature components must ref swivel + components := swivel.SigComponents{ + V: vrs.V, + R: vrs.R, + S: vrs.S, + } + + // call it (finally)... + amount := big.NewInt(25) // 1/2 the premium + amount = amount.Mul(amount, big.NewInt(1e18)) + // initiate wants slices... + orders := []swivel.HashOrder{order} + amounts := []*big.Int{amount} + componentses := []swivel.SigComponents{components} // yeah, i liek it... + + // vault false && exit false will force the call to EZFZI + tx, err = s.Swivel.Exit(orders, amounts, componentses) + + assert.Nil(err) + assert.NotNil(tx) + s.Env.Blockchain.Commit() + + // we should have a filled amount for orderKey + amt, err := s.Swivel.Filled(orderHash) + assert.Equal(amt, amount) + + // first call to utoken transferfrom 'from' should be maker here... + // TODO this call will now be overwritten by a 2nd call with the same From, re-instate this test when the hash-key-fix goes in + // args, err := s.Erc20.TransferFromCalled(order.Maker) + // assert.Nil(err) + // assert.NotNil(args) + // assert.Equal(args.To, s.Env.Owner.Opts.From) + // assert.Equal(args.Amount.Cmp(amt), 1) // amount should be greater than the passed in filled premium + + // this is the 2nd call to transferfrom with from as maker where the fee is transferred + args, err := s.Erc20.TransferFromCalled(order.Maker) + assert.Nil(err) + assert.NotNil(args) + assert.Equal(args.To, s.Dep.SwivelAddress) // fee goes to the swivel contract + assert.Equal(args.Amount.Cmp(big.NewInt(0)), 1) // fee should be something... + // s.T().Log(args.Amount) + + // market zctoken transfer from call... + zcTransferArgs, err := s.MarketPlace.P2pZcTokenExchangeCalled(order.Underlying) + assert.Nil(err) + assert.NotNil(zcTransferArgs) + assert.Equal(zcTransferArgs.Maturity, order.Maturity) + assert.Equal(zcTransferArgs.Amount.Cmp(amt), 1) // .Amount is greater than passed in filled prem (like above) + assert.Equal(zcTransferArgs.Two, order.Maker) + assert.Equal(zcTransferArgs.One, s.Env.Owner.Opts.From) +} + +func TestEZFZISuite(t *test.T) { + suite.Run(t, &EZFZISuite{}) +} diff --git a/gost/pkg/swiveltesting/initiate_vault_filling_vault_exit_test.go b/gost/pkg/swiveltesting/initiate_vault_filling_vault_exit_test.go new file mode 100644 index 0000000..72f5310 --- /dev/null +++ b/gost/pkg/swiveltesting/initiate_vault_filling_vault_exit_test.go @@ -0,0 +1,196 @@ +package swiveltesting + +import ( + "math/big" + test "testing" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/crypto" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" + "github.com/swivel-finance/gost/internal/helpers" + "github.com/swivel-finance/gost/test/fakes" + "github.com/swivel-finance/gost/test/mocks" + "github.com/swivel-finance/gost/test/swivel" +) + +// yeah, just make it an acronym... +type IVFVESuite struct { + suite.Suite + Env *Env + Dep *Dep + Erc20 *mocks.Erc20Session + MarketPlace *mocks.MarketPlaceSession + Swivel *swivel.SwivelSession +} + +func (s *IVFVESuite) SetupTest() { + var err error + + s.Env = NewEnv(big.NewInt(ONE_ETH)) + s.Dep, err = Deploy(s.Env) + + if err != nil { + panic(err) + } + + s.Erc20 = &mocks.Erc20Session{ + Contract: s.Dep.Erc20, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } + + s.MarketPlace = &mocks.MarketPlaceSession{ + Contract: s.Dep.MarketPlace, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } + + // binding owner to both, kind of why it exists - but could be any of the env wallets + s.Swivel = &swivel.SwivelSession{ + Contract: s.Dep.Swivel, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } +} + +func (s *IVFVESuite) TestIVFVE() { + assert := assert.New(s.T()) + + // stub underlying (erc20) transferfrom to return true + tx, err := s.Erc20.TransferFromReturns(true) + assert.Nil(err) + assert.NotNil(tx) + s.Env.Blockchain.Commit() + + // and the marketplace api methods... + tx, err = s.MarketPlace.P2pVaultExchangeReturns(true) + assert.Nil(err) + assert.NotNil(tx) + s.Env.Blockchain.Commit() + + tx, err = s.MarketPlace.TransferVaultNotionalFeeReturns(true) + assert.Nil(err) + assert.NotNil(tx) + s.Env.Blockchain.Commit() + + // hashed order... + orderKey := helpers.GenBytes32("order") + principal := big.NewInt(5000) + premium := big.NewInt(50) + maturity := big.NewInt(10000) + expiry := big.NewInt(20000) + + // TODO preparing an order _may_ be relocated to a helper. Possibly per package? Discuss... + hashOrder := fakes.HashOrder{ + Key: orderKey, + Maker: s.Env.User1.Opts.From, + Underlying: s.Dep.Erc20Address, + Vault: true, + Exit: true, + Principal: principal, + Premium: premium, + Maturity: maturity, + Expiry: expiry, + } + + // signature... + orderHash, err := s.Dep.HashFake.OrderTest(nil, hashOrder) + assert.Nil(err) + assert.NotNil(orderHash) + + // put the hashed order together with the eip712 domain and hash those + separator, _ := s.Swivel.Domain() + messageHash, err := s.Dep.HashFake.MessageTest(nil, separator, orderHash) + assert.Nil(err) + assert.NotNil(messageHash) + + // sign it with User1 private key + sig, err := crypto.Sign(messageHash[:], s.Env.User1.PK) + assert.Nil(err) + assert.NotNil(sig) + + // get the sig components + vrs, err := s.Dep.SigFake.SplitTest(nil, sig) + assert.Nil(err) + assert.NotNil(vrs) + + // see sig_test.go + if vrs.V < 27 { + vrs.V += 27 + } + + // the order passed to the swivel contract must be of the swivel package type... + order := swivel.HashOrder{ + Key: orderKey, + Maker: s.Env.User1.Opts.From, + Underlying: s.Dep.Erc20Address, + Vault: true, + Exit: true, + Principal: principal, + Premium: premium, + Maturity: maturity, + Expiry: expiry, + } + + // like order the signature components must ref swivel + components := swivel.SigComponents{ + V: vrs.V, + R: vrs.R, + S: vrs.S, + } + + // call it (finally)... + amount := big.NewInt(25) + // initiate wants slices... + orders := []swivel.HashOrder{order} + amounts := []*big.Int{amount} + componentses := []swivel.SigComponents{components} // yeah, i liek it... + + // vault false && exit true will force the call to IZFZE + tx, err = s.Swivel.Initiate(orders, amounts, componentses) + + assert.Nil(err) + assert.NotNil(tx) + s.Env.Blockchain.Commit() + + // we should have a filled amount for orderKey + amt, err := s.Swivel.Filled(orderHash) + assert.Equal(amt, amount) + + // first call to utoken transferfrom 'from' should be sender here... + args, err := s.Erc20.TransferFromCalled(s.Env.Owner.Opts.From) + assert.Nil(err) + assert.NotNil(args) + assert.Equal(args.To, order.Maker) + assert.Equal(amt, args.Amount) // should be "a" here + + // market notional transfer from call... + notionalTransferArgs, err := s.MarketPlace.P2pVaultExchangeCalled(order.Underlying) + assert.Nil(err) + assert.NotNil(notionalTransferArgs) + assert.Equal(notionalTransferArgs.Maturity, order.Maturity) + // log the .Amount here to check the math... + assert.Equal(notionalTransferArgs.Amount.Cmp(big.NewInt(0)), 1) // it's pFilled, so should be > 0 at the least... + assert.Equal(notionalTransferArgs.One, order.Maker) + assert.Equal(notionalTransferArgs.Two, s.Env.Owner.Opts.From) + + // transfer fee call... + feeTransferArgs, err := s.MarketPlace.TransferVaultNotionalFeeCalled(order.Underlying) + assert.Nil(err) + assert.NotNil(feeTransferArgs) + assert.Equal(feeTransferArgs.Amount, big.NewInt(6)) // 6.25 will be truncated to 6 +} + +func TestIVFVESuite(t *test.T) { + suite.Run(t, &IVFVESuite{}) +} diff --git a/gost/pkg/swiveltesting/initiate_vault_filling_zctoken_initiate_test.go b/gost/pkg/swiveltesting/initiate_vault_filling_zctoken_initiate_test.go new file mode 100644 index 0000000..07386ee --- /dev/null +++ b/gost/pkg/swiveltesting/initiate_vault_filling_zctoken_initiate_test.go @@ -0,0 +1,254 @@ +package swiveltesting + +import ( + "math/big" + test "testing" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/crypto" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" + "github.com/swivel-finance/gost/internal/helpers" + "github.com/swivel-finance/gost/test/fakes" + "github.com/swivel-finance/gost/test/mocks" + "github.com/swivel-finance/gost/test/swivel" +) + +// yeah, just make it an acronym... +type IVFZISuite struct { + suite.Suite + Env *Env + Dep *Dep + Erc20 *mocks.Erc20Session + CErc20 *mocks.CErc20Session + MarketPlace *mocks.MarketPlaceSession + Swivel *swivel.SwivelSession +} + +func (s *IVFZISuite) SetupTest() { + var err error + + s.Env = NewEnv(big.NewInt(ONE_ETH)) + s.Dep, err = Deploy(s.Env) + + if err != nil { + panic(err) + } + + s.Erc20 = &mocks.Erc20Session{ + Contract: s.Dep.Erc20, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } + + s.CErc20 = &mocks.CErc20Session{ + Contract: s.Dep.CErc20, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } + + s.MarketPlace = &mocks.MarketPlaceSession{ + Contract: s.Dep.MarketPlace, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } + + // binding owner to both, kind of why it exists - but could be any of the env wallets + s.Swivel = &swivel.SwivelSession{ + Contract: s.Dep.Swivel, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } +} + +func (s *IVFZISuite) TestMarketPlaceAddress() { + assert := assert.New(s.T()) + addr, err := s.Swivel.MarketPlace() + assert.Nil(err) + assert.Equal(addr, s.Dep.MarketPlaceAddress) +} + +func (s *IVFZISuite) TestIVFZI() { + assert := assert.New(s.T()) + + // stub underlying (erc20) transferfrom to return true + tx, err := s.Erc20.TransferFromReturns(true) + assert.Nil(err) + assert.NotNil(tx) + s.Env.Blockchain.Commit() + + // and approve + tx, err = s.Erc20.ApproveReturns(true) + assert.Nil(err) + assert.NotNil(tx) + s.Env.Blockchain.Commit() + + // and the marketplace api methods... + tx, err = s.MarketPlace.CTokenAddressReturns(s.Dep.CErc20Address) // must use the actual dep addr here + assert.Nil(err) + assert.NotNil(tx) + s.Env.Blockchain.Commit() + + tx, err = s.MarketPlace.CustodialInitiateReturns(true) + assert.Nil(err) + assert.NotNil(tx) + s.Env.Blockchain.Commit() + + tx, err = s.MarketPlace.TransferVaultNotionalFeeReturns(true) + assert.Nil(err) + assert.NotNil(tx) + s.Env.Blockchain.Commit() + + // and the ctoken mint + tx, err = s.CErc20.MintReturns(big.NewInt(0)) + assert.NotNil(tx) + assert.Nil(err) + s.Env.Blockchain.Commit() + + // hashed order... + orderKey := helpers.GenBytes32("order") + principal := big.NewInt(5000) + premium := big.NewInt(50) + maturity := big.NewInt(10000) + expiry := big.NewInt(20000) + + // TODO preparing an order _may_ be relocated to a helper. Possibly per package? Discuss... + hashOrder := fakes.HashOrder{ + Key: orderKey, + Maker: s.Env.User1.Opts.From, + Underlying: s.Dep.Erc20Address, + Vault: false, + Exit: false, + Principal: principal, + Premium: premium, + Maturity: maturity, + Expiry: expiry, + } + + // signature... + orderHash, err := s.Dep.HashFake.OrderTest(nil, hashOrder) + assert.Nil(err) + assert.NotNil(orderHash) + + // put the hashed order together with the eip712 domain and hash those + separator, _ := s.Swivel.Domain() + messageHash, err := s.Dep.HashFake.MessageTest(nil, separator, orderHash) + assert.Nil(err) + assert.NotNil(messageHash) + + // sign it with User1 private key + sig, err := crypto.Sign(messageHash[:], s.Env.User1.PK) + assert.Nil(err) + assert.NotNil(sig) + + // get the sig components + vrs, err := s.Dep.SigFake.SplitTest(nil, sig) + assert.Nil(err) + assert.NotNil(vrs) + + // see sig_test.go + if vrs.V < 27 { + vrs.V += 27 + } + + // the order passed to the swivel contract must be of the swivel package type... + order := swivel.HashOrder{ + Key: orderKey, + Maker: s.Env.User1.Opts.From, + Underlying: s.Dep.Erc20Address, + Vault: false, + Exit: false, + Principal: principal, + Premium: premium, + Maturity: maturity, + Expiry: expiry, + } + + // like order the signature components must ref swivel + components := swivel.SigComponents{ + V: vrs.V, + R: vrs.R, + S: vrs.S, + } + + // call it (finally)... + amount := big.NewInt(25) // 1/2 the premium + // initiate wants slices... + orders := []swivel.HashOrder{order} + amounts := []*big.Int{amount} + componentses := []swivel.SigComponents{components} // yeah, i liek it... + + // vault && exit false will force the call to IVFZI + tx, err = s.Swivel.Initiate(orders, amounts, componentses) + + // change the internal method to public (recompile) and call directly this way if needed... + // tx, err = s.Swivel.InitiateVaultFillingZcTokenInitiate(order, amount, components) + + assert.Nil(err) + assert.NotNil(tx) + s.Env.Blockchain.Commit() + + // we should have a filled amount for orderKey + amt, err := s.Swivel.Filled(orderHash) + assert.Equal(amt, amount) + + // first call to utoken transferfrom 'from' should be owner here... + args, err := s.Erc20.TransferFromCalled(s.Env.Owner.Opts.From) + assert.Nil(err) + assert.NotNil(args) + assert.Equal(args.To, order.Maker) + assert.Equal(args.Amount.Cmp(amount), 0) + + // second call will be keyed by order.Maker + args, err = s.Erc20.TransferFromCalled(order.Maker) + assert.Nil(err) + assert.NotNil(args) + assert.Equal(args.To, s.Dep.SwivelAddress) + // the amount here is the "principalFilled" + pFilled := args.Amount // log this if you want to check the math (2500 in this test) + assert.Equal(pFilled.Cmp(big.NewInt(0)), 1) // should be > 0 regardless + + // call to utoken approve... + arg, err := s.Erc20.ApproveCalled(s.Dep.CErc20Address) + assert.Nil(err) + assert.NotNil(arg) + // the arg here should be the pFilled + assert.Equal(arg, pFilled) + + // the call to ctoken mint, don't reuse arg as they should actually both be pFilled + mintArg, err := s.CErc20.MintCalled() + assert.Nil(err) + assert.NotNil(mintArg) + assert.Equal(mintArg, pFilled) + + // mint zctoken call... + fillingArgs, err := s.MarketPlace.CustodialInitiateCalled(order.Underlying) + assert.Nil(err) + assert.NotNil(fillingArgs) + assert.Equal(fillingArgs.Maturity, order.Maturity) + assert.Equal(fillingArgs.Amount, pFilled) + assert.Equal(fillingArgs.One, order.Maker) + assert.Equal(fillingArgs.Two, s.Env.Owner.Opts.From) + + // transfer fee call... + feeTransferArgs, err := s.MarketPlace.TransferVaultNotionalFeeCalled(order.Underlying) + assert.Nil(err) + assert.NotNil(feeTransferArgs) + assert.Equal(feeTransferArgs.Amount, big.NewInt(6)) // 6.25 will be truncated to 6 +} + +func TestIVFZISuite(t *test.T) { + suite.Run(t, &IVFZISuite{}) +} diff --git a/gost/pkg/swiveltesting/initiate_zctoken_filling_vault_initiate_test.go b/gost/pkg/swiveltesting/initiate_zctoken_filling_vault_initiate_test.go new file mode 100644 index 0000000..9e4504d --- /dev/null +++ b/gost/pkg/swiveltesting/initiate_zctoken_filling_vault_initiate_test.go @@ -0,0 +1,235 @@ +package swiveltesting + +import ( + "math/big" + test "testing" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/crypto" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" + "github.com/swivel-finance/gost/internal/helpers" + "github.com/swivel-finance/gost/test/fakes" + "github.com/swivel-finance/gost/test/mocks" + "github.com/swivel-finance/gost/test/swivel" +) + +// yeah, just make it an acronym... +type IZFVISuite struct { + suite.Suite + Env *Env + Dep *Dep + Erc20 *mocks.Erc20Session + CErc20 *mocks.CErc20Session + MarketPlace *mocks.MarketPlaceSession + Swivel *swivel.SwivelSession +} + +func (s *IZFVISuite) SetupTest() { + var err error + + s.Env = NewEnv(big.NewInt(ONE_ETH)) + s.Dep, err = Deploy(s.Env) + + if err != nil { + panic(err) + } + + s.Erc20 = &mocks.Erc20Session{ + Contract: s.Dep.Erc20, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } + + s.CErc20 = &mocks.CErc20Session{ + Contract: s.Dep.CErc20, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } + + s.MarketPlace = &mocks.MarketPlaceSession{ + Contract: s.Dep.MarketPlace, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } + + // binding owner to both, kind of why it exists - but could be any of the env wallets + s.Swivel = &swivel.SwivelSession{ + Contract: s.Dep.Swivel, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } +} + +func (s *IZFVISuite) TestIZFVI() { + assert := assert.New(s.T()) + + // stub underlying (erc20) transferfrom to return true + tx, err := s.Erc20.TransferFromReturns(true) + assert.Nil(err) + assert.NotNil(tx) + s.Env.Blockchain.Commit() + + // and approve + tx, err = s.Erc20.ApproveReturns(true) + assert.Nil(err) + assert.NotNil(tx) + s.Env.Blockchain.Commit() + + // and the marketplace api methods... + tx, err = s.MarketPlace.CTokenAddressReturns(s.Dep.CErc20Address) // must use the actual dep addr here + assert.Nil(err) + assert.NotNil(tx) + s.Env.Blockchain.Commit() + + tx, err = s.MarketPlace.CustodialInitiateReturns(true) + assert.Nil(err) + assert.NotNil(tx) + s.Env.Blockchain.Commit() + + // and the ctoken mint + tx, err = s.CErc20.MintReturns(big.NewInt(0)) + assert.NotNil(tx) + assert.Nil(err) + s.Env.Blockchain.Commit() + + // hashed order... + orderKey := helpers.GenBytes32("order") + principal := big.NewInt(1000) + principal = principal.Mul(principal, big.NewInt(1e18)) + premium := big.NewInt(50) + premium = premium.Mul(premium, big.NewInt(1e18)) + maturity := big.NewInt(10000) + expiry := big.NewInt(20000) + + // TODO preparing an order _may_ be relocated to a helper. Possibly per package? Discuss... + hashOrder := fakes.HashOrder{ + Key: orderKey, + Maker: s.Env.User1.Opts.From, + Underlying: s.Dep.Erc20Address, + Vault: true, + Exit: false, + Principal: principal, + Premium: premium, + Maturity: maturity, + Expiry: expiry, + } + + // signature... + orderHash, err := s.Dep.HashFake.OrderTest(nil, hashOrder) + assert.Nil(err) + assert.NotNil(orderHash) + + // put the hashed order together with the eip712 domain and hash those + separator, _ := s.Swivel.Domain() + messageHash, err := s.Dep.HashFake.MessageTest(nil, separator, orderHash) + assert.Nil(err) + assert.NotNil(messageHash) + + // sign it with User1 private key + sig, err := crypto.Sign(messageHash[:], s.Env.User1.PK) + assert.Nil(err) + assert.NotNil(sig) + + // get the sig components + vrs, err := s.Dep.SigFake.SplitTest(nil, sig) + assert.Nil(err) + assert.NotNil(vrs) + + // see sig_test.go + if vrs.V < 27 { + vrs.V += 27 + } + + // the order passed to the swivel contract must be of the swivel package type... + order := swivel.HashOrder{ + Key: orderKey, + Maker: s.Env.User1.Opts.From, + Underlying: s.Dep.Erc20Address, + Vault: true, + Exit: false, + Principal: principal, + Premium: premium, + Maturity: maturity, + Expiry: expiry, + } + + // like order the signature components must ref swivel + components := swivel.SigComponents{ + V: vrs.V, + R: vrs.R, + S: vrs.S, + } + + // call it (finally)... + amount := big.NewInt(25) + amount = amount.Mul(amount, big.NewInt(1e18)) + // initiate wants slices... + orders := []swivel.HashOrder{order} + amounts := []*big.Int{amount} + componentses := []swivel.SigComponents{components} // yeah, i liek it... + + // vault true && exit false will force the call to IZFVI + tx, err = s.Swivel.Initiate(orders, amounts, componentses) + + assert.Nil(err) + assert.NotNil(tx) + s.Env.Blockchain.Commit() + + // we should have a filled amount for orderKey + amt, err := s.Swivel.Filled(orderHash) + assert.Equal(amt, amount) + + // first call to utoken transferfrom 'from' should be maker here... + args, err := s.Erc20.TransferFromCalled(order.Maker) + assert.Nil(err) + assert.NotNil(args) + assert.Equal(args.To, s.Env.Owner.Opts.From) + assert.Equal(args.Amount.Cmp(big.NewInt(0)), 1) // amount is pFilled here so should be > 0 + + // second call will be keyed by owner... + args, err = s.Erc20.TransferFromCalled(s.Env.Owner.Opts.From) + assert.Nil(err) + assert.NotNil(args) + assert.Equal(args.To, s.Dep.SwivelAddress) + // the amount here is the "a" + fee, thus it should be GT the original amount + assert.Equal(1, args.Amount.Cmp(amt)) + + // call to utoken approve... + arg, err := s.Erc20.ApproveCalled(s.Dep.CErc20Address) + assert.Nil(err) + assert.NotNil(arg) + // the arg here should be the passed "a" + assert.Equal(arg, amt) + + // the call to ctoken mint, don't reuse arg as they should actually both be "a" + mintArg, err := s.CErc20.MintCalled() + assert.Nil(err) + assert.NotNil(mintArg) + assert.Equal(mintArg, amt) + + // mint zctoken call... + fillingArgs, err := s.MarketPlace.CustodialInitiateCalled(order.Underlying) + assert.Nil(err) + assert.NotNil(fillingArgs) + assert.Equal(fillingArgs.Maturity, order.Maturity) + assert.Equal(fillingArgs.Amount, amt) + assert.Equal(fillingArgs.Two, order.Maker) + assert.Equal(fillingArgs.One, s.Env.Owner.Opts.From) +} + +func TestIZFVISuite(t *test.T) { + suite.Run(t, &IZFVISuite{}) +} diff --git a/gost/pkg/swiveltesting/initiate_zctoken_filling_zctoken_exit_test.go b/gost/pkg/swiveltesting/initiate_zctoken_filling_zctoken_exit_test.go new file mode 100644 index 0000000..4e39930 --- /dev/null +++ b/gost/pkg/swiveltesting/initiate_zctoken_filling_zctoken_exit_test.go @@ -0,0 +1,194 @@ +package swiveltesting + +import ( + "math/big" + test "testing" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/crypto" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" + "github.com/swivel-finance/gost/internal/helpers" + "github.com/swivel-finance/gost/test/fakes" + "github.com/swivel-finance/gost/test/mocks" + "github.com/swivel-finance/gost/test/swivel" +) + +// yeah, just make it an acronym... +type IZFZESuite struct { + suite.Suite + Env *Env + Dep *Dep + Erc20 *mocks.Erc20Session + CErc20 *mocks.CErc20Session + MarketPlace *mocks.MarketPlaceSession + Swivel *swivel.SwivelSession +} + +func (s *IZFZESuite) SetupTest() { + var err error + + s.Env = NewEnv(big.NewInt(ONE_ETH)) + s.Dep, err = Deploy(s.Env) + + if err != nil { + panic(err) + } + + s.Erc20 = &mocks.Erc20Session{ + Contract: s.Dep.Erc20, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } + + s.CErc20 = &mocks.CErc20Session{ + Contract: s.Dep.CErc20, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } + + s.MarketPlace = &mocks.MarketPlaceSession{ + Contract: s.Dep.MarketPlace, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } + + // binding owner to both, kind of why it exists - but could be any of the env wallets + s.Swivel = &swivel.SwivelSession{ + Contract: s.Dep.Swivel, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } +} + +func (s *IZFZESuite) TestIZFZE() { + assert := assert.New(s.T()) + + // stub underlying (erc20) transferfrom to return true + tx, err := s.Erc20.TransferFromReturns(true) + assert.Nil(err) + assert.NotNil(tx) + s.Env.Blockchain.Commit() + + // and the marketplace api methods... + tx, err = s.MarketPlace.P2pZcTokenExchangeReturns(true) + assert.Nil(err) + assert.NotNil(tx) + s.Env.Blockchain.Commit() + + // hashed order... + orderKey := helpers.GenBytes32("order") + principal := big.NewInt(5000) + premium := big.NewInt(50) + maturity := big.NewInt(10000) + expiry := big.NewInt(20000) + + // TODO preparing an order _may_ be relocated to a helper. Possibly per package? Discuss... + hashOrder := fakes.HashOrder{ + Key: orderKey, + Maker: s.Env.User1.Opts.From, + Underlying: s.Dep.Erc20Address, + Vault: false, + Exit: true, + Principal: principal, + Premium: premium, + Maturity: maturity, + Expiry: expiry, + } + + // signature... + orderHash, err := s.Dep.HashFake.OrderTest(nil, hashOrder) + assert.Nil(err) + assert.NotNil(orderHash) + + // put the hashed order together with the eip712 domain and hash those + separator, _ := s.Swivel.Domain() + messageHash, err := s.Dep.HashFake.MessageTest(nil, separator, orderHash) + assert.Nil(err) + assert.NotNil(messageHash) + + // sign it with User1 private key + sig, err := crypto.Sign(messageHash[:], s.Env.User1.PK) + assert.Nil(err) + assert.NotNil(sig) + + // get the sig components + vrs, err := s.Dep.SigFake.SplitTest(nil, sig) + assert.Nil(err) + assert.NotNil(vrs) + + // see sig_test.go + if vrs.V < 27 { + vrs.V += 27 + } + + // the order passed to the swivel contract must be of the swivel package type... + order := swivel.HashOrder{ + Key: orderKey, + Maker: s.Env.User1.Opts.From, + Underlying: s.Dep.Erc20Address, + Vault: false, + Exit: true, + Principal: principal, + Premium: premium, + Maturity: maturity, + Expiry: expiry, + } + + // like order the signature components must ref swivel + components := swivel.SigComponents{ + V: vrs.V, + R: vrs.R, + S: vrs.S, + } + + // call it (finally)... + amount := big.NewInt(2500) // 1/2 the principal + // initiate wants slices... + orders := []swivel.HashOrder{order} + amounts := []*big.Int{amount} + componentses := []swivel.SigComponents{components} // yeah, i liek it... + + // vault false && exit true will force the call to IZFZE + tx, err = s.Swivel.Initiate(orders, amounts, componentses) + + assert.Nil(err) + assert.NotNil(tx) + s.Env.Blockchain.Commit() + + // we should have a filled amount for orderKey + amt, err := s.Swivel.Filled(orderHash) + assert.Equal(amt, amount) + + // first call to utoken transferfrom 'from' should be sender here... + args, err := s.Erc20.TransferFromCalled(s.Env.Owner.Opts.From) + assert.Nil(err) + assert.NotNil(args) + assert.Equal(args.To, order.Maker) + assert.Equal(amt.Cmp(args.Amount), 1) // amount should be (a - pFilled, so less than passed amt) + + // market zctoken transfer from call... + marketTransferArgs, err := s.MarketPlace.P2pZcTokenExchangeCalled(order.Underlying) + assert.Nil(err) + assert.NotNil(marketTransferArgs) + assert.Equal(marketTransferArgs.Maturity, order.Maturity) + assert.Equal(marketTransferArgs.Amount, amt) + assert.Equal(marketTransferArgs.One, order.Maker) + assert.Equal(marketTransferArgs.Two, s.Env.Owner.Opts.From) +} + +func TestIZFZESuite(t *test.T) { + suite.Run(t, &IZFZESuite{}) +} diff --git a/gost/pkg/swiveltesting/redeem_vault_interest_test.go b/gost/pkg/swiveltesting/redeem_vault_interest_test.go new file mode 100644 index 0000000..c324917 --- /dev/null +++ b/gost/pkg/swiveltesting/redeem_vault_interest_test.go @@ -0,0 +1,137 @@ +package swiveltesting + +import ( + "math/big" + test "testing" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + assertions "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" + "github.com/swivel-finance/gost/test/mocks" + "github.com/swivel-finance/gost/test/swivel" +) + +type redeemVaultInterestSuite struct { + suite.Suite + Env *Env + Dep *Dep + Erc20 *mocks.Erc20Session + CErc20 *mocks.CErc20Session + MarketPlace *mocks.MarketPlaceSession + Swivel *swivel.SwivelSession +} + +func (s *redeemVaultInterestSuite) SetupTest() { + var err error + + s.Env = NewEnv(big.NewInt(ONE_ETH)) + s.Dep, err = Deploy(s.Env) + + if err != nil { + panic(err) + } + + s.Erc20 = &mocks.Erc20Session{ + Contract: s.Dep.Erc20, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } + + s.CErc20 = &mocks.CErc20Session{ + Contract: s.Dep.CErc20, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } + + s.MarketPlace = &mocks.MarketPlaceSession{ + Contract: s.Dep.MarketPlace, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } + + s.Swivel = &swivel.SwivelSession{ + Contract: s.Dep.Swivel, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } +} + +func (s *redeemZcTokenSuite) TestRedeemVaultInterest() { + assert := assertions.New(s.T()) + underlying := s.Dep.Erc20Address + maturity := s.Dep.Maturity + + tx, err := s.CErc20.RedeemUnderlyingReturns(big.NewInt(0)) + assert.NotNil(tx) + assert.Nil(err) + + s.Env.Blockchain.Commit() + + tx, err = s.MarketPlace.CTokenAddressReturns(s.Dep.CErc20Address) // must use the actual dep addr here + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + redeemed := big.NewInt(12345) + tx, err = s.MarketPlace.RedeemVaultInterestReturns(redeemed) + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + tx, err = s.Swivel.RedeemVaultInterest(underlying, maturity) + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + // underlying tranfer should have been called with an amount redeemed + transferred, err := s.Erc20.TransferCalled(s.Env.Owner.Opts.From) + assert.Nil(err) + assert.Equal(redeemed, transferred) +} + +func (s *redeemZcTokenSuite) TestRedeemVaultInterestUnderlyingFails() { + assert := assertions.New(s.T()) + underlying := s.Dep.Erc20Address + maturity := s.Dep.Maturity + + tx, err := s.CErc20.RedeemUnderlyingReturns(big.NewInt(1)) + assert.NotNil(tx) + assert.Nil(err) + + s.Env.Blockchain.Commit() + + tx, err = s.MarketPlace.CTokenAddressReturns(s.Dep.CErc20Address) // must use the actual dep addr here + assert.Nil(err) + assert.NotNil(tx) + s.Env.Blockchain.Commit() + + tx, err = s.MarketPlace.RedeemVaultInterestReturns(big.NewInt(12345)) + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + tx, err = s.Swivel.RedeemVaultInterest(underlying, maturity) + assert.NotNil(err) + assert.Regexp("compound redemption failed", err.Error()) + assert.Nil(tx) +} + +func TestRedeemVaultInterestSuite(t *test.T) { + suite.Run(t, &redeemVaultInterestSuite{}) +} diff --git a/gost/pkg/swiveltesting/redeem_zctoken_test.go b/gost/pkg/swiveltesting/redeem_zctoken_test.go new file mode 100644 index 0000000..1162926 --- /dev/null +++ b/gost/pkg/swiveltesting/redeem_zctoken_test.go @@ -0,0 +1,141 @@ +package swiveltesting + +import ( + "math/big" + test "testing" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + assertions "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" + "github.com/swivel-finance/gost/test/mocks" + "github.com/swivel-finance/gost/test/swivel" +) + +type redeemZcTokenSuite struct { + suite.Suite + Env *Env + Dep *Dep + Erc20 *mocks.Erc20Session + CErc20 *mocks.CErc20Session + MarketPlace *mocks.MarketPlaceSession + Swivel *swivel.SwivelSession +} + +func (s *redeemZcTokenSuite) SetupTest() { + var err error + + s.Env = NewEnv(big.NewInt(ONE_ETH)) + s.Dep, err = Deploy(s.Env) + + if err != nil { + panic(err) + } + + s.Erc20 = &mocks.Erc20Session{ + Contract: s.Dep.Erc20, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } + + s.CErc20 = &mocks.CErc20Session{ + Contract: s.Dep.CErc20, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } + + s.MarketPlace = &mocks.MarketPlaceSession{ + Contract: s.Dep.MarketPlace, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } + + s.Swivel = &swivel.SwivelSession{ + Contract: s.Dep.Swivel, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } +} + +func (s *redeemZcTokenSuite) TestRedeemZcToken() { + assert := assertions.New(s.T()) + underlying := s.Dep.Erc20Address + maturity := s.Dep.Maturity + + tx, err := s.CErc20.RedeemUnderlyingReturns(big.NewInt(0)) + assert.NotNil(tx) + assert.Nil(err) + + s.Env.Blockchain.Commit() + + tx, err = s.MarketPlace.CTokenAddressReturns(s.Dep.CErc20Address) // must use the actual dep addr here + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + // stub the marketplace mock.redeemZcToken + redeemed := big.NewInt(12345) + tx, err = s.MarketPlace.RedeemZcTokenReturns(redeemed) + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + amount := big.NewInt(123456) + tx, err = s.Swivel.RedeemZcToken(underlying, maturity, amount) + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + // underlying tranfer should have been called with an amount redeemed + transferred, err := s.Erc20.TransferCalled(s.Env.Owner.Opts.From) + assert.Nil(err) + assert.Equal(redeemed, transferred) +} + +func (s *redeemZcTokenSuite) TestRedeemZcTokenRedeemUnderlyingFails() { + assert := assertions.New(s.T()) + underlying := s.Dep.Erc20Address + maturity := s.Dep.Maturity + + tx, err := s.CErc20.RedeemUnderlyingReturns(big.NewInt(1)) + assert.NotNil(tx) + assert.Nil(err) + + s.Env.Blockchain.Commit() + + tx, err = s.MarketPlace.CTokenAddressReturns(s.Dep.CErc20Address) // must use the actual dep addr here + assert.Nil(err) + assert.NotNil(tx) + s.Env.Blockchain.Commit() + + // stub the marketplace mock.redeemZcToken + tx, err = s.MarketPlace.RedeemZcTokenReturns(big.NewInt(12345)) + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + amount := big.NewInt(123456) + tx, err = s.Swivel.RedeemZcToken(underlying, maturity, amount) + assert.NotNil(err) + assert.Regexp("compound redemption failed", err.Error()) + assert.Nil(tx) +} + +func TestRedeemZcTokenSuite(t *test.T) { + suite.Run(t, &redeemZcTokenSuite{}) +} diff --git a/gost/pkg/swiveltesting/split_and_combine_test.go b/gost/pkg/swiveltesting/split_and_combine_test.go new file mode 100644 index 0000000..1b52f1c --- /dev/null +++ b/gost/pkg/swiveltesting/split_and_combine_test.go @@ -0,0 +1,156 @@ +package swiveltesting + +import ( + "math/big" + test "testing" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + // "github.com/ethereum/go-ethereum/common" + // "github.com/ethereum/go-ethereum/crypto" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" + // "github.com/swivel-finance/gost/internal/helpers" + // "github.com/swivel-finance/gost/test/fakes" + "github.com/swivel-finance/gost/test/mocks" + "github.com/swivel-finance/gost/test/swivel" +) + +type splitCombineSuite struct { + suite.Suite + Env *Env + Dep *Dep + Erc20 *mocks.Erc20Session + CErc20 *mocks.CErc20Session + MarketPlace *mocks.MarketPlaceSession + Swivel *swivel.SwivelSession +} + +func (s *splitCombineSuite) SetupTest() { + var err error + + s.Env = NewEnv(big.NewInt(ONE_ETH)) + s.Dep, err = Deploy(s.Env) + + if err != nil { + panic(err) + } + + s.Erc20 = &mocks.Erc20Session{ + Contract: s.Dep.Erc20, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } + + s.CErc20 = &mocks.CErc20Session{ + Contract: s.Dep.CErc20, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } + + s.MarketPlace = &mocks.MarketPlaceSession{ + Contract: s.Dep.MarketPlace, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } + + // binding owner to both, kind of why it exists - but could be any of the env wallets + s.Swivel = &swivel.SwivelSession{ + Contract: s.Dep.Swivel, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } +} + +func (s *splitCombineSuite) TestSplit() { + assert := assert.New(s.T()) + + // stub (Cerc20) to return 0 + tx, err := s.CErc20.MintReturns(big.NewInt(0)) + assert.NotNil(tx) + assert.Nil(err) + s.Env.Blockchain.Commit() + + // the marketplace mock... + tx, err = s.MarketPlace.CTokenAddressReturns(s.Dep.CErc20Address) // must use the actual dep addr here + assert.NotNil(tx) + assert.Nil(err) + s.Env.Blockchain.Commit() + + tx, err = s.MarketPlace.MintZcTokenAddingNotionalReturns(true) + assert.NotNil(tx) + assert.Nil(err) + s.Env.Blockchain.Commit() + + maturity := big.NewInt(123456789) + amount := big.NewInt(1000) + + tx, err = s.Swivel.SplitUnderlying(s.Dep.Erc20Address, maturity, amount) + + assert.Nil(err) + assert.NotNil(tx) + s.Env.Blockchain.Commit() + + // we just care that the args were passed thru... + splitArgs, err := s.MarketPlace.MintZcTokenAddingNotionalCalled(s.Dep.Erc20Address) + assert.Nil(err) + assert.NotNil(splitArgs) + assert.Equal(splitArgs.Maturity, maturity) + assert.Equal(splitArgs.Amount, amount) + // msg.sender will be owner here + assert.Equal(splitArgs.One, s.Env.Owner.Opts.From) +} + +func (s *splitCombineSuite) TestCombine() { + assert := assert.New(s.T()) + + // stub (Cerc20) to return 0 + tx, err := s.CErc20.RedeemUnderlyingReturns(big.NewInt(0)) + assert.NotNil(tx) + assert.Nil(err) + s.Env.Blockchain.Commit() + + // the marketplace mock... + tx, err = s.MarketPlace.CTokenAddressReturns(s.Dep.CErc20Address) // must use the actual dep addr here + assert.NotNil(tx) + assert.Nil(err) + s.Env.Blockchain.Commit() + + tx, err = s.MarketPlace.BurnZcTokenRemovingNotionalReturns(true) + assert.NotNil(tx) + assert.Nil(err) + s.Env.Blockchain.Commit() + + maturity := big.NewInt(123456789) + amount := big.NewInt(1000) + + tx, err = s.Swivel.CombineTokens(s.Dep.Erc20Address, maturity, amount) + + assert.Nil(err) + assert.NotNil(tx) + s.Env.Blockchain.Commit() + + // we just care that the args were passed thru... + combineArgs, err := s.MarketPlace.BurnZcTokenRemovingNotionalCalled(s.Dep.Erc20Address) + assert.Nil(err) + assert.NotNil(combineArgs) + assert.Equal(combineArgs.Maturity, maturity) + assert.Equal(combineArgs.Amount, amount) + // msg.sender will be owner here + assert.Equal(combineArgs.One, s.Env.Owner.Opts.From) +} + +func TestSplitCombineSuite(t *test.T) { + suite.Run(t, &splitCombineSuite{}) +} diff --git a/gost/pkg/swiveltesting/swivel_construction_test.go b/gost/pkg/swiveltesting/swivel_construction_test.go new file mode 100644 index 0000000..1e2f0e7 --- /dev/null +++ b/gost/pkg/swiveltesting/swivel_construction_test.go @@ -0,0 +1,65 @@ +package swiveltesting + +import ( + "math/big" + test "testing" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + // "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" + "github.com/swivel-finance/gost/test/swivel" +) + +type swivelCtorSuite struct { + suite.Suite + Env *Env + Dep *Dep + Swivel *swivel.SwivelSession // *Session objects are created by the go bindings +} + +func (s *swivelCtorSuite) SetupSuite() { + var err error + + s.Env = NewEnv(big.NewInt(ONE_ETH)) // each of the wallets in the env will begin with this balance + s.Dep, err = Deploy(s.Env) + + if err != nil { + panic(err) + } + + // binding owner to both, kind of why it exists - but could be any of the env wallets + s.Swivel = &swivel.SwivelSession{ + Contract: s.Dep.Swivel, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } +} + +func (s *swivelCtorSuite) TestName() { + assert := assert.New(s.T()) + name, err := s.Swivel.NAME() + assert.Nil(err) + assert.Equal(name, "Swivel Finance") +} + +func (s *swivelCtorSuite) TestVersion() { + assert := assert.New(s.T()) + verz, err := s.Swivel.VERSION() + assert.Nil(err) + assert.Equal(verz, "2.0.0") +} + +func (s *swivelCtorSuite) TestDomain() { + assert := assert.New(s.T()) + separator, err := s.Swivel.Domain() + assert.Nil(err) + assert.Equal(32, len(separator)) +} + +func TestSwivelCtorSuite(t *test.T) { + suite.Run(t, &swivelCtorSuite{}) +} diff --git a/gost/pkg/swiveltesting/withdrawal_test.go b/gost/pkg/swiveltesting/withdrawal_test.go new file mode 100644 index 0000000..9ee45d6 --- /dev/null +++ b/gost/pkg/swiveltesting/withdrawal_test.go @@ -0,0 +1,166 @@ +package swiveltesting + +import ( + "math/big" + "strings" + test "testing" + "time" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" + "github.com/swivel-finance/gost/test/mocks" + "github.com/swivel-finance/gost/test/swivel" +) + +type withdrawalSuite struct { + suite.Suite + Env *Env + Dep *Dep + Erc20 *mocks.Erc20Session + Swivel *swivel.SwivelSession +} + +func (s *withdrawalSuite) SetupTest() { + var err error + + s.Env = NewEnv(big.NewInt(ONE_ETH)) + s.Dep, err = Deploy(s.Env) + + if err != nil { + panic(err) + } + + // err = s.Env.Blockchain.AdjustTime(0) // set bc timestamp to 0 + // if err != nil { + // panic(err) + // } + // s.Env.Blockchain.Commit() + + s.Erc20 = &mocks.Erc20Session{ + Contract: s.Dep.Erc20, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } + + s.Swivel = &swivel.SwivelSession{ + Contract: s.Dep.Swivel, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } +} + +func (s *withdrawalSuite) TestScheduleWithdrawal() { + assert := assert.New(s.T()) + + tokenAddress := common.HexToAddress("0xiamatoken") // we don't need an actual token here + + tx, err := s.Swivel.ScheduleWithdrawal(tokenAddress) + + assert.Nil(err) + assert.NotNil(tx) + s.Env.Blockchain.Commit() + + hold, _ := s.Swivel.Withdrawals(tokenAddress) + assert.Equal(1, hold.Cmp(big.NewInt(259200))) // hold should be greater than the hold constant +} + +func (s *withdrawalSuite) TestScheduleWithdrawalFails() { + assert := assert.New(s.T()) + + tokenAddress := common.HexToAddress("0xiamanothertoken") + + tx, err := s.Dep.Swivel.ScheduleWithdrawal(&bind.TransactOpts{From: s.Env.User1.Opts.From, Signer: s.Env.User1.Opts.Signer}, tokenAddress) + + assert.NotNil(err) + assert.Nil(tx) + assert.True(strings.Contains(err.Error(), "sender must be admin")) + s.Env.Blockchain.Commit() + + hold, _ := s.Swivel.Withdrawals(tokenAddress) + assert.Equal(0, hold.Cmp(big.NewInt(0))) +} + +func (s *withdrawalSuite) TestWithdrawalFailsNotScheduled() { + assert := assert.New(s.T()) + + tokenAddress := common.HexToAddress("0xyomommastoken") + + tx, err := s.Swivel.Withdraw(tokenAddress) + + assert.NotNil(err) + assert.Nil(tx) + assert.True(strings.Contains(err.Error(), "no withdrawal scheduled")) +} + +func (s *withdrawalSuite) TestWithdrawalFailsOnHold() { + assert := assert.New(s.T()) + + tokenAddress := common.HexToAddress("0xspamtoken") + + tx, err := s.Swivel.ScheduleWithdrawal(tokenAddress) + + assert.Nil(err) + assert.NotNil(tx) + s.Env.Blockchain.Commit() + + tx, err = s.Swivel.Withdraw(tokenAddress) + + assert.NotNil(err) + assert.Nil(tx) + assert.True(strings.Contains(err.Error(), "withdrawal still on hold")) +} + +func (s *withdrawalSuite) TestWithdrawal() { + assert := assert.New(s.T()) + + // reset time to 0 + err := s.Env.Blockchain.AdjustTime(0) + if err != nil { + panic(err) + } + + s.Env.Blockchain.Commit() + + oneBill := big.NewInt(1000000000) + + // stub the balanceOf return + tx, err := s.Erc20.BalanceOfReturns(oneBill) + assert.NotNil(tx) + assert.Nil(err) + + s.Env.Blockchain.Commit() + + // schedule it... + tx, err = s.Swivel.ScheduleWithdrawal(s.Dep.Erc20Address) + s.Env.Blockchain.Commit() + + // move, at least, to the hold time + err = s.Env.Blockchain.AdjustTime(259200 * time.Second) + if err != nil { + panic(err) + } + s.Env.Blockchain.Commit() + + // now you should be able to withdraw + tx, err = s.Swivel.Withdraw(s.Dep.Erc20Address) + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + // inspect the transfer amt + amount, _ := s.Erc20.TransferCalled(s.Env.Owner.Opts.From) + assert.Equal(amount, oneBill) +} + +func TestWithdrawalSuite(t *test.T) { + suite.Run(t, &withdrawalSuite{}) +} diff --git a/gost/pkg/testing/constants.go b/gost/pkg/testing/constants.go new file mode 100644 index 0000000..2eb2cfb --- /dev/null +++ b/gost/pkg/testing/constants.go @@ -0,0 +1,9 @@ +package testing + +import "math/big" + +const ONE_ETH = 1000000000000000000 +const ONE_GWEI = 1000000000 +const ONE_WEI = 1 + +var ZERO = big.NewInt(0) diff --git a/gost/pkg/testing/dep.go b/gost/pkg/testing/dep.go new file mode 100644 index 0000000..575031e --- /dev/null +++ b/gost/pkg/testing/dep.go @@ -0,0 +1,85 @@ +package testing + +import ( + "github.com/ethereum/go-ethereum/common" + "github.com/swivel-finance/gost/test/fakes" + "github.com/swivel-finance/gost/test/mocks" +) + +type Dep struct { + SigFakeAddress common.Address + SigFake *fakes.SigFake // fake sig lib test contract + HashFakeAddress common.Address + HashFake *fakes.HashFake // fake hash lib test contract + Erc20Address common.Address + Erc20 *mocks.Erc20 + CErc20Address common.Address + CErc20 *mocks.CErc20 +} + +func Deploy(e *Env) (*Dep, error) { + // deploying the lib testing contract "fakes" + // NOTE these _could_ be moved into their own package as they are not needed + // for swivel to operate. TODO + sigAddress, _, sigContract, sigErr := fakes.DeploySigFake(e.Owner.Opts, e.Blockchain) + + if sigErr != nil { + return nil, sigErr + } + + e.Blockchain.Commit() + + hashAddress, _, hashContract, hashErr := fakes.DeployHashFake(e.Owner.Opts, e.Blockchain) + + if hashErr != nil { + return nil, hashErr + } + + e.Blockchain.Commit() + + // deploy the two mock tokens. + ercAddress, _, ercContract, ercErr := mocks.DeployErc20(e.Owner.Opts, e.Blockchain) + + if ercErr != nil { + return nil, ercErr + } + + e.Blockchain.Commit() + + cercAddress, _, cercContract, cercErr := mocks.DeployCErc20(e.Owner.Opts, e.Blockchain) + + if cercErr != nil { + return nil, cercErr + } + + e.Blockchain.Commit() + + // deploy marketplace contract... TODO we likely give the marketplace address to swivel... + // marketAddress, _, marketContract, marketErr := swivel.DeployMarketPlace(e.Owner.Opts, e.Blockchain) + + // if marketErr != nil { + // return nil, marketErr + // } + + // e.Blockchain.Commit() + + // deploy swivel contract... + // swivelAddress, _, swivelContract, swivelErr := swivel.DeploySwivel(e.Owner.Opts, e.Blockchain) + + // if swivelErr != nil { + // return nil, swivelErr + // } + + // e.Blockchain.Commit() + + return &Dep{ + SigFakeAddress: sigAddress, + SigFake: sigContract, + HashFakeAddress: hashAddress, + HashFake: hashContract, + Erc20Address: ercAddress, + Erc20: ercContract, + CErc20Address: cercAddress, + CErc20: cercContract, + }, nil +} diff --git a/gost/pkg/testing/env.go b/gost/pkg/testing/env.go new file mode 100644 index 0000000..ba2b662 --- /dev/null +++ b/gost/pkg/testing/env.go @@ -0,0 +1,52 @@ +package testing + +import ( + "crypto/ecdsa" + "math/big" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/accounts/abi/bind/backends" + "github.com/ethereum/go-ethereum/core" + "github.com/swivel-finance/gost/internal/helpers" +) + +// Auth is a custom type which allows us easy access to the dynamically generated +// ecdsa.PrivateKey along with the bind.TransactOpts +type Auth struct { + PK *ecdsa.PrivateKey + Opts *bind.TransactOpts +} + +// Env, holds Auth objects capable of signing transactions. +// Also holds the Geth simulated backend. +type Env struct { + Alloc core.GenesisAlloc + // TODO maybe change to Admin to fit v2 contract terms... + Owner *Auth + User1 *Auth + User2 *Auth + Blockchain *backends.SimulatedBackend +} + +// NewEnv returns a hydrated Env struct, ready for use. +// Given a balance argument, it assigns this as the wallet balance for +// each authorization object in the Ctx +func NewEnv(b *big.Int) *Env { + pk, owner := helpers.NewAuth() + pk1, u1 := helpers.NewAuth() + pk2, u2 := helpers.NewAuth() + alloc := make(core.GenesisAlloc) + alloc[owner.From] = core.GenesisAccount{Balance: b} + alloc[u1.From] = core.GenesisAccount{Balance: b} + alloc[u2.From] = core.GenesisAccount{Balance: b} + // 2nd arg is a gas limit, a uint64. we'll use 4.7 million + bc := backends.NewSimulatedBackend(alloc, 4700000) + + return &Env{ + Alloc: alloc, + Owner: &Auth{PK: pk, Opts: owner}, + User1: &Auth{PK: pk1, Opts: u1}, + User2: &Auth{PK: pk2, Opts: u2}, + Blockchain: bc, + } +} diff --git a/gost/pkg/testing/hash_test.go b/gost/pkg/testing/hash_test.go new file mode 100644 index 0000000..82854f3 --- /dev/null +++ b/gost/pkg/testing/hash_test.go @@ -0,0 +1,108 @@ +package testing + +import ( + "math/big" + test "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" + "github.com/swivel-finance/gost/internal/helpers" + "github.com/swivel-finance/gost/test/fakes" +) + +type hashTestSuite struct { + suite.Suite + Env *Env + Dep *Dep + Separator [32]byte // keep a ref to prevent re calculating +} + +// helper to return a hydrated order. TODO move to a helper... +func order(m common.Address, f bool) fakes.HashOrder { // abigen defined + // NOTE: none of the actual numbers used matter here for the purpose of this test. + return fakes.HashOrder{ + Key: helpers.GenBytes32("abc123"), + Maker: m, + Underlying: common.HexToAddress("0xbcd234"), + Vault: f, + Exit: f, + Principal: big.NewInt(1000), + Premium: big.NewInt(100), + Maturity: big.NewInt(123456), + Expiry: big.NewInt(123456789), + } +} + +// SetupSuite serves as a 'beforeAll', hydrating both the Env and Dep objects +func (s *hashTestSuite) SetupSuite() { + // declared because we can't use := here (s.Dep already defined) + var err error + + s.Env = NewEnv(big.NewInt(ONE_ETH)) // each of the wallets in the env will begin with this balance + s.Dep, err = Deploy(s.Env) + + if err != nil { + panic(err) + } +} + +// NOTE: present just to calculate the hashed values stored in the contracts +func (s *hashTestSuite) TestTypeHashes() { + domainTypehash, _ := s.Dep.HashFake.DomainTypeHash(nil) + orderTypehash, _ := s.Dep.HashFake.OrderTypeHash(nil) + permitTypehash, _ := s.Dep.HashFake.PermitTypeHash(nil) + s.T().Logf("Domain Typehash: %v", hexutil.Encode(domainTypehash[:])) + s.T().Logf("Order Typehash: %v", hexutil.Encode(orderTypehash[:])) + s.T().Logf("Permit Typehash: %v", hexutil.Encode(permitTypehash[:])) +} + +func (s *hashTestSuite) TestDomain() { + var err error + + assert := assert.New(s.T()) + + s.Separator, err = s.Dep.HashFake.DomainTest( + nil, + "Swivel Finance", + "2.0.0", + big.NewInt(5), + common.HexToAddress("0x6a6BeC42A5Dd6F2766F806F91Ad12034F43b6361"), + ) + + assert.Nil(err) + assert.NotNil(s.Separator) + assert.Equal(len(s.Separator), 32) + // s.T().Log(hexutil.Encode(s.Separator[:])) +} + +func (s *hashTestSuite) TestOrder() { + assert := assert.New(s.T()) + + order := order(s.Env.Owner.Opts.From, false) + + hash, err := s.Dep.HashFake.OrderTest(nil, order) + + assert.Nil(err) + assert.NotNil(hash) + assert.Equal(len(hash), 32) +} + +func (s *hashTestSuite) TestMessage() { + assert := assert.New(s.T()) + // get a hashed order + + order := order(s.Env.Owner.Opts.From, false) + orderHash, _ := s.Dep.HashFake.OrderTest(nil, order) + + messageHash, err := s.Dep.HashFake.MessageTest(nil, s.Separator, orderHash) + + assert.Nil(err) + assert.NotNil(messageHash) + assert.Equal(len(messageHash), 32) +} + +func TestHashSuite(t *test.T) { + suite.Run(t, &hashTestSuite{}) +} diff --git a/gost/pkg/testing/sig_test.go b/gost/pkg/testing/sig_test.go new file mode 100644 index 0000000..6bf58aa --- /dev/null +++ b/gost/pkg/testing/sig_test.go @@ -0,0 +1,74 @@ +package testing + +import ( + "math/big" + test "testing" + + "github.com/ethereum/go-ethereum/crypto" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" +) + +type sigTestSuite struct { + suite.Suite + Env *Env + Dep *Dep +} + +// SetupSuite serves as a 'beforeAll', hydrating both the Env and Dep objects +func (s *sigTestSuite) SetupSuite() { + var err error + + s.Env = NewEnv(big.NewInt(ONE_ETH)) // each of the wallets in the env will begin with this balance + s.Dep, err = Deploy(s.Env) + + if err != nil { + panic(err) + } +} + +func (s *sigTestSuite) TestSplit() { + assert := assert.New(s.T()) + + msg := []byte("Yo Dawg, heard u liek unit tests") + hash := crypto.Keccak256Hash(msg) + + // sign with user1... + sig, err := crypto.Sign(hash.Bytes(), s.Env.User1.PK) + + assert.Nil(err) + assert.NotNil(sig) + + vrs, err := s.Dep.SigFake.SplitTest(nil, sig) + + assert.Nil(err) + assert.NotNil(vrs) +} + +func (s *sigTestSuite) TestRecover() { + assert := assert.New(s.T()) + + msg := []byte("So we put tests in your tests so you can test while you test") + hash := crypto.Keccak256Hash(msg) + + // sign with user1... + sig, err := crypto.Sign(hash.Bytes(), s.Env.User1.PK) + // the go bindings return a struct here -> { V: R: S: } + vrs, err := s.Dep.SigFake.SplitTest(nil, sig) + + // crypto.Sign will produce a split whose V is 0 or 1 + // NOTE: 27 or 28 are acceptable + if vrs.V < 27 { + vrs.V += 27 + } + + addr, err := s.Dep.SigFake.RecoverTest(nil, hash, vrs) + + assert.Nil(err) + assert.NotNil(addr) + assert.Equal(addr, s.Env.User1.Opts.From) +} + +func TestSigSuite(t *test.T) { + suite.Run(t, &sigTestSuite{}) +} diff --git a/gost/pkg/testing/token_test.go b/gost/pkg/testing/token_test.go new file mode 100644 index 0000000..5580c43 --- /dev/null +++ b/gost/pkg/testing/token_test.go @@ -0,0 +1,186 @@ +package testing + +import ( + "math/big" + test "testing" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" + "github.com/swivel-finance/gost/test/mocks" +) + +type tokenTestSuite struct { + suite.Suite + Env *Env + Dep *Dep + Erc20 *mocks.Erc20Session // *Session objects are created by the go bindings + CErc20 *mocks.CErc20Session +} + +func (s *tokenTestSuite) SetupSuite() { + var err error + + s.Env = NewEnv(big.NewInt(ONE_ETH)) // each of the wallets in the env will begin with this balance + s.Dep, err = Deploy(s.Env) + + if err != nil { + panic(err) + } + + // binding owner to both, kind of why it exists - but could be any of the env wallets + s.Erc20 = &mocks.Erc20Session{ + Contract: s.Dep.Erc20, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } + + s.CErc20 = &mocks.CErc20Session{ + Contract: s.Dep.CErc20, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } +} + +func (s *tokenTestSuite) TestApprove() { + assert := assert.New(s.T()) + // set approve to return true + tx, err := s.Erc20.ApproveReturns(true) + assert.NotNil(tx) + assert.Nil(err) + // nothing happens witout manually 'mining'... + s.Env.Blockchain.Commit() + // do an actual approval + address := common.HexToAddress("0xaBC") + amount := big.NewInt(ONE_ETH) + tx, err = s.Erc20.Approve(address, amount) + assert.NotNil(tx) + assert.Nil(err) + s.Env.Blockchain.Commit() + // check the args we passed + stored, err := s.Erc20.ApproveCalled(address) + assert.Nil(err) + assert.Equal(amount, stored) +} + +func (s *tokenTestSuite) TestTransfer() { + assert := assert.New(s.T()) + tx, err := s.Erc20.TransferReturns(true) + assert.NotNil(tx) + assert.Nil(err) + s.Env.Blockchain.Commit() + + amount := big.NewInt(ONE_ETH) + // fake transfer to user2 + tx, err = s.Erc20.Transfer( + s.Env.User2.Opts.From, + amount, + ) + assert.NotNil(tx) + assert.Nil(err) + s.Env.Blockchain.Commit() + + // mapping uses the passed address as key + stored, err := s.Erc20.TransferCalled(s.Env.User2.Opts.From) + assert.Nil(err) + assert.Equal(stored, amount) +} + +func (s *tokenTestSuite) TestTransferFrom() { + assert := assert.New(s.T()) + tx, err := s.Erc20.TransferFromReturns(true) + assert.NotNil(tx) + assert.Nil(err) + s.Env.Blockchain.Commit() + + amount := big.NewInt(ONE_ETH) + // fake transfer from user1 to owner + tx, err = s.Erc20.TransferFrom( + s.Env.User1.Opts.From, + s.Env.Owner.Opts.From, + amount, + ) + assert.NotNil(tx) + assert.Nil(err) + s.Env.Blockchain.Commit() + + // mapping uses the from address as key + stored, err := s.Erc20.TransferFromCalled(s.Env.User1.Opts.From) + assert.Nil(err) + assert.Equal(stored.To, s.Env.Owner.Opts.From) + assert.Equal(stored.Amount, amount) +} + +func (s *tokenTestSuite) TestExchangeRateCurrent() { + assert := assert.New(s.T()) + // set the amount we want the stub to return + // NOTE: an actual current exchange rate is bigger than int64 will hold + // while we could use any number in this test, shown here for posterity + amount := big.NewInt(205906566771510710) + amount = amount.Mul(amount, big.NewInt(1000000000)) + + tx, err := s.CErc20.ExchangeRateCurrentReturns(amount) + assert.NotNil(tx) + assert.Nil(err) + s.Env.Blockchain.Commit() + + // should return the stubbed amt + curr, err := s.CErc20.ExchangeRateCurrent() + assert.Nil(err) + assert.Equal(amount, curr) +} + +func (s *tokenTestSuite) TestMint() { + assert := assert.New(s.T()) + // arbitrary amount + minted := big.NewInt(ONE_GWEI) + + // not necessary for the result, but test it anyway + tx, err := s.CErc20.MintReturns(minted) + assert.NotNil(tx) + assert.Nil(err) + s.Env.Blockchain.Commit() + + // call mint() so that the args are stored + tx, err = s.CErc20.Mint(minted) + assert.NotNil(tx) + assert.Nil(err) + s.Env.Blockchain.Commit() + + stored, err := s.CErc20.MintCalled() + assert.Nil(err) + assert.Equal(minted, stored) +} + +func (s *tokenTestSuite) TestRedeemUnderlying() { + assert := assert.New(s.T()) + // arbitrary amount + redeemed := big.NewInt(ONE_GWEI) + + // compound uses 0 as 'success'. see https://compound.finance/docs/ctokens#redeem-underlying + tx, err := s.CErc20.RedeemUnderlyingReturns(big.NewInt(0)) + assert.NotNil(tx) + assert.Nil(err) + s.Env.Blockchain.Commit() + + // call redeem...() so that the args are stored + tx, err = s.CErc20.RedeemUnderlying(redeemed) + assert.NotNil(tx) + assert.Nil(err) + s.Env.Blockchain.Commit() + + stored, err := s.CErc20.RedeemUnderlyingCalled() + assert.Nil(err) + assert.Equal(redeemed, stored) +} + +func TestTokenSuite(t *test.T) { + suite.Run(t, &tokenTestSuite{}) +} diff --git a/gost/pkg/vaulttrackertesting/add_notional_test.go b/gost/pkg/vaulttrackertesting/add_notional_test.go new file mode 100644 index 0000000..be88ab8 --- /dev/null +++ b/gost/pkg/vaulttrackertesting/add_notional_test.go @@ -0,0 +1,255 @@ +package vaulttrackertesting + +import ( + "math/big" + test "testing" + "time" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + assertions "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" + "github.com/swivel-finance/gost/test/mocks" + "github.com/swivel-finance/gost/test/vaulttracker" +) + +type addNotionalSuite struct { + suite.Suite + Env *Env + Dep *Dep + CErc20 *mocks.CErc20Session + VaultTracker *vaulttracker.VaultTrackerSession // *Session objects are created by the go bindings +} + +func (s *addNotionalSuite) SetupTest() { + var err error + + s.Env = NewEnv(big.NewInt(ONE_ETH)) // each of the wallets in the env will begin with this balance + s.Dep, err = Deploy(s.Env) + if err != nil { + panic(err) + } + + err = s.Env.Blockchain.AdjustTime(0) // set bc timestamp to 0 + if err != nil { + panic(err) + } + s.Env.Blockchain.Commit() + + s.CErc20 = &mocks.CErc20Session{ + Contract: s.Dep.CErc20, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } + + // binding owner to both, kind of why it exists - but could be any of the env wallets + s.VaultTracker = &vaulttracker.VaultTrackerSession{ + Contract: s.Dep.VaultTracker, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } +} + +func (s *addNotionalSuite) TestAddNotionalCreateVault() { + assert := assertions.New(s.T()) + + rate1 := big.NewInt(123456789) + tx, err := s.CErc20.ExchangeRateCurrentReturns(rate1) + assert.Nil(err) + assert.NotNil(tx) + s.Env.Blockchain.Commit() + + // no vault found for Owner + vault, err := s.VaultTracker.Vaults(s.Env.Owner.Opts.From) + assert.Nil(err) + assert.NotNil(vault) + assert.Equal(vault.Redeemable.Cmp(ZERO), 0) + assert.Equal(vault.Notional.Cmp(ZERO), 0) + assert.Equal(vault.ExchangeRate.Cmp(ZERO),0) + + // call AddNotional for Owner with no vault + caller := s.Env.Owner.Opts.From + amount1 := big.NewInt(10000000) + redeemable1 := ZERO + tx, err = s.VaultTracker.AddNotional(caller, amount1) + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + // found vault for Owner + vault, err = s.VaultTracker.Vaults(s.Env.Owner.Opts.From) + assert.Nil(err) + assert.NotNil(vault) + assert.Equal(amount1, vault.Notional) + assert.Equal(rate1, vault.ExchangeRate) + assert.Equal(vault.Redeemable.Cmp(redeemable1), 0) +} + +func (s *addNotionalSuite) TestAddNotionalNotMatured() { + assert := assertions.New(s.T()) + + rate1 := big.NewInt(123456789) + tx, err := s.CErc20.ExchangeRateCurrentReturns(rate1) + assert.Nil(err) + assert.NotNil(tx) + s.Env.Blockchain.Commit() + + // no vault found for Owner + vault, err := s.VaultTracker.Vaults(s.Env.Owner.Opts.From) + assert.Nil(err) + assert.NotNil(vault) + assert.Equal(vault.Redeemable.Cmp(ZERO), 0) + assert.Equal(vault.Notional.Cmp(ZERO), 0) + assert.Equal(vault.ExchangeRate.Cmp(ZERO),0) + + // call AddNotional for Owner with no vault + caller := s.Env.Owner.Opts.From + amount1 := big.NewInt(10000000) + redeemable1 := ZERO + tx, err = s.VaultTracker.AddNotional(caller, amount1) + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + // found vault for Owner + vault, err = s.VaultTracker.Vaults(s.Env.Owner.Opts.From) + assert.Nil(err) + assert.NotNil(vault) + assert.Equal(amount1, vault.Notional) + assert.Equal(rate1, vault.ExchangeRate) + assert.Equal(vault.Redeemable.Cmp(redeemable1), 0) + + rate2 := big.NewInt(723456789) + tx, err = s.CErc20.ExchangeRateCurrentReturns(rate2) + assert.NotNil(tx) + assert.Nil(err) + s.Env.Blockchain.Commit() + + amount2 := big.NewInt(20000000) + redeemable2 := big.NewInt(48600000) + + // call AddNotional for Owner which already has vault and market is not matured + tx, err = s.VaultTracker.AddNotional(caller, amount1) + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + vault, err = s.VaultTracker.Vaults(s.Env.Owner.Opts.From) + assert.Nil(err) + assert.NotNil(vault) + assert.Equal(amount2, vault.Notional) + assert.Equal(rate2, vault.ExchangeRate) + assert.Equal(redeemable2, vault.Redeemable) +} + +func (s *addNotionalSuite) TestAddNotionalMatured() { + assert := assertions.New(s.T()) + + rate1 := big.NewInt(123456789) + tx, err := s.CErc20.ExchangeRateCurrentReturns(rate1) + assert.Nil(err) + assert.NotNil(tx) + s.Env.Blockchain.Commit() + + // no vault found for Owner + vault, err := s.VaultTracker.Vaults(s.Env.Owner.Opts.From) + assert.Nil(err) + assert.NotNil(vault) + assert.Equal(vault.Redeemable.Cmp(ZERO), 0) + assert.Equal(vault.Notional.Cmp(ZERO), 0) + assert.Equal(vault.ExchangeRate.Cmp(ZERO),0) + + // call AddNotional for Owner with no vault + caller := s.Env.Owner.Opts.From + amount1 := big.NewInt(10000000) + redeemable1 := ZERO + tx, err = s.VaultTracker.AddNotional(caller, amount1) + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + // found vault for Owner + vault, err = s.VaultTracker.Vaults(s.Env.Owner.Opts.From) + assert.Nil(err) + assert.NotNil(vault) + assert.Equal(amount1, vault.Notional) + assert.Equal(rate1, vault.ExchangeRate) + assert.Equal(vault.Redeemable.Cmp(redeemable1), 0) + + rate2 := big.NewInt(723456789) + tx, err = s.CErc20.ExchangeRateCurrentReturns(rate2) + assert.NotNil(tx) + assert.Nil(err) + s.Env.Blockchain.Commit() + + amount2 := big.NewInt(20000000) + redeemable2 := big.NewInt(48600000) + + // call AddNotional for Owner which already has vault and market is not matured + tx, err = s.VaultTracker.AddNotional(caller, amount1) + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + vault, err = s.VaultTracker.Vaults(s.Env.Owner.Opts.From) + assert.Nil(err) + assert.NotNil(vault) + assert.Equal(amount2, vault.Notional) + assert.Equal(rate2, vault.ExchangeRate) + assert.Equal(redeemable2, vault.Redeemable) + + rate3 := big.NewInt(823456789) + tx, err = s.CErc20.ExchangeRateCurrentReturns(rate3) + assert.NotNil(tx) + assert.Nil(err) + s.Env.Blockchain.Commit() + + // move past the maturity + err = s.Env.Blockchain.AdjustTime(MATURITY * time.Second) + assert.Nil(err) + s.Env.Blockchain.Commit() + + // call mature + tx, err = s.VaultTracker.MatureVault() + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + rate4 := big.NewInt(923456787) + tx, err = s.CErc20.ExchangeRateCurrentReturns(rate4) + assert.NotNil(tx) + assert.Nil(err) + s.Env.Blockchain.Commit() + + amount3 := big.NewInt(30000000) + redeemable3 := big.NewInt(51364505) + + // call AddNotional for Owner which already has vault and market matured + tx, err = s.VaultTracker.AddNotional(caller, amount1) + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + vault, err = s.VaultTracker.Vaults(s.Env.Owner.Opts.From) + assert.Nil(err) + assert.NotNil(vault) + assert.Equal(amount3, vault.Notional) + assert.Equal(rate4, vault.ExchangeRate) + assert.Equal(redeemable3, vault.Redeemable) +} + +func TestAddNotionalSuite(t *test.T) { + suite.Run(t, &addNotionalSuite{}) +} diff --git a/gost/pkg/vaulttrackertesting/balances_of_test.go b/gost/pkg/vaulttrackertesting/balances_of_test.go new file mode 100644 index 0000000..6e2e02b --- /dev/null +++ b/gost/pkg/vaulttrackertesting/balances_of_test.go @@ -0,0 +1,90 @@ +package vaulttrackertesting + +import ( + "math/big" + test "testing" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + assertions "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" + "github.com/swivel-finance/gost/test/mocks" + "github.com/swivel-finance/gost/test/vaulttracker" +) + +type balancesOfSuite struct { + suite.Suite + Env *Env + Dep *Dep + CErc20 *mocks.CErc20Session + VaultTracker *vaulttracker.VaultTrackerSession // *Session objects are created by the go bindings +} + +func (s *balancesOfSuite) SetupTest() { + var err error + + s.Env = NewEnv(big.NewInt(ONE_ETH)) // each of the wallets in the env will begin with this balance + s.Dep, err = Deploy(s.Env) + if err != nil { + panic(err) + } + + err = s.Env.Blockchain.AdjustTime(0) // set bc timestamp to 0 + if err != nil { + panic(err) + } + s.Env.Blockchain.Commit() + + s.CErc20 = &mocks.CErc20Session{ + Contract: s.Dep.CErc20, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } + + // binding owner to both, kind of why it exists - but could be any of the env wallets + s.VaultTracker = &vaulttracker.VaultTrackerSession{ + Contract: s.Dep.VaultTracker, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } +} + +func (s *balancesOfSuite) TestBalancesOf() { + assert := assertions.New(s.T()) + + rate1 := big.NewInt(123456789) + tx, err := s.CErc20.ExchangeRateCurrentReturns(rate1) + assert.Nil(err) + assert.NotNil(tx) + s.Env.Blockchain.Commit() + + // balance of the Owner + notional, redeemable, err := s.VaultTracker.BalancesOf(s.Env.Owner.Opts.From) + assert.Nil(err) + assert.Equal(notional.Cmp(redeemable), 0) + assert.Equal(redeemable.Cmp(ZERO), 0) + + // call AddNotional for Owner with no vault + caller := s.Env.Owner.Opts.From + amount := big.NewInt(10000000) + tx, err = s.VaultTracker.AddNotional(caller, amount) + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + // balance of the Owner + notional, redeemable, err = s.VaultTracker.BalancesOf(s.Env.Owner.Opts.From) + assert.Nil(err) + assert.Equal(amount, notional) + assert.Equal(redeemable.Cmp(ZERO), 0) +} + +func TestBalancesOfSuite(t *test.T) { + suite.Run(t, &balancesOfSuite{}) +} diff --git a/gost/pkg/vaulttrackertesting/constants.go b/gost/pkg/vaulttrackertesting/constants.go new file mode 100644 index 0000000..5f25161 --- /dev/null +++ b/gost/pkg/vaulttrackertesting/constants.go @@ -0,0 +1,13 @@ +package vaulttrackertesting + +import "math/big" + +const ONE_ETH = 1000000000000000000 + +var ZERO = big.NewInt(0) + +// MATURITY is one day, in seconds +const MATURITY = 86400 + +// REDEEM_INTEREST_EVENT_SIG = crypto.Keccak256Hash([]byte("RedeemInterest(address,uint256))").Hex() +const REDEEM_INTEREST_EVENT_SIG = "0x83a945bd12c713615b59a6e48a3467c05d1a7442350600d6f7fce6af9f7190e9" \ No newline at end of file diff --git a/gost/pkg/vaulttrackertesting/dep.go b/gost/pkg/vaulttrackertesting/dep.go new file mode 100644 index 0000000..7691e9c --- /dev/null +++ b/gost/pkg/vaulttrackertesting/dep.go @@ -0,0 +1,59 @@ +package vaulttrackertesting + +import ( + "math/big" + + "github.com/ethereum/go-ethereum/common" + "github.com/swivel-finance/gost/test/mocks" + "github.com/swivel-finance/gost/test/vaulttracker" +) + +type Dep struct { + CErc20 *mocks.CErc20 + CErc20Address common.Address + + SwivelAddress common.Address + + VaultTracker *vaulttracker.VaultTracker + VaultTrackerAddress common.Address + + Maturity *big.Int +} + +func Deploy(e *Env) (*Dep, error) { + maturity := big.NewInt(MATURITY) + cercAddress, _, cercContract, cercErr := mocks.DeployCErc20(e.Owner.Opts, e.Blockchain) + + if cercErr != nil { + return nil, cercErr + } + + e.Blockchain.Commit() + + // vaultTracker expects a swivel address passed to it + swivelAddress := common.HexToAddress("0xAbC123") + + // deploy contract... + trackerAddress, _, trackerContract, trackerErr := vaulttracker.DeployVaultTracker( + e.Owner.Opts, + e.Blockchain, + maturity, + cercAddress, + swivelAddress, + ) + + if trackerErr != nil { + return nil, trackerErr + } + + e.Blockchain.Commit() + + return &Dep{ + SwivelAddress: swivelAddress, + VaultTrackerAddress: trackerAddress, + VaultTracker: trackerContract, + Maturity: maturity, + CErc20: cercContract, + CErc20Address: cercAddress, + }, nil +} diff --git a/gost/pkg/vaulttrackertesting/env.go b/gost/pkg/vaulttrackertesting/env.go new file mode 100644 index 0000000..3651c22 --- /dev/null +++ b/gost/pkg/vaulttrackertesting/env.go @@ -0,0 +1,52 @@ +package vaulttrackertesting + +import ( + "crypto/ecdsa" + "math/big" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/accounts/abi/bind/backends" + "github.com/ethereum/go-ethereum/core" + "github.com/swivel-finance/gost/internal/helpers" +) + +// Auth is a custom type which allows us easy access to the dynamically generated +// ecdsa.PrivateKey along with the bind.TransactOpts +type Auth struct { + PK *ecdsa.PrivateKey + Opts *bind.TransactOpts +} + +// Env, holds Auth objects capable of signing transactions. +// Also holds the Geth simulated backend. +type Env struct { + Alloc core.GenesisAlloc + // TODO maybe change to Admin to fit v2 contract terms... + Owner *Auth + User1 *Auth + User2 *Auth + Blockchain *backends.SimulatedBackend +} + +// NewEnv returns a hydrated Env struct, ready for use. +// Given a balance argument, it assigns this as the wallet balance for +// each authorization object in the Ctx +func NewEnv(b *big.Int) *Env { + pk, owner := helpers.NewAuth() + pk1, u1 := helpers.NewAuth() + pk2, u2 := helpers.NewAuth() + alloc := make(core.GenesisAlloc) + alloc[owner.From] = core.GenesisAccount{Balance: b} + alloc[u1.From] = core.GenesisAccount{Balance: b} + alloc[u2.From] = core.GenesisAccount{Balance: b} + // 2nd arg is a gas limit, a uint64. we'll use 4.7 million + bc := backends.NewSimulatedBackend(alloc, 4700000) + + return &Env{ + Alloc: alloc, + Owner: &Auth{PK: pk, Opts: owner}, + User1: &Auth{PK: pk1, Opts: u1}, + User2: &Auth{PK: pk2, Opts: u2}, + Blockchain: bc, + } +} diff --git a/gost/pkg/vaulttrackertesting/mature_vault_test.go b/gost/pkg/vaulttrackertesting/mature_vault_test.go new file mode 100644 index 0000000..1a05de3 --- /dev/null +++ b/gost/pkg/vaulttrackertesting/mature_vault_test.go @@ -0,0 +1,104 @@ +package vaulttrackertesting + +import ( + "math/big" + test "testing" + "time" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + assertions "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" + "github.com/swivel-finance/gost/test/mocks" + "github.com/swivel-finance/gost/test/vaulttracker" +) + +type matureVaultSuite struct { + suite.Suite + Env *Env + Dep *Dep + CErc20 *mocks.CErc20Session + VaultTracker *vaulttracker.VaultTrackerSession // *Session objects are created by the go bindings +} + +func (s *matureVaultSuite) SetupTest() { + var err error + + s.Env = NewEnv(big.NewInt(ONE_ETH)) // each of the wallets in the env will begin with this balance + s.Dep, err = Deploy(s.Env) + if err != nil { + panic(err) + } + + err = s.Env.Blockchain.AdjustTime(0) // set bc timestamp to 0 + if err != nil { + panic(err) + } + s.Env.Blockchain.Commit() + + s.CErc20 = &mocks.CErc20Session{ + Contract: s.Dep.CErc20, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } + + // binding owner to both, kind of why it exists - but could be any of the env wallets + s.VaultTracker = &vaulttracker.VaultTrackerSession{ + Contract: s.Dep.VaultTracker, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } +} + +func (s *matureVaultSuite) TestMatureVaultRequireFail() { + assert := assertions.New(s.T()) + + rate1 := big.NewInt(123456789) + tx, err := s.CErc20.ExchangeRateCurrentReturns(rate1) + assert.Nil(err) + assert.NotNil(tx) + s.Env.Blockchain.Commit() + + tx, err = s.VaultTracker.MatureVault() + assert.NotNil(err) + assert.Regexp("maturity has not been reached", err.Error()) + assert.Nil(tx) + + s.Env.Blockchain.Commit() +} + +func (s *matureVaultSuite) TestMatureVaultRequirePasses() { + assert := assertions.New(s.T()) + + rate1 := big.NewInt(123456789) + tx, err := s.CErc20.ExchangeRateCurrentReturns(rate1) + assert.Nil(err) + assert.NotNil(tx) + s.Env.Blockchain.Commit() + + // move past the maturity + err = s.Env.Blockchain.AdjustTime(MATURITY * time.Second) + assert.Nil(err) + s.Env.Blockchain.Commit() + + tx, err = s.VaultTracker.MatureVault() + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + // any further calls to mature the vault should fail + tx, err = s.VaultTracker.MatureVault() + assert.Nil(tx) + assert.NotNil(err) + assert.Regexp("already mature", err.Error()) +} + +func TestTrackerMatureVaultSuite(t *test.T) { + suite.Run(t, &matureVaultSuite{}) +} diff --git a/gost/pkg/vaulttrackertesting/redeem_interest_test.go b/gost/pkg/vaulttrackertesting/redeem_interest_test.go new file mode 100644 index 0000000..d688c00 --- /dev/null +++ b/gost/pkg/vaulttrackertesting/redeem_interest_test.go @@ -0,0 +1,257 @@ +package vaulttrackertesting + +import ( + // "context" + // "github.com/ethereum/go-ethereum/common" + "math/big" + test "testing" + "time" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + assertions "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" + "github.com/swivel-finance/gost/test/mocks" + "github.com/swivel-finance/gost/test/vaulttracker" +) + +type redeemInterestSuite struct { + suite.Suite + Env *Env + Dep *Dep + CErc20 *mocks.CErc20Session + VaultTracker *vaulttracker.VaultTrackerSession +} + +func (s *redeemInterestSuite) SetupTest() { + var err error + + s.Env = NewEnv(big.NewInt(ONE_ETH)) // each of the wallets in the env will begin with this balance + s.Dep, err = Deploy(s.Env) + if err != nil { + panic(err) + } + + err = s.Env.Blockchain.AdjustTime(0) // set bc timestamp to 0 + if err != nil { + panic(err) + } + s.Env.Blockchain.Commit() + + s.CErc20 = &mocks.CErc20Session{ + Contract: s.Dep.CErc20, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } + + s.VaultTracker = &vaulttracker.VaultTrackerSession{ + Contract: s.Dep.VaultTracker, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } +} + +func (s *redeemInterestSuite) TestRedeemInterestNotMatured() { + assert := assertions.New(s.T()) + + rate1 := big.NewInt(123456789) + tx, err := s.CErc20.ExchangeRateCurrentReturns(rate1) + assert.Nil(err) + assert.NotNil(tx) + s.Env.Blockchain.Commit() + + // no vault found for Owner + vault, err := s.VaultTracker.Vaults(s.Env.Owner.Opts.From) + assert.Nil(err) + assert.NotNil(vault) + assert.Equal(vault.Redeemable.Cmp(ZERO), 0) + assert.Equal(vault.Notional.Cmp(ZERO), 0) + assert.Equal(vault.ExchangeRate.Cmp(ZERO), 0) + + // call AddNotional for Owner with no vault + caller := s.Env.Owner.Opts.From + amount1 := big.NewInt(10000000) + redeemable1 := ZERO + tx, err = s.VaultTracker.AddNotional(caller, amount1) + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + // found vault for Owner + vault, err = s.VaultTracker.Vaults(s.Env.Owner.Opts.From) + assert.Nil(err) + assert.NotNil(vault) + assert.Equal(amount1, vault.Notional) + assert.Equal(rate1, vault.ExchangeRate) + assert.Equal(vault.Redeemable.Cmp(redeemable1), 0) + + rate2 := big.NewInt(723456789) + tx, err = s.CErc20.ExchangeRateCurrentReturns(rate2) + assert.NotNil(tx) + assert.Nil(err) + s.Env.Blockchain.Commit() + + amount2 := big.NewInt(20000000) + redeemable2 := big.NewInt(48600000) + + // call AddNotional for Owner which already has vault and market is not matured + tx, err = s.VaultTracker.AddNotional(caller, amount1) + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + vault, err = s.VaultTracker.Vaults(s.Env.Owner.Opts.From) + assert.Nil(err) + assert.NotNil(vault) + assert.Equal(amount2, vault.Notional) + assert.Equal(rate2, vault.ExchangeRate) + assert.Equal(redeemable2, vault.Redeemable) + + rate3 := big.NewInt(823456789) + tx, err = s.CErc20.ExchangeRateCurrentReturns(rate3) + assert.NotNil(tx) + assert.Nil(err) + s.Env.Blockchain.Commit() + + // redeem interest using rate3 + tx, err = s.VaultTracker.RedeemInterest(caller) + assert.Nil(err) + assert.NotNil(tx) + s.Env.Blockchain.Commit() + + // receipt, err := s.Env.Blockchain.TransactionReceipt(context.Background(), tx.Hash()) + // assert.Nil(err) + // assert.NotNil(receipt) + + // logs := receipt.Logs + // assert.NotNil(logs) + // assert.Equal(1, len(logs)) + + // assert.Equal(REDEEM_INTEREST_EVENT_SIG, logs[0].Topics[0].Hex()) + // assert.Equal(caller.Hex(), common.HexToAddress(logs[0].Topics[1].Hex()).String()) + // assert.Equal(big.NewInt(51364505), logs[0].Topics[2].Big()) + + vault, err = s.VaultTracker.Vaults(s.Env.Owner.Opts.From) + assert.Nil(err) + assert.NotNil(vault) + assert.Equal(amount2, vault.Notional) + assert.Equal(rate3, vault.ExchangeRate) + assert.Equal(vault.Redeemable.Cmp(ZERO), 0) +} + +func (s *redeemInterestSuite) TestRedeemInterestMatured() { + assert := assertions.New(s.T()) + + rate1 := big.NewInt(123456789) + tx, err := s.CErc20.ExchangeRateCurrentReturns(rate1) + assert.Nil(err) + assert.NotNil(tx) + s.Env.Blockchain.Commit() + + // no vault found for Owner + vault, err := s.VaultTracker.Vaults(s.Env.Owner.Opts.From) + assert.Nil(err) + assert.NotNil(vault) + assert.Equal(vault.Redeemable.Cmp(ZERO), 0) + assert.Equal(vault.Notional.Cmp(ZERO), 0) + assert.Equal(vault.ExchangeRate.Cmp(ZERO), 0) + + // call AddNotional for Owner with no vault + caller := s.Env.Owner.Opts.From + amount1 := big.NewInt(10000000) + redeemable1 := ZERO + tx, err = s.VaultTracker.AddNotional(caller, amount1) + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + // found vault for Owner + vault, err = s.VaultTracker.Vaults(s.Env.Owner.Opts.From) + assert.Nil(err) + assert.NotNil(vault) + assert.Equal(amount1, vault.Notional) + assert.Equal(rate1, vault.ExchangeRate) + assert.Equal(vault.Redeemable.Cmp(redeemable1), 0) + + rate2 := big.NewInt(723456789) + tx, err = s.CErc20.ExchangeRateCurrentReturns(rate2) + assert.NotNil(tx) + assert.Nil(err) + s.Env.Blockchain.Commit() + + amount2 := big.NewInt(20000000) + redeemable2 := big.NewInt(48600000) + + // call AddNotional for Owner which already has vault and market is not matured + tx, err = s.VaultTracker.AddNotional(caller, amount1) + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + vault, err = s.VaultTracker.Vaults(s.Env.Owner.Opts.From) + assert.Nil(err) + assert.NotNil(vault) + assert.Equal(amount2, vault.Notional) + assert.Equal(rate2, vault.ExchangeRate) + assert.Equal(redeemable2, vault.Redeemable) + + rate3 := big.NewInt(823456789) + tx, err = s.CErc20.ExchangeRateCurrentReturns(rate3) + assert.NotNil(tx) + assert.Nil(err) + s.Env.Blockchain.Commit() + + // move past the maturity + err = s.Env.Blockchain.AdjustTime(MATURITY * time.Second) + assert.Nil(err) + s.Env.Blockchain.Commit() + + // call mature + tx, err = s.VaultTracker.MatureVault() + assert.Nil(err) + assert.NotNil(tx) + + rate4 := big.NewInt(923456789) + tx, err = s.CErc20.ExchangeRateCurrentReturns(rate4) + assert.NotNil(tx) + assert.Nil(err) + s.Env.Blockchain.Commit() + + // redeem interest using rate3 (maturityRate) + tx, err = s.VaultTracker.RedeemInterest(caller) + assert.Nil(err) + assert.NotNil(tx) + s.Env.Blockchain.Commit() + + // receipt, err := s.Env.Blockchain.TransactionReceipt(context.Background(), tx.Hash()) + // assert.Nil(err) + // assert.NotNil(receipt) + + // logs := receipt.Logs + // assert.NotNil(logs) + // assert.Equal(1, len(logs)) + + // assert.Equal(REDEEM_INTEREST_EVENT_SIG, logs[0].Topics[0].Hex()) + // assert.Equal(caller.Hex(), common.HexToAddress(logs[0].Topics[1].Hex()).String()) + // assert.Equal(big.NewInt(51364505), logs[0].Topics[2].Big()) + + vault, err = s.VaultTracker.Vaults(s.Env.Owner.Opts.From) + assert.Nil(err) + assert.NotNil(vault) + assert.Equal(amount2, vault.Notional) + assert.Equal(rate4, vault.ExchangeRate) + assert.Equal(vault.Redeemable.Cmp(ZERO), 0) +} + +func TestRedeemInterestSuite(t *test.T) { + suite.Run(t, &redeemInterestSuite{}) +} diff --git a/gost/pkg/vaulttrackertesting/remove_notional_test.go b/gost/pkg/vaulttrackertesting/remove_notional_test.go new file mode 100644 index 0000000..43f3091 --- /dev/null +++ b/gost/pkg/vaulttrackertesting/remove_notional_test.go @@ -0,0 +1,217 @@ +package vaulttrackertesting + +import ( + "math/big" + test "testing" + "time" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + assertions "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" + "github.com/swivel-finance/gost/test/mocks" + "github.com/swivel-finance/gost/test/vaulttracker" +) + +type removeNotionalSuite struct { + suite.Suite + Env *Env + Dep *Dep + CErc20 *mocks.CErc20Session + VaultTracker *vaulttracker.VaultTrackerSession // *Session objects are created by the go bindings +} + +func (s *removeNotionalSuite) SetupTest() { + var err error + + s.Env = NewEnv(big.NewInt(ONE_ETH)) // each of the wallets in the env will begin with this balance + s.Dep, err = Deploy(s.Env) + if err != nil { + panic(err) + } + + err = s.Env.Blockchain.AdjustTime(0) // set bc timestamp to 0 + if err != nil { + panic(err) + } + s.Env.Blockchain.Commit() + + s.CErc20 = &mocks.CErc20Session{ + Contract: s.Dep.CErc20, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } + + // binding owner to both, kind of why it exists - but could be any of the env wallets + s.VaultTracker = &vaulttracker.VaultTrackerSession{ + Contract: s.Dep.VaultTracker, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } +} + +func (s *removeNotionalSuite) TestRemoveNotionalFailRequireAmount() { + assert := assertions.New(s.T()) + + rate1 := big.NewInt(123456789) + tx, err := s.CErc20.ExchangeRateCurrentReturns(rate1) + assert.Nil(err) + assert.NotNil(tx) + s.Env.Blockchain.Commit() + + // no vault found for Owner + vault, err := s.VaultTracker.Vaults(s.Env.Owner.Opts.From) + assert.Nil(err) + assert.NotNil(vault) + assert.Equal(vault.Redeemable.Cmp(ZERO), 0) + assert.Equal(vault.Notional.Cmp(ZERO), 0) + assert.Equal(vault.ExchangeRate.Cmp(ZERO),0) + + // call AddNotional for Owner with no vault and add "small" amount + caller := s.Env.Owner.Opts.From + amount1 := big.NewInt(1) + tx, err = s.VaultTracker.AddNotional(caller, amount1) + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + // call RemoveNotional for Owner with vault amount lower than removal amount + caller = s.Env.Owner.Opts.From + amount2 := big.NewInt(1000) + tx, err = s.VaultTracker.RemoveNotional(caller, amount2) + assert.NotNil(err) + assert.Regexp("amount exceeds vault balance", err.Error()) + assert.Nil(tx) + + s.Env.Blockchain.Commit() +} + +func (s *removeNotionalSuite) TestRemoveNotionalNotMatured() { + assert := assertions.New(s.T()) + + rate1 := big.NewInt(123456789) + tx, err := s.CErc20.ExchangeRateCurrentReturns(rate1) + assert.Nil(err) + assert.NotNil(tx) + s.Env.Blockchain.Commit() + + // no vault found for Owner + vault, err := s.VaultTracker.Vaults(s.Env.Owner.Opts.From) + assert.Nil(err) + assert.NotNil(vault) + assert.Equal(vault.Redeemable.Cmp(ZERO), 0) + assert.Equal(vault.Notional.Cmp(ZERO), 0) + assert.Equal(vault.ExchangeRate.Cmp(ZERO),0) + + // call AddNotional for Owner with no vault + caller := s.Env.Owner.Opts.From + amount1 := big.NewInt(10000000) + tx, err = s.VaultTracker.AddNotional(caller, amount1) + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + rate2 := big.NewInt(723456789) + tx, err = s.CErc20.ExchangeRateCurrentReturns(rate2) + assert.NotNil(tx) + assert.Nil(err) + s.Env.Blockchain.Commit() + + // call RemoveNotional for Owner with vault amount lower than removal amount + caller = s.Env.Owner.Opts.From + amount2 := big.NewInt(1000) + tx, err = s.VaultTracker.RemoveNotional(caller, amount2) + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + vault, err = s.VaultTracker.Vaults(s.Env.Owner.Opts.From) + assert.Nil(err) + assert.NotNil(vault) + assert.Equal(big.NewInt(9999000), vault.Notional) + assert.Equal(rate2, vault.ExchangeRate) + assert.Equal(big.NewInt(48600000), vault.Redeemable) +} + +func (s *removeNotionalSuite) TestRemoveNotionalMatured() { + assert := assertions.New(s.T()) + + rate1 := big.NewInt(123456789) + tx, err := s.CErc20.ExchangeRateCurrentReturns(rate1) + assert.Nil(err) + assert.NotNil(tx) + s.Env.Blockchain.Commit() + + // no vault found for Owner + vault, err := s.VaultTracker.Vaults(s.Env.Owner.Opts.From) + assert.Nil(err) + assert.NotNil(vault) + assert.Equal(vault.Redeemable.Cmp(ZERO), 0) + assert.Equal(vault.Notional.Cmp(ZERO), 0) + assert.Equal(vault.ExchangeRate.Cmp(ZERO),0) + + // call AddNotional for Owner with no vault and add "small" amount + caller := s.Env.Owner.Opts.From + amount1 := big.NewInt(10000000) + tx, err = s.VaultTracker.AddNotional(caller, amount1) + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + rate2 := big.NewInt(723456789) + tx, err = s.CErc20.ExchangeRateCurrentReturns(rate2) + assert.NotNil(tx) + assert.Nil(err) + s.Env.Blockchain.Commit() + + rate3 := big.NewInt(823456789) + tx, err = s.CErc20.ExchangeRateCurrentReturns(rate3) + assert.NotNil(tx) + assert.Nil(err) + s.Env.Blockchain.Commit() + + // move past the maturity + err = s.Env.Blockchain.AdjustTime(MATURITY * time.Second) + assert.Nil(err) + s.Env.Blockchain.Commit() + + // call mature + tx, err = s.VaultTracker.MatureVault() + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + rate4 := big.NewInt(923456787) + tx, err = s.CErc20.ExchangeRateCurrentReturns(rate4) + assert.NotNil(tx) + assert.Nil(err) + s.Env.Blockchain.Commit() + + // call AddNotional for Owner which already has vault and market matured + tx, err = s.VaultTracker.RemoveNotional(caller, amount1) + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + vault, err = s.VaultTracker.Vaults(s.Env.Owner.Opts.From) + assert.Nil(err) + assert.NotNil(vault) + assert.Equal(vault.Notional.Cmp(ZERO),0) + assert.Equal(rate4, vault.ExchangeRate) + assert.Equal(big.NewInt(56700000), vault.Redeemable) +} + +func TestTrackerRemoveNotionalSuite(t *test.T) { + suite.Run(t, &removeNotionalSuite{}) +} diff --git a/gost/pkg/vaulttrackertesting/transfer_notional_fee_test.go b/gost/pkg/vaulttrackertesting/transfer_notional_fee_test.go new file mode 100644 index 0000000..23c4848 --- /dev/null +++ b/gost/pkg/vaulttrackertesting/transfer_notional_fee_test.go @@ -0,0 +1,93 @@ +package vaulttrackertesting + +import ( + "math/big" + test "testing" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + assertions "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" + "github.com/swivel-finance/gost/test/mocks" + "github.com/swivel-finance/gost/test/vaulttracker" +) + +type transferNotionalFeeSuite struct { + suite.Suite + Env *Env + Dep *Dep + CErc20 *mocks.CErc20Session + VaultTracker *vaulttracker.VaultTrackerSession +} + +func (s *transferNotionalFeeSuite) SetupTest() { + var err error + assert := assertions.New(s.T()) + + s.Env = NewEnv(big.NewInt(ONE_ETH)) + s.Dep, err = Deploy(s.Env) + assert.Nil(err) + + err = s.Env.Blockchain.AdjustTime(0) // set bc timestamp to 0 + assert.Nil(err) + s.Env.Blockchain.Commit() + + s.CErc20 = &mocks.CErc20Session{ + Contract: s.Dep.CErc20, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } + + // binding owner to both, kind of why it exists - but could be any of the env wallets + s.VaultTracker = &vaulttracker.VaultTrackerSession{ + Contract: s.Dep.VaultTracker, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } +} + +func (s *transferNotionalFeeSuite) TestTransferNotionalFee() { + assert := assertions.New(s.T()) + + rate1 := big.NewInt(123456789) + tx, err := s.CErc20.ExchangeRateCurrentReturns(rate1) + assert.Nil(err) + assert.NotNil(tx) + s.Env.Blockchain.Commit() + + // user needs funds in their vault + userVaultAmt := big.NewInt(1000) + userFee := big.NewInt(500) + + tx, err = s.VaultTracker.AddNotional(s.Env.User1.Opts.From, userVaultAmt) + assert.Nil(err) + assert.NotNil(tx) + s.Env.Blockchain.Commit() + + // transfer from user to swivel, which will have no vault up til now... + tx, err = s.VaultTracker.TransferNotionalFee(s.Env.User1.Opts.From, userFee) + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + swiVault, err := s.VaultTracker.Vaults(s.Dep.SwivelAddress) + assert.Nil(err) + assert.NotNil(swiVault) + assert.Equal(swiVault.Notional, userFee) + // s.T().Log(swiVault.Notional) + + userVault, err := s.VaultTracker.Vaults(s.Env.User1.Opts.From) + assert.Nil(err) + assert.NotNil(userVault) + assert.Equal(userFee, userVault.Notional) +} + +func TestTrackerTransferNotionalFeeSuite(t *test.T) { + suite.Run(t, &transferNotionalFeeSuite{}) +} diff --git a/gost/pkg/vaulttrackertesting/transfer_notional_from_test.go b/gost/pkg/vaulttrackertesting/transfer_notional_from_test.go new file mode 100644 index 0000000..d929954 --- /dev/null +++ b/gost/pkg/vaulttrackertesting/transfer_notional_from_test.go @@ -0,0 +1,138 @@ +package vaulttrackertesting + +import ( + "math/big" + test "testing" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + assertions "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" + "github.com/swivel-finance/gost/test/mocks" + "github.com/swivel-finance/gost/test/vaulttracker" +) + +type transferNotionalFromSuite struct { + suite.Suite + Env *Env + Dep *Dep + CErc20 *mocks.CErc20Session + VaultTracker *vaulttracker.VaultTrackerSession // *Session objects are created by the go bindings +} + +func (s *transferNotionalFromSuite) SetupTest() { + var err error + + s.Env = NewEnv(big.NewInt(ONE_ETH)) // each of the wallets in the env will begin with this balance + s.Dep, err = Deploy(s.Env) + if err != nil { + panic(err) + } + + err = s.Env.Blockchain.AdjustTime(0) // set bc timestamp to 0 + if err != nil { + panic(err) + } + s.Env.Blockchain.Commit() + + s.CErc20 = &mocks.CErc20Session{ + Contract: s.Dep.CErc20, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } + + // binding owner to both, kind of why it exists - but could be any of the env wallets + s.VaultTracker = &vaulttracker.VaultTrackerSession{ + Contract: s.Dep.VaultTracker, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } +} + +func (s *transferNotionalFromSuite) TestTransferNotionalFrom() { + assert := assertions.New(s.T()) + + rate1 := big.NewInt(123456789) + tx, err := s.CErc20.ExchangeRateCurrentReturns(rate1) + assert.Nil(err) + assert.NotNil(tx) + s.Env.Blockchain.Commit() + + // call AddNotional for Owner with no ownerVault + amount1 := big.NewInt(1000) + tx, err = s.VaultTracker.AddNotional(s.Env.Owner.Opts.From, amount1) + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + // call AddNotional for User1 with no ownerVault + amount2 := big.NewInt(1000) + tx, err = s.VaultTracker.AddNotional(s.Env.User1.Opts.From, amount2) + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + tx, err = s.VaultTracker.TransferNotionalFrom(s.Env.Owner.Opts.From, s.Env.User1.Opts.From, big.NewInt(100)) + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + ownerVault, err := s.VaultTracker.Vaults(s.Env.Owner.Opts.From) + assert.Nil(err) + assert.NotNil(ownerVault) + assert.Equal(big.NewInt(900), ownerVault.Notional) + assert.Equal(rate1, ownerVault.ExchangeRate) + assert.Equal(ownerVault.Redeemable.Cmp(ZERO), 0) + + user1Vault, err := s.VaultTracker.Vaults(s.Env.User1.Opts.From) + assert.Nil(err) + assert.NotNil(user1Vault) + assert.Equal(big.NewInt(1100), user1Vault.Notional) + assert.Equal(rate1, user1Vault.ExchangeRate) + assert.Equal(user1Vault.Redeemable.Cmp(ZERO), 0) +} + +func (s *transferNotionalFromSuite) TestTransferNotionalFromAmountExceedsFail() { + assert := assertions.New(s.T()) + + rate1 := big.NewInt(123456789) + tx, err := s.CErc20.ExchangeRateCurrentReturns(rate1) + assert.Nil(err) + assert.NotNil(tx) + s.Env.Blockchain.Commit() + + // call AddNotional for Owner with no ownerVault + amount1 := big.NewInt(1000) + tx, err = s.VaultTracker.AddNotional(s.Env.Owner.Opts.From, amount1) + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + // call AddNotional for User1 with no ownerVault + amount2 := big.NewInt(1000) + tx, err = s.VaultTracker.AddNotional(s.Env.User1.Opts.From, amount2) + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + tx, err = s.VaultTracker.TransferNotionalFrom(s.Env.Owner.Opts.From, s.Env.User1.Opts.From, big.NewInt(2000)) + assert.NotNil(err) + assert.Regexp("amount exceeds available balance", err.Error()) + assert.Nil(tx) + + s.Env.Blockchain.Commit() +} + +func TestTrackerTransferNotionalFromSuite(t *test.T) { + suite.Run(t, &transferNotionalFromSuite{}) +} diff --git a/gost/pkg/vaulttrackertesting/transfer_notional_test.go b/gost/pkg/vaulttrackertesting/transfer_notional_test.go new file mode 100644 index 0000000..73c28af --- /dev/null +++ b/gost/pkg/vaulttrackertesting/transfer_notional_test.go @@ -0,0 +1,521 @@ +package vaulttrackertesting + +import ( + "math/big" + test "testing" + "time" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + assertions "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" + "github.com/swivel-finance/gost/test/mocks" + "github.com/swivel-finance/gost/test/vaulttracker" +) + +// NOTE: the transferNotional method was removed in favor of only having transferNotionalFrom. +// Keeping this spec here however, and just changing the reference. + +type transferSuite struct { + suite.Suite + Env *Env + Dep *Dep + CErc20 *mocks.CErc20Session + VaultTracker *vaulttracker.VaultTrackerSession // *Session objects are created by the go bindings +} + +func (s *transferSuite) SetupTest() { + var err error + + s.Env = NewEnv(big.NewInt(ONE_ETH)) // each of the wallets in the env will begin with this balance + s.Dep, err = Deploy(s.Env) + if err != nil { + panic(err) + } + + err = s.Env.Blockchain.AdjustTime(0) // set bc timestamp to 0 + if err != nil { + panic(err) + } + s.Env.Blockchain.Commit() + + s.CErc20 = &mocks.CErc20Session{ + Contract: s.Dep.CErc20, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } + + // binding owner to both, kind of why it exists - but could be any of the env wallets + s.VaultTracker = &vaulttracker.VaultTrackerSession{ + Contract: s.Dep.VaultTracker, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } +} + +func (s *transferSuite) TestTransferFailRequireAmount() { + assert := assertions.New(s.T()) + + rate1 := big.NewInt(123456789) + tx, err := s.CErc20.ExchangeRateCurrentReturns(rate1) + assert.Nil(err) + assert.NotNil(tx) + s.Env.Blockchain.Commit() + + // no vault found for Owner + vault, err := s.VaultTracker.Vaults(s.Env.Owner.Opts.From) + assert.Nil(err) + assert.NotNil(vault) + assert.Equal(vault.Redeemable.Cmp(ZERO), 0) + assert.Equal(vault.Notional.Cmp(ZERO), 0) + assert.Equal(vault.ExchangeRate.Cmp(ZERO), 0) + + // call AddNotional for Owner with no vault and add "small" amount + caller := s.Env.Owner.Opts.From + amount1 := big.NewInt(1) + tx, err = s.VaultTracker.AddNotional(caller, amount1) + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + // call RemoveNotional for Owner with vault amount lower than removal amount + // caller = s.Env.Owner.Opts.From + amount2 := big.NewInt(1000) + tx, err = s.VaultTracker.TransferNotionalFrom(caller, s.Env.User1.Opts.From, amount2) + assert.NotNil(err) + assert.Regexp("amount exceeds available balance", err.Error()) + assert.Nil(tx) + + s.Env.Blockchain.Commit() +} + +func (s *transferSuite) TestTransferNotMaturedNotExistingVault() { + assert := assertions.New(s.T()) + + rate1 := big.NewInt(123456789) + tx, err := s.CErc20.ExchangeRateCurrentReturns(rate1) + assert.Nil(err) + assert.NotNil(tx) + s.Env.Blockchain.Commit() + + // no vault found for Owner + vaultO, err := s.VaultTracker.Vaults(s.Env.Owner.Opts.From) + assert.Nil(err) + assert.NotNil(vaultO) + assert.Equal(vaultO.Redeemable.Cmp(ZERO), 0) + assert.Equal(vaultO.Notional.Cmp(ZERO), 0) + assert.Equal(vaultO.ExchangeRate.Cmp(ZERO), 0) + + // call AddNotional for Owner + callerO := s.Env.Owner.Opts.From + tx, err = s.VaultTracker.AddNotional(callerO, big.NewInt(1000)) + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + // found vault for Owner + vaultO, err = s.VaultTracker.Vaults(s.Env.Owner.Opts.From) + assert.Nil(err) + assert.NotNil(vaultO) + assert.Equal(big.NewInt(1000), vaultO.Notional) + assert.Equal(rate1, vaultO.ExchangeRate) + assert.Equal(vaultO.Redeemable.Cmp(ZERO), 0) + + rate2 := big.NewInt(223456789) + tx, err = s.CErc20.ExchangeRateCurrentReturns(rate2) + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + tx, err = s.VaultTracker.AddNotional(callerO, big.NewInt(1000)) + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + vaultO, err = s.VaultTracker.Vaults(callerO) + assert.Nil(err) + assert.NotNil(vaultO) + assert.Equal(big.NewInt(2000), vaultO.Notional) + assert.Equal(rate2, vaultO.ExchangeRate) + assert.Equal(vaultO.Redeemable.Cmp(big.NewInt(810)), 0) + + // no vault found for User1 + vaultU, err := s.VaultTracker.Vaults(s.Env.User1.Opts.From) + assert.Nil(err) + assert.NotNil(vaultU) + assert.Equal(vaultU.Redeemable.Cmp(ZERO), 0) + assert.Equal(vaultU.Notional.Cmp(ZERO), 0) + assert.Equal(vaultU.ExchangeRate.Cmp(ZERO), 0) + + rate3 := big.NewInt(323456789) + tx, err = s.CErc20.ExchangeRateCurrentReturns(rate3) + assert.Nil(err) + assert.NotNil(tx) + + // call Transfer Owner -> User1 + transferAmount := big.NewInt(500) + tx, err = s.VaultTracker.TransferNotionalFrom(callerO, s.Env.User1.Opts.From, transferAmount) + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + vaultO, err = s.VaultTracker.Vaults(callerO) + assert.Nil(err) + assert.NotNil(vaultO) + assert.Equal(big.NewInt(1500), vaultO.Notional) + assert.Equal(rate3, vaultO.ExchangeRate) + assert.Equal(vaultO.Redeemable.Cmp(big.NewInt(1705)), 0) + + vaultU, err = s.VaultTracker.Vaults(s.Env.User1.Opts.From) + assert.Nil(err) + assert.NotNil(vaultU) + assert.Equal(big.NewInt(500), vaultU.Notional) + assert.Equal(rate3, vaultU.ExchangeRate) + assert.Equal(vaultU.Redeemable.Cmp(ZERO), 0) +} + +func (s *transferSuite) TestTransferNotMaturedExistingVault() { + assert := assertions.New(s.T()) + + rate1 := big.NewInt(123456789) + tx, err := s.CErc20.ExchangeRateCurrentReturns(rate1) + assert.Nil(err) + assert.NotNil(tx) + s.Env.Blockchain.Commit() + + // no vault found for Owner + vaultO, err := s.VaultTracker.Vaults(s.Env.Owner.Opts.From) + assert.Nil(err) + assert.NotNil(vaultO) + assert.Equal(vaultO.Redeemable.Cmp(ZERO), 0) + assert.Equal(vaultO.Notional.Cmp(ZERO), 0) + assert.Equal(vaultO.ExchangeRate.Cmp(ZERO), 0) + + // call AddNotional for Owner + callerO := s.Env.Owner.Opts.From + tx, err = s.VaultTracker.AddNotional(callerO, big.NewInt(1000)) + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + // found vault for Owner + vaultO, err = s.VaultTracker.Vaults(callerO) + assert.Nil(err) + assert.NotNil(vaultO) + assert.Equal(big.NewInt(1000), vaultO.Notional) + assert.Equal(rate1, vaultO.ExchangeRate) + assert.Equal(vaultO.Redeemable.Cmp(ZERO), 0) + + rate2 := big.NewInt(223456789) + tx, err = s.CErc20.ExchangeRateCurrentReturns(rate2) + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + tx, err = s.VaultTracker.AddNotional(callerO, big.NewInt(1000)) + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + vaultO, err = s.VaultTracker.Vaults(callerO) + assert.Nil(err) + assert.NotNil(vaultO) + assert.Equal(big.NewInt(2000), vaultO.Notional) + assert.Equal(rate2, vaultO.ExchangeRate) + assert.Equal(vaultO.Redeemable.Cmp(big.NewInt(810)), 0) + + // no vault found for User1 + vaultU, err := s.VaultTracker.Vaults(s.Env.User1.Opts.From) + assert.Nil(err) + assert.NotNil(vaultU) + assert.Equal(vaultU.Redeemable.Cmp(ZERO), 0) + assert.Equal(vaultU.Notional.Cmp(ZERO), 0) + assert.Equal(vaultU.ExchangeRate.Cmp(ZERO), 0) + + rate3 := big.NewInt(323456789) + tx, err = s.CErc20.ExchangeRateCurrentReturns(rate3) + assert.Nil(err) + assert.NotNil(tx) + + // call AddNotional for User1 + callerU := s.Env.User1.Opts.From + notionalAmountU := big.NewInt(2000) + tx, err = s.VaultTracker.AddNotional(callerU, notionalAmountU) + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + // found vault for User1 + vaultU, err = s.VaultTracker.Vaults(s.Env.User1.Opts.From) + assert.Nil(err) + assert.NotNil(vaultU) + assert.Equal(notionalAmountU, vaultU.Notional) + assert.Equal(rate3, vaultU.ExchangeRate) + assert.Equal(vaultU.Redeemable.Cmp(ZERO), 0) + + // call Transfer Owner -> User1 + transferAmount := big.NewInt(500) + tx, err = s.VaultTracker.TransferNotionalFrom(callerO, callerU, transferAmount) + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + vaultO, err = s.VaultTracker.Vaults(callerO) + assert.Nil(err) + assert.NotNil(vaultO) + assert.Equal(big.NewInt(1500), vaultO.Notional) + assert.Equal(rate3, vaultO.ExchangeRate) + assert.Equal(vaultO.Redeemable.Cmp(big.NewInt(1705)), 0) + + vaultU, err = s.VaultTracker.Vaults(callerU) + assert.Nil(err) + assert.NotNil(vaultU) + assert.Equal(big.NewInt(2500), vaultU.Notional) + assert.Equal(rate3, vaultU.ExchangeRate) + assert.Equal(vaultU.Redeemable.Cmp(ZERO), 0) +} + +func (s *transferSuite) TestTransferMaturedNotExistingVault() { + assert := assertions.New(s.T()) + + rate1 := big.NewInt(123456789) + tx, err := s.CErc20.ExchangeRateCurrentReturns(rate1) + assert.Nil(err) + assert.NotNil(tx) + s.Env.Blockchain.Commit() + + // no vault found for Owner + vaultO, err := s.VaultTracker.Vaults(s.Env.Owner.Opts.From) + assert.Nil(err) + assert.NotNil(vaultO) + assert.Equal(vaultO.Redeemable.Cmp(ZERO), 0) + assert.Equal(vaultO.Notional.Cmp(ZERO), 0) + assert.Equal(vaultO.ExchangeRate.Cmp(ZERO), 0) + + // call AddNotional for Owner + callerO := s.Env.Owner.Opts.From + tx, err = s.VaultTracker.AddNotional(callerO, big.NewInt(1000)) + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + // found vault for Owner + vaultO, err = s.VaultTracker.Vaults(callerO) + assert.Nil(err) + assert.NotNil(vaultO) + assert.Equal(big.NewInt(1000), vaultO.Notional) + assert.Equal(rate1, vaultO.ExchangeRate) + assert.Equal(vaultO.Redeemable.Cmp(ZERO), 0) + + rate2 := big.NewInt(223456789) + tx, err = s.CErc20.ExchangeRateCurrentReturns(rate2) + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + tx, err = s.VaultTracker.AddNotional(callerO, big.NewInt(1000)) + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + vaultO, err = s.VaultTracker.Vaults(callerO) + assert.Nil(err) + assert.NotNil(vaultO) + assert.Equal(big.NewInt(2000), vaultO.Notional) + assert.Equal(rate2, vaultO.ExchangeRate) + assert.Equal(vaultO.Redeemable.Cmp(big.NewInt(810)), 0) + + // no vault found for User1 + vaultU, err := s.VaultTracker.Vaults(s.Env.User1.Opts.From) + assert.Nil(err) + assert.NotNil(vaultU) + assert.Equal(vaultU.Redeemable.Cmp(ZERO), 0) + assert.Equal(vaultU.Notional.Cmp(ZERO), 0) + assert.Equal(vaultU.ExchangeRate.Cmp(ZERO), 0) + + rate3 := big.NewInt(823456789) + tx, err = s.CErc20.ExchangeRateCurrentReturns(rate3) + assert.NotNil(tx) + assert.Nil(err) + s.Env.Blockchain.Commit() + + // move past the maturity + err = s.Env.Blockchain.AdjustTime(MATURITY * time.Second) + assert.Nil(err) + s.Env.Blockchain.Commit() + + // call mature + tx, err = s.VaultTracker.MatureVault() + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + // call Transfer Owner -> User1 + transferAmount := big.NewInt(500) + tx, err = s.VaultTracker.TransferNotionalFrom(callerO, s.Env.User1.Opts.From, transferAmount) + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + vaultO, err = s.VaultTracker.Vaults(callerO) + assert.Nil(err) + assert.NotNil(vaultO) + assert.Equal(big.NewInt(1500), vaultO.Notional) + assert.Equal(rate3, vaultO.ExchangeRate) + assert.Equal(vaultO.Redeemable.Cmp(big.NewInt(6180)), 0) + + vaultU, err = s.VaultTracker.Vaults(s.Env.User1.Opts.From) + assert.Nil(err) + assert.NotNil(vaultU) + assert.Equal(big.NewInt(500), vaultU.Notional) + assert.Equal(rate3, vaultU.ExchangeRate) + assert.Equal(vaultU.Redeemable.Cmp(ZERO), 0) +} + +func (s *transferSuite) TestTransferMaturedExistingVault() { + assert := assertions.New(s.T()) + + rate1 := big.NewInt(123456789) + tx, err := s.CErc20.ExchangeRateCurrentReturns(rate1) + assert.Nil(err) + assert.NotNil(tx) + s.Env.Blockchain.Commit() + + // no vault found for Owner + vaultO, err := s.VaultTracker.Vaults(s.Env.Owner.Opts.From) + assert.Nil(err) + assert.NotNil(vaultO) + assert.Equal(vaultO.Redeemable.Cmp(ZERO), 0) + assert.Equal(vaultO.Notional.Cmp(ZERO), 0) + assert.Equal(vaultO.ExchangeRate.Cmp(ZERO), 0) + + // call AddNotional for Owner + callerO := s.Env.Owner.Opts.From + tx, err = s.VaultTracker.AddNotional(callerO, big.NewInt(1000)) + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + // found vault for Owner + vaultO, err = s.VaultTracker.Vaults(callerO) + assert.Nil(err) + assert.NotNil(vaultO) + assert.Equal(big.NewInt(1000), vaultO.Notional) + assert.Equal(rate1, vaultO.ExchangeRate) + assert.Equal(vaultO.Redeemable.Cmp(ZERO), 0) + + rate2 := big.NewInt(223456789) + tx, err = s.CErc20.ExchangeRateCurrentReturns(rate2) + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + tx, err = s.VaultTracker.AddNotional(callerO, big.NewInt(1000)) + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + vaultO, err = s.VaultTracker.Vaults(callerO) + assert.Nil(err) + assert.NotNil(vaultO) + assert.Equal(big.NewInt(2000), vaultO.Notional) + assert.Equal(rate2, vaultO.ExchangeRate) + assert.Equal(vaultO.Redeemable.Cmp(big.NewInt(810)), 0) + + // no vault found for User1 + vaultU, err := s.VaultTracker.Vaults(s.Env.User1.Opts.From) + assert.Nil(err) + assert.NotNil(vaultU) + assert.Equal(vaultU.Redeemable.Cmp(ZERO), 0) + assert.Equal(vaultU.Notional.Cmp(ZERO), 0) + assert.Equal(vaultU.ExchangeRate.Cmp(ZERO), 0) + + rate3 := big.NewInt(323456789) + tx, err = s.CErc20.ExchangeRateCurrentReturns(rate3) + assert.Nil(err) + assert.NotNil(tx) + + // call AddNotional for User1 + callerU := s.Env.User1.Opts.From + notionalAmountU := big.NewInt(2000) + tx, err = s.VaultTracker.AddNotional(callerU, notionalAmountU) + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + // found vault for User1 + vaultU, err = s.VaultTracker.Vaults(callerU) + assert.Nil(err) + assert.NotNil(vaultU) + assert.Equal(notionalAmountU, vaultU.Notional) + assert.Equal(rate3, vaultU.ExchangeRate) + assert.Equal(vaultU.Redeemable.Cmp(ZERO), 0) + + rate4 := big.NewInt(823456789) + tx, err = s.CErc20.ExchangeRateCurrentReturns(rate4) + assert.NotNil(tx) + assert.Nil(err) + s.Env.Blockchain.Commit() + + // move past the maturity + err = s.Env.Blockchain.AdjustTime(MATURITY * time.Second) + assert.Nil(err) + s.Env.Blockchain.Commit() + + // call mature + tx, err = s.VaultTracker.MatureVault() + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + // call Transfer Owner -> User1 + transferAmount := big.NewInt(500) + tx, err = s.VaultTracker.TransferNotionalFrom(callerO, callerU, transferAmount) + assert.Nil(err) + assert.NotNil(tx) + + s.Env.Blockchain.Commit() + + vaultO, err = s.VaultTracker.Vaults(callerO) + assert.Nil(err) + assert.NotNil(vaultO) + assert.Equal(big.NewInt(1500), vaultO.Notional) + assert.Equal(rate4, vaultO.ExchangeRate) + assert.Equal(vaultO.Redeemable.Cmp(big.NewInt(6180)), 0) + + vaultU, err = s.VaultTracker.Vaults(callerU) + assert.Nil(err) + assert.NotNil(vaultU) + assert.Equal(big.NewInt(2500), vaultU.Notional) + assert.Equal(rate4, vaultU.ExchangeRate) + assert.Equal(vaultU.Redeemable.Cmp(big.NewInt(3091)), 0) +} + +func TestTrackerTransferSuite(t *test.T) { + suite.Run(t, &transferSuite{}) +} diff --git a/gost/pkg/vaulttrackertesting/vault_tracker_construction_test.go b/gost/pkg/vaulttrackertesting/vault_tracker_construction_test.go new file mode 100644 index 0000000..f72bca0 --- /dev/null +++ b/gost/pkg/vaulttrackertesting/vault_tracker_construction_test.go @@ -0,0 +1,69 @@ +package vaulttrackertesting + +import ( + "math/big" + test "testing" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + assertions "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" + "github.com/swivel-finance/gost/test/vaulttracker" +) + +type vaultTrackerCtorSuite struct { + suite.Suite + Env *Env + Dep *Dep + VaultTracker *vaulttracker.VaultTrackerSession // *Session objects are created by the go bindings +} + +func (s *vaultTrackerCtorSuite) SetupSuite() { + var err error + + s.Env = NewEnv(big.NewInt(ONE_ETH)) // each of the wallets in the env will begin with this balance + s.Dep, err = Deploy(s.Env) + if err != nil { + panic(err) + } + + err = s.Env.Blockchain.AdjustTime(0) // set bc timestamp to 0 + if err != nil { + panic(err) + } + s.Env.Blockchain.Commit() + + // binding owner to both, kind of why it exists - but could be any of the env wallets + s.VaultTracker = &vaulttracker.VaultTrackerSession{ + Contract: s.Dep.VaultTracker, + CallOpts: bind.CallOpts{From: s.Env.Owner.Opts.From, Pending: false}, + TransactOpts: bind.TransactOpts{ + From: s.Env.Owner.Opts.From, + Signer: s.Env.Owner.Opts.Signer, + }, + } +} + +func (s *vaultTrackerCtorSuite) TestAdmin() { + assert := assertions.New(s.T()) + addr, err := s.VaultTracker.Admin() + assert.Nil(err) + assert.Equal(addr, s.Env.Owner.Opts.From) +} + +func (s *vaultTrackerCtorSuite) TestCTokenAddress() { + assert := assertions.New(s.T()) + addr, err := s.VaultTracker.CTokenAddr() + assert.Nil(err) + assert.Equal(s.Dep.CErc20Address, addr) +} + +func (s *vaultTrackerCtorSuite) TestMaturity() { + assert := assertions.New(s.T()) + maturity, err := s.VaultTracker.Maturity() + assert.Nil(err) + assert.Equal(maturity, s.Dep.Maturity) +} + +func TestVaultTrackerCtorSuite(t *test.T) { + suite.Run(t, &vaultTrackerCtorSuite{}) +} diff --git a/gost/test/.DS_Store b/gost/test/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..85b278b9c0c5333f4d75b0314a096087cf88afb3 GIT binary patch literal 6148 zcmeHLJx{|h5IrXWRTPPijDdfEnAk!UCO|@BM{W658&b6e)`$hc#D)+*fdyt}HvR(Q zUmzqF-r1(L(*~FTAzx)b$9HGHye4*CA`;cZtvR9!5tUFFg9%h4jQw1O%+o#7Kq1HI zwsz;%H`Am&6ze*i0#1RyrvSgZW3)qcYSK34-ru)b+nc0u+-Ri@^p?)9md~H29~Scw zTVF)9_ly-nTp*pwlwkgjWYD8FwQ#jb+tym*FWePJn!K)G`n(FpP0|6!ucIx#{w?zz z1K$)3n>oGw$0OTo^4d6A8R*r|H@S?Cu;vfec>Zzf(lPDR5x%jOrIPnLmG_$*X1vu8 z4%QeZi=r5dho31PJ?OyC%|T8H?{dg*^0>b-co<`tJc?p$9yOk45=zwR5YJ5ypN@Qb zm{rHpM$8|47Hjf5eeUxs9NXmjop_74$e8zU8}@9rQdyy^odQk)r$Ao;ULQgf#zb1SjgiJoAv`dlQh_Q}=p%+u>F5u2T%<8msM1NunK6!@S?Cjr zkh7ydl;I>Ig|2oAI0bA4e05pj{eP+W{BI|@E2n@{;9n^qf_Ocy;+FK@I&^cq*M=xH r6gG~_6v`A-dOMa4-irBu1!?ew+yF)zGll4ZxgP>j23I)+epG>X4gTAj literal 0 HcmV?d00001 diff --git a/gost/test/fakes/Hash.abi b/gost/test/fakes/Hash.abi new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/gost/test/fakes/Hash.abi @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/gost/test/fakes/Hash.bin b/gost/test/fakes/Hash.bin new file mode 100644 index 0000000..787f6f1 --- /dev/null +++ b/gost/test/fakes/Hash.bin @@ -0,0 +1 @@ +60566050600b82828239805160001a6073146043577f4e487b7100000000000000000000000000000000000000000000000000000000600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220cceb758f662abc5409df6f68d38062e036fb60d6c13ffc5a01fd7d119667ef9b64736f6c63430008040033 \ No newline at end of file diff --git a/gost/test/fakes/Hash.sol b/gost/test/fakes/Hash.sol new file mode 100644 index 0000000..9cfefb2 --- /dev/null +++ b/gost/test/fakes/Hash.sol @@ -0,0 +1,107 @@ +// SPDX-License-Identifier: UNLICENSED + +pragma solidity 0.8.4; + +/** + @notice Encapsulation of the logic to produce EIP712 hashed domain and messages. + Also to produce / verify hashed and signed Orders. + See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-712.md + See/attribute https://github.com/0xProject/0x-monorepo/blob/development/contracts/utils/contracts/src/LibEIP712.sol +*/ + +library Hash { + /// @dev struct represents the attributes of an offchain Swivel.Order + struct Order { + bytes32 key; + address maker; + address underlying; + bool vault; + bool exit; + uint256 principal; + uint256 premium; + uint256 maturity; + uint256 expiry; + } + + // EIP712 Domain Separator typeHash + // keccak256(abi.encodePacked( + // 'EIP712Domain(', + // 'string name,', + // 'string version,', + // 'uint256 chainId,', + // 'address verifyingContract', + // ')' + // )); + bytes32 constant internal DOMAIN_TYPEHASH = 0x8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f; + + // EIP712 typeHash of an Order + // keccak256(abi.encodePacked( + // 'Order(', + // 'bytes32 key,', + // 'address maker,', + // 'address underlying,', + // 'bool vault,', + // 'bool exit,', + // 'uint256 principal,', + // 'uint256 premium,', + // 'uint256 maturity,', + // 'uint256 expiry', + // ')' + // )); + bytes32 constant internal ORDER_TYPEHASH = 0x7ddd38ab5ed1c16b61ca90eeb9579e29da1ba821cf42d8cdef8f30a31a6a4146; + + /// @param n EIP712 domain name + /// @param version EIP712 semantic version string + /// @param i Chain ID + /// @param verifier address of the verifying contract + function domain(string memory n, string memory version, uint256 i, address verifier) internal pure returns (bytes32) { + bytes32 hash; + + assembly { + let nameHash := keccak256(add(n, 32), mload(n)) + let versionHash := keccak256(add(version, 32), mload(version)) + let pointer := mload(64) + mstore(pointer, DOMAIN_TYPEHASH) + mstore(add(pointer, 32), nameHash) + mstore(add(pointer, 64), versionHash) + mstore(add(pointer, 96), i) + mstore(add(pointer, 128), verifier) + hash := keccak256(pointer, 160) + } + + return hash; + } + + /// @param d Type hash of the domain separator (see Hash.domain) + /// @param h EIP712 hash struct (order for example) + function message(bytes32 d, bytes32 h) internal pure returns (bytes32) { + bytes32 hash; + + assembly { + let pointer := mload(64) + mstore(pointer, 0x1901000000000000000000000000000000000000000000000000000000000000) + mstore(add(pointer, 2), d) + mstore(add(pointer, 34), h) + hash := keccak256(pointer, 66) + } + + return hash; + } + + /// @param o A Swivel Order + function order(Order calldata o) internal pure returns (bytes32) { + // TODO assembly + return keccak256(abi.encode( + ORDER_TYPEHASH, + o.key, + o.maker, + o.underlying, + o.vault, + o.exit, + o.principal, + o.premium, + o.maturity, + o.expiry + )); + } +} diff --git a/gost/test/fakes/HashFake.abi b/gost/test/fakes/HashFake.abi new file mode 100644 index 0000000..ef5c5ca --- /dev/null +++ b/gost/test/fakes/HashFake.abi @@ -0,0 +1 @@ +[{"inputs":[{"internalType":"string","name":"n","type":"string"},{"internalType":"string","name":"version","type":"string"},{"internalType":"uint256","name":"c","type":"uint256"},{"internalType":"address","name":"verifier","type":"address"}],"name":"domainTest","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"domainTypeHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes32","name":"d","type":"bytes32"},{"internalType":"bytes32","name":"h","type":"bytes32"}],"name":"messageTest","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"key","type":"bytes32"},{"internalType":"address","name":"maker","type":"address"},{"internalType":"address","name":"underlying","type":"address"},{"internalType":"bool","name":"vault","type":"bool"},{"internalType":"bool","name":"exit","type":"bool"},{"internalType":"uint256","name":"principal","type":"uint256"},{"internalType":"uint256","name":"premium","type":"uint256"},{"internalType":"uint256","name":"maturity","type":"uint256"},{"internalType":"uint256","name":"expiry","type":"uint256"}],"internalType":"struct Hash.Order","name":"o","type":"tuple"}],"name":"orderTest","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"orderTypeHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"permitTypeHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"}] \ No newline at end of file diff --git a/gost/test/fakes/HashFake.bin b/gost/test/fakes/HashFake.bin new file mode 100644 index 0000000..0de3c30 --- /dev/null +++ b/gost/test/fakes/HashFake.bin @@ -0,0 +1 @@ +608060405234801561001057600080fd5b50611008806100206000396000f3fe608060405234801561001057600080fd5b50600436106100625760003560e01c806310ce43bd146100675780634c05b2a11461008557806391c2600f146100b557806397995ecb146100d3578063af1ef90b146100f1578063e2711de414610121575b600080fd5b61006f610151565b60405161007c9190610a06565b60405180910390f35b61009f600480360381019061009a91906104a9565b61017d565b6040516100ac9190610a06565b60405180910390f35b6100bd610191565b6040516100ca9190610a06565b60405180910390f35b6100db6101bd565b6040516100e89190610a06565b60405180910390f35b61010b600480360381019061010691906104e5565b6101e9565b6040516101189190610a06565b60405180910390f35b61013b60048036038101906101369190610578565b610201565b6040516101489190610a06565b60405180910390f35b600060405160200161016290610963565b60405160208183030381529060405280519060200120905090565b60006101898383610213565b905092915050565b60006040516020016101a2906108e0565b60405160208183030381529060405280519060200120905090565b60006040516020016101ce906109ba565b60405160208183030381529060405280519060200120905090565b60006101f785858585610259565b9050949350505050565b600061020c826102bd565b9050919050565b6000806040517f19010000000000000000000000000000000000000000000000000000000000008152846002820152836022820152604281209150508091505092915050565b60008085516020870120855160208701206040517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f815282602082015281604082015286606082015285608082015260a08120935050505080915050949350505050565b60007f7ddd38ab5ed1c16b61ca90eeb9579e29da1ba821cf42d8cdef8f30a31a6a414660001b82600001358360200160208101906102fb9190610457565b84604001602081019061030e9190610457565b8560600160208101906103219190610480565b8660800160208101906103349190610480565b8760a001358860c001358960e001358a61010001356040516020016103629a99989796959493929190610a21565b604051602081830303815290604052805190602001209050919050565b600061039261038d84610ae2565b610abd565b9050828152602081018484840111156103aa57600080fd5b6103b5848285610b70565b509392505050565b6000813590506103cc81610f76565b92915050565b6000813590506103e181610f8d565b92915050565b6000813590506103f681610fa4565b92915050565b600082601f83011261040d57600080fd5b813561041d84826020860161037f565b91505092915050565b6000610120828403121561043957600080fd5b81905092915050565b60008135905061045181610fbb565b92915050565b60006020828403121561046957600080fd5b6000610477848285016103bd565b91505092915050565b60006020828403121561049257600080fd5b60006104a0848285016103d2565b91505092915050565b600080604083850312156104bc57600080fd5b60006104ca858286016103e7565b92505060206104db858286016103e7565b9150509250929050565b600080600080608085870312156104fb57600080fd5b600085013567ffffffffffffffff81111561051557600080fd5b610521878288016103fc565b945050602085013567ffffffffffffffff81111561053e57600080fd5b61054a878288016103fc565b935050604061055b87828801610442565b925050606061056c878288016103bd565b91505092959194509250565b6000610120828403121561058b57600080fd5b600061059984828501610426565b91505092915050565b6105ab81610b1e565b82525050565b6105ba81610b30565b82525050565b6105c981610b3c565b82525050565b60006105dc600c83610b13565b91506105e782610bf0565b600c82019050919050565b60006105ff600c83610b13565b915061060a82610c19565b600c82019050919050565b6000610622600e83610b13565b915061062d82610c42565b600e82019050919050565b6000610645600683610b13565b915061065082610c6b565b600682019050919050565b6000610668601083610b13565b915061067382610c94565b601082019050919050565b600061068b601383610b13565b915061069682610cbd565b601382019050919050565b60006106ae601983610b13565b91506106b982610ce6565b601982019050919050565b60006106d1601183610b13565b91506106dc82610d0f565b601182019050919050565b60006106f4601083610b13565b91506106ff82610d38565b601082019050919050565b6000610717601183610b13565b915061072282610d61565b601182019050919050565b600061073a600e83610b13565b915061074582610d8a565b600e82019050919050565b600061075d600183610b13565b915061076882610db3565b600182019050919050565b6000610780600f83610b13565b915061078b82610ddc565b600f82019050919050565b60006107a3601083610b13565b91506107ae82610e05565b601082019050919050565b60006107c6600783610b13565b91506107d182610e2e565b600782019050919050565b60006107e9600e83610b13565b91506107f482610e57565b600e82019050919050565b600061080c600e83610b13565b915061081782610e80565b600e82019050919050565b600061082f600b83610b13565b915061083a82610ea9565b600b82019050919050565b6000610852601283610b13565b915061085d82610ed2565b601282019050919050565b6000610875600a83610b13565b915061088082610efb565b600a82019050919050565b6000610898600e83610b13565b91506108a382610f24565b600e82019050919050565b60006108bb600d83610b13565b91506108c682610f4d565b600d82019050919050565b6108da81610b66565b82525050565b60006108eb82610638565b91506108f6826105f2565b9150610901826107ff565b915061090c8261067e565b915061091782610822565b915061092282610868565b915061092d82610845565b91506109388261065b565b9150610943826106c4565b915061094e8261072d565b915061095982610750565b9150819050919050565b600061096e826107b9565b9150610979826107dc565b915061098482610796565b915061098f8261088b565b915061099a82610615565b91506109a58261070a565b91506109b082610750565b9150819050919050565b60006109c5826108ae565b91506109d0826105cf565b91506109db82610773565b91506109e6826106e7565b91506109f1826106a1565b91506109fc82610750565b9150819050919050565b6000602082019050610a1b60008301846105c0565b92915050565b600061014082019050610a37600083018d6105c0565b610a44602083018c6105c0565b610a51604083018b6105a2565b610a5e606083018a6105a2565b610a6b60808301896105b1565b610a7860a08301886105b1565b610a8560c08301876108d1565b610a9260e08301866108d1565b610aa06101008301856108d1565b610aae6101208301846108d1565b9b9a5050505050505050505050565b6000610ac7610ad8565b9050610ad38282610b7f565b919050565b6000604051905090565b600067ffffffffffffffff821115610afd57610afc610bb0565b5b610b0682610bdf565b9050602081019050919050565b600081905092915050565b6000610b2982610b46565b9050919050565b60008115159050919050565b6000819050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b82818337600083830152505050565b610b8882610bdf565b810181811067ffffffffffffffff82111715610ba757610ba6610bb0565b5b80604052505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000601f19601f8301169050919050565b7f737472696e67206e616d652c0000000000000000000000000000000000000000600082015250565b7f62797465733332206b65792c0000000000000000000000000000000000000000600082015250565b7f75696e74323536206e6f6e63652c000000000000000000000000000000000000600082015250565b7f4f72646572280000000000000000000000000000000000000000000000000000600082015250565b7f75696e74323536207072656d69756d2c00000000000000000000000000000000600082015250565b7f6164647265737320756e6465726c79696e672c00000000000000000000000000600082015250565b7f6164647265737320766572696679696e67436f6e747261637400000000000000600082015250565b7f75696e74323536206d617475726974792c000000000000000000000000000000600082015250565b7f75696e7432353620636861696e49642c00000000000000000000000000000000600082015250565b7f75696e7432353620646561646c696e652c000000000000000000000000000000600082015250565b7f75696e7432353620657870697279000000000000000000000000000000000000600082015250565b7f2900000000000000000000000000000000000000000000000000000000000000600082015250565b7f737472696e672076657273696f6e2c0000000000000000000000000000000000600082015250565b7f61646472657373207370656e6465722c00000000000000000000000000000000600082015250565b7f5065726d69742800000000000000000000000000000000000000000000000000600082015250565b7f61646472657373206f776e65722c000000000000000000000000000000000000600082015250565b7f61646472657373206d616b65722c000000000000000000000000000000000000600082015250565b7f626f6f6c207661756c742c000000000000000000000000000000000000000000600082015250565b7f75696e74323536207072696e636970616c2c0000000000000000000000000000600082015250565b7f626f6f6c20657869742c00000000000000000000000000000000000000000000600082015250565b7f75696e743235362076616c75652c000000000000000000000000000000000000600082015250565b7f454950373132446f6d61696e2800000000000000000000000000000000000000600082015250565b610f7f81610b1e565b8114610f8a57600080fd5b50565b610f9681610b30565b8114610fa157600080fd5b50565b610fad81610b3c565b8114610fb857600080fd5b50565b610fc481610b66565b8114610fcf57600080fd5b5056fea264697066735822122058fb74935accb8eaea7bf389dce878ecfc8be1490b20b6d10307988c0bb533ca64736f6c63430008040033 \ No newline at end of file diff --git a/gost/test/fakes/HashFake.sol b/gost/test/fakes/HashFake.sol new file mode 100644 index 0000000..aa45eae --- /dev/null +++ b/gost/test/fakes/HashFake.sol @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: UNLICENSED + +/** + @dev HashFake.sol is written specfically to test the functions which exist in our Hash.sol "embedded" library +*/ + +pragma solidity 0.8.4; + +import './Hash.sol'; + +contract HashFake { + /// @dev convenience method to get the domain type hash + function domainTypeHash() public pure returns (bytes32) { + return keccak256(abi.encodePacked( + 'EIP712Domain(', + 'string name,', + 'string version,', + 'uint256 chainId,', + 'address verifyingContract', + ')' + )); + } + + function domainTest(string memory n, string memory version, uint256 c, address verifier) public pure returns (bytes32) { + return Hash.domain(n, version, c, verifier); + } + + function messageTest(bytes32 d, bytes32 h) public pure returns (bytes32) { + return Hash.message(d, h); + } + + /// @dev convenience method to get the order type hash + function orderTypeHash() public pure returns (bytes32) { + return keccak256(abi.encodePacked( + 'Order(', + 'bytes32 key,', + 'address maker,', + 'address underlying,', + 'bool vault,', + 'bool exit,', + 'uint256 principal,', + 'uint256 premium,', + 'uint256 maturity,', + 'uint256 expiry', + ')' + )); + } + + function orderTest(Hash.Order calldata o) external pure returns (bytes32) { + return Hash.order(o); + } + + /// @dev convenience method to generate the /token/hash permit type hash + function permitTypeHash() public pure returns (bytes32) { + return keccak256(abi.encodePacked( + 'Permit(', + 'address owner,', + 'address spender,', + 'uint256 value,', + 'uint256 nonce,', + 'uint256 deadline,', + ')' + )); + } +} diff --git a/gost/test/fakes/Sig.abi b/gost/test/fakes/Sig.abi new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/gost/test/fakes/Sig.abi @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/gost/test/fakes/Sig.bin b/gost/test/fakes/Sig.bin new file mode 100644 index 0000000..26a90dd --- /dev/null +++ b/gost/test/fakes/Sig.bin @@ -0,0 +1 @@ +60566050600b82828239805160001a6073146043577f4e487b7100000000000000000000000000000000000000000000000000000000600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220b6cc4a1d4d2a5fefaaef68df09084e80b911968e2ca6768dce4c9863564f663d64736f6c63430008040033 \ No newline at end of file diff --git a/gost/test/fakes/Sig.sol b/gost/test/fakes/Sig.sol new file mode 100644 index 0000000..d65f2cc --- /dev/null +++ b/gost/test/fakes/Sig.sol @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: UNLICENSED + +pragma solidity 0.8.4; + +library Sig { + /// @dev ECDSA V,R and S components encapsulated here as we may not always be able to accept a bytes signature + struct Components { + uint8 v; + bytes32 r; + bytes32 s; + } + + /// @param h Hashed data which was originally signed + /// @param c signature struct containing V,R and S + /// @return The recovered address + function recover(bytes32 h, Components calldata c) internal pure returns (address) { + // EIP-2 and malleable signatures... + // see https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/cryptography/ECDSA.sol + require(uint256(c.s) <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0, 'invalid signature "s" value'); + require(c.v == 27 || c.v == 28, 'invalid signature "v" value'); + + return ecrecover(h, c.v, c.r, c.s); + } + + /// @param h Hashed data which was originally signed + /// @param sig Valid ECDSA signature + /// @dev splitAndRecover should only be used if it is known that the resulting + /// verifying bit (V) will be 27 || 28. Otherwise use recover, possibly calling split first. + /// @return The recovered address + function splitAndRecover(bytes32 h, bytes memory sig) internal pure returns (address) { + (uint8 v, bytes32 r, bytes32 s) = split(sig); + + return ecrecover(h, v, r, s); + } + + /// @param sig Valid ECDSA signature + /// @return v The verification bit + /// @return r First 32 bytes + /// @return s Next 32 bytes + function split(bytes memory sig) internal pure returns (uint8, bytes32, bytes32) { + require(sig.length == 65, 'invalid signature length'); + + bytes32 r; + bytes32 s; + uint8 v; + + assembly { + r := mload(add(sig, 32)) + s := mload(add(sig, 64)) + v := byte(0, mload(add(sig, 96))) + } + + return (v, r, s); + } +} diff --git a/gost/test/fakes/SigFake.abi b/gost/test/fakes/SigFake.abi new file mode 100644 index 0000000..222d1b6 --- /dev/null +++ b/gost/test/fakes/SigFake.abi @@ -0,0 +1 @@ +[{"inputs":[{"internalType":"bytes32","name":"h","type":"bytes32"},{"components":[{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct Sig.Components","name":"c","type":"tuple"}],"name":"recoverTest","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes","name":"sig","type":"bytes"}],"name":"splitTest","outputs":[{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"stateMutability":"pure","type":"function"}] \ No newline at end of file diff --git a/gost/test/fakes/SigFake.bin b/gost/test/fakes/SigFake.bin new file mode 100644 index 0000000..cc95373 --- /dev/null +++ b/gost/test/fakes/SigFake.bin @@ -0,0 +1 @@ +608060405234801561001057600080fd5b50610789806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c8063458b017a1461003b578063ecf888711461006d575b600080fd5b61005560048036038101906100509190610383565b61009d565b60405161006493929190610543565b60405180910390f35b61008760048036038101906100829190610347565b6100b8565b6040516100949190610483565b60405180910390f35b60008060006100ab846100cc565b9250925092509193909250565b60006100c48383610145565b905092915050565b60008060006041845114610115576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161010c90610503565b60405180910390fd5b60008060006020870151925060408701519150606087015160001a90508083839550955095505050509193909250565b60007f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0826040013560001c11156101b1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101a890610523565b60405180910390fd5b601b8260000160208101906101c691906103c4565b60ff1614806101ea5750601c8260000160208101906101e591906103c4565b60ff16145b610229576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610220906104e3565b60405180910390fd5b60018383600001602081019061023f91906103c4565b8460200135856040013560405160008152602001604052604051610266949392919061049e565b6020604051602081039080840390855afa158015610288573d6000803e3d6000fd5b50505060206040510351905092915050565b60006102ad6102a88461059f565b61057a565b9050828152602081018484840111156102c557600080fd5b6102d084828561062a565b509392505050565b6000813590506102e781610725565b92915050565b600082601f8301126102fe57600080fd5b813561030e84826020860161029a565b91505092915050565b60006060828403121561032957600080fd5b81905092915050565b6000813590506103418161073c565b92915050565b6000806080838503121561035a57600080fd5b6000610368858286016102d8565b925050602061037985828601610317565b9150509250929050565b60006020828403121561039557600080fd5b600082013567ffffffffffffffff8111156103af57600080fd5b6103bb848285016102ed565b91505092915050565b6000602082840312156103d657600080fd5b60006103e484828501610332565b91505092915050565b6103f6816105e1565b82525050565b610405816105f3565b82525050565b6000610418601b836105d0565b9150610423826106aa565b602082019050919050565b600061043b6018836105d0565b9150610446826106d3565b602082019050919050565b600061045e601b836105d0565b9150610469826106fc565b602082019050919050565b61047d8161061d565b82525050565b600060208201905061049860008301846103ed565b92915050565b60006080820190506104b360008301876103fc565b6104c06020830186610474565b6104cd60408301856103fc565b6104da60608301846103fc565b95945050505050565b600060208201905081810360008301526104fc8161040b565b9050919050565b6000602082019050818103600083015261051c8161042e565b9050919050565b6000602082019050818103600083015261053c81610451565b9050919050565b60006060820190506105586000830186610474565b61056560208301856103fc565b61057260408301846103fc565b949350505050565b6000610584610595565b90506105908282610639565b919050565b6000604051905090565b600067ffffffffffffffff8211156105ba576105b961066a565b5b6105c382610699565b9050602081019050919050565b600082825260208201905092915050565b60006105ec826105fd565b9050919050565b6000819050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600060ff82169050919050565b82818337600083830152505050565b61064282610699565b810181811067ffffffffffffffff821117156106615761066061066a565b5b80604052505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000601f19601f8301169050919050565b7f696e76616c6964207369676e6174757265202276222076616c75650000000000600082015250565b7f696e76616c6964207369676e6174757265206c656e6774680000000000000000600082015250565b7f696e76616c6964207369676e6174757265202273222076616c75650000000000600082015250565b61072e816105f3565b811461073957600080fd5b50565b6107458161061d565b811461075057600080fd5b5056fea2646970667358221220e63deb792e476d2b8af6643e104292c4051f4dee40d035fb79165a90e45b2aa664736f6c63430008040033 \ No newline at end of file diff --git a/gost/test/fakes/SigFake.sol b/gost/test/fakes/SigFake.sol new file mode 100644 index 0000000..f0afbdb --- /dev/null +++ b/gost/test/fakes/SigFake.sol @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: UNLICENSED + +/** + @dev SigFake.sol is written specfically to test the functions which exist in our Sig.sol "embedded" library +*/ + +pragma solidity 0.8.4; + +import './Sig.sol'; + +contract SigFake { + function splitTest(bytes memory sig) public pure returns (uint8 v, bytes32 r, bytes32 s) { + return Sig.split(sig); + } + + function recoverTest(bytes32 h, Sig.Components calldata c) public pure returns (address) { + return Sig.recover(h,c); + } +} diff --git a/gost/test/fakes/hashfake.go b/gost/test/fakes/hashfake.go new file mode 100644 index 0000000..c93d4b1 --- /dev/null +++ b/gost/test/fakes/hashfake.go @@ -0,0 +1,388 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package fakes + +import ( + "math/big" + "strings" + + ethereum "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/event" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription +) + +// HashOrder is an auto generated low-level Go binding around an user-defined struct. +type HashOrder struct { + Key [32]byte + Maker common.Address + Underlying common.Address + Vault bool + Exit bool + Principal *big.Int + Premium *big.Int + Maturity *big.Int + Expiry *big.Int +} + +// HashFakeABI is the input ABI used to generate the binding from. +const HashFakeABI = "[{\"inputs\":[{\"internalType\":\"string\",\"name\":\"n\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"version\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"c\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"verifier\",\"type\":\"address\"}],\"name\":\"domainTest\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"domainTypeHash\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"d\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"h\",\"type\":\"bytes32\"}],\"name\":\"messageTest\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"key\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"maker\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"underlying\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"vault\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"exit\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"principal\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"premium\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maturity\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"expiry\",\"type\":\"uint256\"}],\"internalType\":\"structHash.Order\",\"name\":\"o\",\"type\":\"tuple\"}],\"name\":\"orderTest\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"orderTypeHash\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"permitTypeHash\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"pure\",\"type\":\"function\"}]" + +// HashFakeBin is the compiled bytecode used for deploying new contracts. +var HashFakeBin = "0x608060405234801561001057600080fd5b50611008806100206000396000f3fe608060405234801561001057600080fd5b50600436106100625760003560e01c806310ce43bd146100675780634c05b2a11461008557806391c2600f146100b557806397995ecb146100d3578063af1ef90b146100f1578063e2711de414610121575b600080fd5b61006f610151565b60405161007c9190610a06565b60405180910390f35b61009f600480360381019061009a91906104a9565b61017d565b6040516100ac9190610a06565b60405180910390f35b6100bd610191565b6040516100ca9190610a06565b60405180910390f35b6100db6101bd565b6040516100e89190610a06565b60405180910390f35b61010b600480360381019061010691906104e5565b6101e9565b6040516101189190610a06565b60405180910390f35b61013b60048036038101906101369190610578565b610201565b6040516101489190610a06565b60405180910390f35b600060405160200161016290610963565b60405160208183030381529060405280519060200120905090565b60006101898383610213565b905092915050565b60006040516020016101a2906108e0565b60405160208183030381529060405280519060200120905090565b60006040516020016101ce906109ba565b60405160208183030381529060405280519060200120905090565b60006101f785858585610259565b9050949350505050565b600061020c826102bd565b9050919050565b6000806040517f19010000000000000000000000000000000000000000000000000000000000008152846002820152836022820152604281209150508091505092915050565b60008085516020870120855160208701206040517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f815282602082015281604082015286606082015285608082015260a08120935050505080915050949350505050565b60007f7ddd38ab5ed1c16b61ca90eeb9579e29da1ba821cf42d8cdef8f30a31a6a414660001b82600001358360200160208101906102fb9190610457565b84604001602081019061030e9190610457565b8560600160208101906103219190610480565b8660800160208101906103349190610480565b8760a001358860c001358960e001358a61010001356040516020016103629a99989796959493929190610a21565b604051602081830303815290604052805190602001209050919050565b600061039261038d84610ae2565b610abd565b9050828152602081018484840111156103aa57600080fd5b6103b5848285610b70565b509392505050565b6000813590506103cc81610f76565b92915050565b6000813590506103e181610f8d565b92915050565b6000813590506103f681610fa4565b92915050565b600082601f83011261040d57600080fd5b813561041d84826020860161037f565b91505092915050565b6000610120828403121561043957600080fd5b81905092915050565b60008135905061045181610fbb565b92915050565b60006020828403121561046957600080fd5b6000610477848285016103bd565b91505092915050565b60006020828403121561049257600080fd5b60006104a0848285016103d2565b91505092915050565b600080604083850312156104bc57600080fd5b60006104ca858286016103e7565b92505060206104db858286016103e7565b9150509250929050565b600080600080608085870312156104fb57600080fd5b600085013567ffffffffffffffff81111561051557600080fd5b610521878288016103fc565b945050602085013567ffffffffffffffff81111561053e57600080fd5b61054a878288016103fc565b935050604061055b87828801610442565b925050606061056c878288016103bd565b91505092959194509250565b6000610120828403121561058b57600080fd5b600061059984828501610426565b91505092915050565b6105ab81610b1e565b82525050565b6105ba81610b30565b82525050565b6105c981610b3c565b82525050565b60006105dc600c83610b13565b91506105e782610bf0565b600c82019050919050565b60006105ff600c83610b13565b915061060a82610c19565b600c82019050919050565b6000610622600e83610b13565b915061062d82610c42565b600e82019050919050565b6000610645600683610b13565b915061065082610c6b565b600682019050919050565b6000610668601083610b13565b915061067382610c94565b601082019050919050565b600061068b601383610b13565b915061069682610cbd565b601382019050919050565b60006106ae601983610b13565b91506106b982610ce6565b601982019050919050565b60006106d1601183610b13565b91506106dc82610d0f565b601182019050919050565b60006106f4601083610b13565b91506106ff82610d38565b601082019050919050565b6000610717601183610b13565b915061072282610d61565b601182019050919050565b600061073a600e83610b13565b915061074582610d8a565b600e82019050919050565b600061075d600183610b13565b915061076882610db3565b600182019050919050565b6000610780600f83610b13565b915061078b82610ddc565b600f82019050919050565b60006107a3601083610b13565b91506107ae82610e05565b601082019050919050565b60006107c6600783610b13565b91506107d182610e2e565b600782019050919050565b60006107e9600e83610b13565b91506107f482610e57565b600e82019050919050565b600061080c600e83610b13565b915061081782610e80565b600e82019050919050565b600061082f600b83610b13565b915061083a82610ea9565b600b82019050919050565b6000610852601283610b13565b915061085d82610ed2565b601282019050919050565b6000610875600a83610b13565b915061088082610efb565b600a82019050919050565b6000610898600e83610b13565b91506108a382610f24565b600e82019050919050565b60006108bb600d83610b13565b91506108c682610f4d565b600d82019050919050565b6108da81610b66565b82525050565b60006108eb82610638565b91506108f6826105f2565b9150610901826107ff565b915061090c8261067e565b915061091782610822565b915061092282610868565b915061092d82610845565b91506109388261065b565b9150610943826106c4565b915061094e8261072d565b915061095982610750565b9150819050919050565b600061096e826107b9565b9150610979826107dc565b915061098482610796565b915061098f8261088b565b915061099a82610615565b91506109a58261070a565b91506109b082610750565b9150819050919050565b60006109c5826108ae565b91506109d0826105cf565b91506109db82610773565b91506109e6826106e7565b91506109f1826106a1565b91506109fc82610750565b9150819050919050565b6000602082019050610a1b60008301846105c0565b92915050565b600061014082019050610a37600083018d6105c0565b610a44602083018c6105c0565b610a51604083018b6105a2565b610a5e606083018a6105a2565b610a6b60808301896105b1565b610a7860a08301886105b1565b610a8560c08301876108d1565b610a9260e08301866108d1565b610aa06101008301856108d1565b610aae6101208301846108d1565b9b9a5050505050505050505050565b6000610ac7610ad8565b9050610ad38282610b7f565b919050565b6000604051905090565b600067ffffffffffffffff821115610afd57610afc610bb0565b5b610b0682610bdf565b9050602081019050919050565b600081905092915050565b6000610b2982610b46565b9050919050565b60008115159050919050565b6000819050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b82818337600083830152505050565b610b8882610bdf565b810181811067ffffffffffffffff82111715610ba757610ba6610bb0565b5b80604052505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000601f19601f8301169050919050565b7f737472696e67206e616d652c0000000000000000000000000000000000000000600082015250565b7f62797465733332206b65792c0000000000000000000000000000000000000000600082015250565b7f75696e74323536206e6f6e63652c000000000000000000000000000000000000600082015250565b7f4f72646572280000000000000000000000000000000000000000000000000000600082015250565b7f75696e74323536207072656d69756d2c00000000000000000000000000000000600082015250565b7f6164647265737320756e6465726c79696e672c00000000000000000000000000600082015250565b7f6164647265737320766572696679696e67436f6e747261637400000000000000600082015250565b7f75696e74323536206d617475726974792c000000000000000000000000000000600082015250565b7f75696e7432353620636861696e49642c00000000000000000000000000000000600082015250565b7f75696e7432353620646561646c696e652c000000000000000000000000000000600082015250565b7f75696e7432353620657870697279000000000000000000000000000000000000600082015250565b7f2900000000000000000000000000000000000000000000000000000000000000600082015250565b7f737472696e672076657273696f6e2c0000000000000000000000000000000000600082015250565b7f61646472657373207370656e6465722c00000000000000000000000000000000600082015250565b7f5065726d69742800000000000000000000000000000000000000000000000000600082015250565b7f61646472657373206f776e65722c000000000000000000000000000000000000600082015250565b7f61646472657373206d616b65722c000000000000000000000000000000000000600082015250565b7f626f6f6c207661756c742c000000000000000000000000000000000000000000600082015250565b7f75696e74323536207072696e636970616c2c0000000000000000000000000000600082015250565b7f626f6f6c20657869742c00000000000000000000000000000000000000000000600082015250565b7f75696e743235362076616c75652c000000000000000000000000000000000000600082015250565b7f454950373132446f6d61696e2800000000000000000000000000000000000000600082015250565b610f7f81610b1e565b8114610f8a57600080fd5b50565b610f9681610b30565b8114610fa157600080fd5b50565b610fad81610b3c565b8114610fb857600080fd5b50565b610fc481610b66565b8114610fcf57600080fd5b5056fea264697066735822122058fb74935accb8eaea7bf389dce878ecfc8be1490b20b6d10307988c0bb533ca64736f6c63430008040033" + +// DeployHashFake deploys a new Ethereum contract, binding an instance of HashFake to it. +func DeployHashFake(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *HashFake, error) { + parsed, err := abi.JSON(strings.NewReader(HashFakeABI)) + if err != nil { + return common.Address{}, nil, nil, err + } + + address, tx, contract, err := bind.DeployContract(auth, parsed, common.FromHex(HashFakeBin), backend) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &HashFake{HashFakeCaller: HashFakeCaller{contract: contract}, HashFakeTransactor: HashFakeTransactor{contract: contract}, HashFakeFilterer: HashFakeFilterer{contract: contract}}, nil +} + +// HashFake is an auto generated Go binding around an Ethereum contract. +type HashFake struct { + HashFakeCaller // Read-only binding to the contract + HashFakeTransactor // Write-only binding to the contract + HashFakeFilterer // Log filterer for contract events +} + +// HashFakeCaller is an auto generated read-only Go binding around an Ethereum contract. +type HashFakeCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// HashFakeTransactor is an auto generated write-only Go binding around an Ethereum contract. +type HashFakeTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// HashFakeFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type HashFakeFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// HashFakeSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type HashFakeSession struct { + Contract *HashFake // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// HashFakeCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type HashFakeCallerSession struct { + Contract *HashFakeCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// HashFakeTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type HashFakeTransactorSession struct { + Contract *HashFakeTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// HashFakeRaw is an auto generated low-level Go binding around an Ethereum contract. +type HashFakeRaw struct { + Contract *HashFake // Generic contract binding to access the raw methods on +} + +// HashFakeCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type HashFakeCallerRaw struct { + Contract *HashFakeCaller // Generic read-only contract binding to access the raw methods on +} + +// HashFakeTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type HashFakeTransactorRaw struct { + Contract *HashFakeTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewHashFake creates a new instance of HashFake, bound to a specific deployed contract. +func NewHashFake(address common.Address, backend bind.ContractBackend) (*HashFake, error) { + contract, err := bindHashFake(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &HashFake{HashFakeCaller: HashFakeCaller{contract: contract}, HashFakeTransactor: HashFakeTransactor{contract: contract}, HashFakeFilterer: HashFakeFilterer{contract: contract}}, nil +} + +// NewHashFakeCaller creates a new read-only instance of HashFake, bound to a specific deployed contract. +func NewHashFakeCaller(address common.Address, caller bind.ContractCaller) (*HashFakeCaller, error) { + contract, err := bindHashFake(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &HashFakeCaller{contract: contract}, nil +} + +// NewHashFakeTransactor creates a new write-only instance of HashFake, bound to a specific deployed contract. +func NewHashFakeTransactor(address common.Address, transactor bind.ContractTransactor) (*HashFakeTransactor, error) { + contract, err := bindHashFake(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &HashFakeTransactor{contract: contract}, nil +} + +// NewHashFakeFilterer creates a new log filterer instance of HashFake, bound to a specific deployed contract. +func NewHashFakeFilterer(address common.Address, filterer bind.ContractFilterer) (*HashFakeFilterer, error) { + contract, err := bindHashFake(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &HashFakeFilterer{contract: contract}, nil +} + +// bindHashFake binds a generic wrapper to an already deployed contract. +func bindHashFake(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := abi.JSON(strings.NewReader(HashFakeABI)) + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_HashFake *HashFakeRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _HashFake.Contract.HashFakeCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_HashFake *HashFakeRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _HashFake.Contract.HashFakeTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_HashFake *HashFakeRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _HashFake.Contract.HashFakeTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_HashFake *HashFakeCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _HashFake.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_HashFake *HashFakeTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _HashFake.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_HashFake *HashFakeTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _HashFake.Contract.contract.Transact(opts, method, params...) +} + +// DomainTest is a free data retrieval call binding the contract method 0xaf1ef90b. +// +// Solidity: function domainTest(string n, string version, uint256 c, address verifier) pure returns(bytes32) +func (_HashFake *HashFakeCaller) DomainTest(opts *bind.CallOpts, n string, version string, c *big.Int, verifier common.Address) ([32]byte, error) { + var out []interface{} + err := _HashFake.contract.Call(opts, &out, "domainTest", n, version, c, verifier) + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// DomainTest is a free data retrieval call binding the contract method 0xaf1ef90b. +// +// Solidity: function domainTest(string n, string version, uint256 c, address verifier) pure returns(bytes32) +func (_HashFake *HashFakeSession) DomainTest(n string, version string, c *big.Int, verifier common.Address) ([32]byte, error) { + return _HashFake.Contract.DomainTest(&_HashFake.CallOpts, n, version, c, verifier) +} + +// DomainTest is a free data retrieval call binding the contract method 0xaf1ef90b. +// +// Solidity: function domainTest(string n, string version, uint256 c, address verifier) pure returns(bytes32) +func (_HashFake *HashFakeCallerSession) DomainTest(n string, version string, c *big.Int, verifier common.Address) ([32]byte, error) { + return _HashFake.Contract.DomainTest(&_HashFake.CallOpts, n, version, c, verifier) +} + +// DomainTypeHash is a free data retrieval call binding the contract method 0x97995ecb. +// +// Solidity: function domainTypeHash() pure returns(bytes32) +func (_HashFake *HashFakeCaller) DomainTypeHash(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _HashFake.contract.Call(opts, &out, "domainTypeHash") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// DomainTypeHash is a free data retrieval call binding the contract method 0x97995ecb. +// +// Solidity: function domainTypeHash() pure returns(bytes32) +func (_HashFake *HashFakeSession) DomainTypeHash() ([32]byte, error) { + return _HashFake.Contract.DomainTypeHash(&_HashFake.CallOpts) +} + +// DomainTypeHash is a free data retrieval call binding the contract method 0x97995ecb. +// +// Solidity: function domainTypeHash() pure returns(bytes32) +func (_HashFake *HashFakeCallerSession) DomainTypeHash() ([32]byte, error) { + return _HashFake.Contract.DomainTypeHash(&_HashFake.CallOpts) +} + +// MessageTest is a free data retrieval call binding the contract method 0x4c05b2a1. +// +// Solidity: function messageTest(bytes32 d, bytes32 h) pure returns(bytes32) +func (_HashFake *HashFakeCaller) MessageTest(opts *bind.CallOpts, d [32]byte, h [32]byte) ([32]byte, error) { + var out []interface{} + err := _HashFake.contract.Call(opts, &out, "messageTest", d, h) + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// MessageTest is a free data retrieval call binding the contract method 0x4c05b2a1. +// +// Solidity: function messageTest(bytes32 d, bytes32 h) pure returns(bytes32) +func (_HashFake *HashFakeSession) MessageTest(d [32]byte, h [32]byte) ([32]byte, error) { + return _HashFake.Contract.MessageTest(&_HashFake.CallOpts, d, h) +} + +// MessageTest is a free data retrieval call binding the contract method 0x4c05b2a1. +// +// Solidity: function messageTest(bytes32 d, bytes32 h) pure returns(bytes32) +func (_HashFake *HashFakeCallerSession) MessageTest(d [32]byte, h [32]byte) ([32]byte, error) { + return _HashFake.Contract.MessageTest(&_HashFake.CallOpts, d, h) +} + +// OrderTest is a free data retrieval call binding the contract method 0xe2711de4. +// +// Solidity: function orderTest((bytes32,address,address,bool,bool,uint256,uint256,uint256,uint256) o) pure returns(bytes32) +func (_HashFake *HashFakeCaller) OrderTest(opts *bind.CallOpts, o HashOrder) ([32]byte, error) { + var out []interface{} + err := _HashFake.contract.Call(opts, &out, "orderTest", o) + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// OrderTest is a free data retrieval call binding the contract method 0xe2711de4. +// +// Solidity: function orderTest((bytes32,address,address,bool,bool,uint256,uint256,uint256,uint256) o) pure returns(bytes32) +func (_HashFake *HashFakeSession) OrderTest(o HashOrder) ([32]byte, error) { + return _HashFake.Contract.OrderTest(&_HashFake.CallOpts, o) +} + +// OrderTest is a free data retrieval call binding the contract method 0xe2711de4. +// +// Solidity: function orderTest((bytes32,address,address,bool,bool,uint256,uint256,uint256,uint256) o) pure returns(bytes32) +func (_HashFake *HashFakeCallerSession) OrderTest(o HashOrder) ([32]byte, error) { + return _HashFake.Contract.OrderTest(&_HashFake.CallOpts, o) +} + +// OrderTypeHash is a free data retrieval call binding the contract method 0x91c2600f. +// +// Solidity: function orderTypeHash() pure returns(bytes32) +func (_HashFake *HashFakeCaller) OrderTypeHash(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _HashFake.contract.Call(opts, &out, "orderTypeHash") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// OrderTypeHash is a free data retrieval call binding the contract method 0x91c2600f. +// +// Solidity: function orderTypeHash() pure returns(bytes32) +func (_HashFake *HashFakeSession) OrderTypeHash() ([32]byte, error) { + return _HashFake.Contract.OrderTypeHash(&_HashFake.CallOpts) +} + +// OrderTypeHash is a free data retrieval call binding the contract method 0x91c2600f. +// +// Solidity: function orderTypeHash() pure returns(bytes32) +func (_HashFake *HashFakeCallerSession) OrderTypeHash() ([32]byte, error) { + return _HashFake.Contract.OrderTypeHash(&_HashFake.CallOpts) +} + +// PermitTypeHash is a free data retrieval call binding the contract method 0x10ce43bd. +// +// Solidity: function permitTypeHash() pure returns(bytes32) +func (_HashFake *HashFakeCaller) PermitTypeHash(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _HashFake.contract.Call(opts, &out, "permitTypeHash") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// PermitTypeHash is a free data retrieval call binding the contract method 0x10ce43bd. +// +// Solidity: function permitTypeHash() pure returns(bytes32) +func (_HashFake *HashFakeSession) PermitTypeHash() ([32]byte, error) { + return _HashFake.Contract.PermitTypeHash(&_HashFake.CallOpts) +} + +// PermitTypeHash is a free data retrieval call binding the contract method 0x10ce43bd. +// +// Solidity: function permitTypeHash() pure returns(bytes32) +func (_HashFake *HashFakeCallerSession) PermitTypeHash() ([32]byte, error) { + return _HashFake.Contract.PermitTypeHash(&_HashFake.CallOpts) +} diff --git a/gost/test/fakes/sigfake.go b/gost/test/fakes/sigfake.go new file mode 100644 index 0000000..9f89b46 --- /dev/null +++ b/gost/test/fakes/sigfake.go @@ -0,0 +1,277 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package fakes + +import ( + "math/big" + "strings" + + ethereum "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/event" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription +) + +// SigComponents is an auto generated low-level Go binding around an user-defined struct. +type SigComponents struct { + V uint8 + R [32]byte + S [32]byte +} + +// SigFakeABI is the input ABI used to generate the binding from. +const SigFakeABI = "[{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"h\",\"type\":\"bytes32\"},{\"components\":[{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"r\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"s\",\"type\":\"bytes32\"}],\"internalType\":\"structSig.Components\",\"name\":\"c\",\"type\":\"tuple\"}],\"name\":\"recoverTest\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"sig\",\"type\":\"bytes\"}],\"name\":\"splitTest\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"r\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"s\",\"type\":\"bytes32\"}],\"stateMutability\":\"pure\",\"type\":\"function\"}]" + +// SigFakeBin is the compiled bytecode used for deploying new contracts. +var SigFakeBin = "0x608060405234801561001057600080fd5b50610789806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c8063458b017a1461003b578063ecf888711461006d575b600080fd5b61005560048036038101906100509190610383565b61009d565b60405161006493929190610543565b60405180910390f35b61008760048036038101906100829190610347565b6100b8565b6040516100949190610483565b60405180910390f35b60008060006100ab846100cc565b9250925092509193909250565b60006100c48383610145565b905092915050565b60008060006041845114610115576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161010c90610503565b60405180910390fd5b60008060006020870151925060408701519150606087015160001a90508083839550955095505050509193909250565b60007f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0826040013560001c11156101b1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101a890610523565b60405180910390fd5b601b8260000160208101906101c691906103c4565b60ff1614806101ea5750601c8260000160208101906101e591906103c4565b60ff16145b610229576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610220906104e3565b60405180910390fd5b60018383600001602081019061023f91906103c4565b8460200135856040013560405160008152602001604052604051610266949392919061049e565b6020604051602081039080840390855afa158015610288573d6000803e3d6000fd5b50505060206040510351905092915050565b60006102ad6102a88461059f565b61057a565b9050828152602081018484840111156102c557600080fd5b6102d084828561062a565b509392505050565b6000813590506102e781610725565b92915050565b600082601f8301126102fe57600080fd5b813561030e84826020860161029a565b91505092915050565b60006060828403121561032957600080fd5b81905092915050565b6000813590506103418161073c565b92915050565b6000806080838503121561035a57600080fd5b6000610368858286016102d8565b925050602061037985828601610317565b9150509250929050565b60006020828403121561039557600080fd5b600082013567ffffffffffffffff8111156103af57600080fd5b6103bb848285016102ed565b91505092915050565b6000602082840312156103d657600080fd5b60006103e484828501610332565b91505092915050565b6103f6816105e1565b82525050565b610405816105f3565b82525050565b6000610418601b836105d0565b9150610423826106aa565b602082019050919050565b600061043b6018836105d0565b9150610446826106d3565b602082019050919050565b600061045e601b836105d0565b9150610469826106fc565b602082019050919050565b61047d8161061d565b82525050565b600060208201905061049860008301846103ed565b92915050565b60006080820190506104b360008301876103fc565b6104c06020830186610474565b6104cd60408301856103fc565b6104da60608301846103fc565b95945050505050565b600060208201905081810360008301526104fc8161040b565b9050919050565b6000602082019050818103600083015261051c8161042e565b9050919050565b6000602082019050818103600083015261053c81610451565b9050919050565b60006060820190506105586000830186610474565b61056560208301856103fc565b61057260408301846103fc565b949350505050565b6000610584610595565b90506105908282610639565b919050565b6000604051905090565b600067ffffffffffffffff8211156105ba576105b961066a565b5b6105c382610699565b9050602081019050919050565b600082825260208201905092915050565b60006105ec826105fd565b9050919050565b6000819050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600060ff82169050919050565b82818337600083830152505050565b61064282610699565b810181811067ffffffffffffffff821117156106615761066061066a565b5b80604052505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000601f19601f8301169050919050565b7f696e76616c6964207369676e6174757265202276222076616c75650000000000600082015250565b7f696e76616c6964207369676e6174757265206c656e6774680000000000000000600082015250565b7f696e76616c6964207369676e6174757265202273222076616c75650000000000600082015250565b61072e816105f3565b811461073957600080fd5b50565b6107458161061d565b811461075057600080fd5b5056fea2646970667358221220e63deb792e476d2b8af6643e104292c4051f4dee40d035fb79165a90e45b2aa664736f6c63430008040033" + +// DeploySigFake deploys a new Ethereum contract, binding an instance of SigFake to it. +func DeploySigFake(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *SigFake, error) { + parsed, err := abi.JSON(strings.NewReader(SigFakeABI)) + if err != nil { + return common.Address{}, nil, nil, err + } + + address, tx, contract, err := bind.DeployContract(auth, parsed, common.FromHex(SigFakeBin), backend) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &SigFake{SigFakeCaller: SigFakeCaller{contract: contract}, SigFakeTransactor: SigFakeTransactor{contract: contract}, SigFakeFilterer: SigFakeFilterer{contract: contract}}, nil +} + +// SigFake is an auto generated Go binding around an Ethereum contract. +type SigFake struct { + SigFakeCaller // Read-only binding to the contract + SigFakeTransactor // Write-only binding to the contract + SigFakeFilterer // Log filterer for contract events +} + +// SigFakeCaller is an auto generated read-only Go binding around an Ethereum contract. +type SigFakeCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// SigFakeTransactor is an auto generated write-only Go binding around an Ethereum contract. +type SigFakeTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// SigFakeFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type SigFakeFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// SigFakeSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type SigFakeSession struct { + Contract *SigFake // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// SigFakeCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type SigFakeCallerSession struct { + Contract *SigFakeCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// SigFakeTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type SigFakeTransactorSession struct { + Contract *SigFakeTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// SigFakeRaw is an auto generated low-level Go binding around an Ethereum contract. +type SigFakeRaw struct { + Contract *SigFake // Generic contract binding to access the raw methods on +} + +// SigFakeCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type SigFakeCallerRaw struct { + Contract *SigFakeCaller // Generic read-only contract binding to access the raw methods on +} + +// SigFakeTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type SigFakeTransactorRaw struct { + Contract *SigFakeTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewSigFake creates a new instance of SigFake, bound to a specific deployed contract. +func NewSigFake(address common.Address, backend bind.ContractBackend) (*SigFake, error) { + contract, err := bindSigFake(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &SigFake{SigFakeCaller: SigFakeCaller{contract: contract}, SigFakeTransactor: SigFakeTransactor{contract: contract}, SigFakeFilterer: SigFakeFilterer{contract: contract}}, nil +} + +// NewSigFakeCaller creates a new read-only instance of SigFake, bound to a specific deployed contract. +func NewSigFakeCaller(address common.Address, caller bind.ContractCaller) (*SigFakeCaller, error) { + contract, err := bindSigFake(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &SigFakeCaller{contract: contract}, nil +} + +// NewSigFakeTransactor creates a new write-only instance of SigFake, bound to a specific deployed contract. +func NewSigFakeTransactor(address common.Address, transactor bind.ContractTransactor) (*SigFakeTransactor, error) { + contract, err := bindSigFake(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &SigFakeTransactor{contract: contract}, nil +} + +// NewSigFakeFilterer creates a new log filterer instance of SigFake, bound to a specific deployed contract. +func NewSigFakeFilterer(address common.Address, filterer bind.ContractFilterer) (*SigFakeFilterer, error) { + contract, err := bindSigFake(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &SigFakeFilterer{contract: contract}, nil +} + +// bindSigFake binds a generic wrapper to an already deployed contract. +func bindSigFake(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := abi.JSON(strings.NewReader(SigFakeABI)) + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_SigFake *SigFakeRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _SigFake.Contract.SigFakeCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_SigFake *SigFakeRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _SigFake.Contract.SigFakeTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_SigFake *SigFakeRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _SigFake.Contract.SigFakeTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_SigFake *SigFakeCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _SigFake.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_SigFake *SigFakeTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _SigFake.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_SigFake *SigFakeTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _SigFake.Contract.contract.Transact(opts, method, params...) +} + +// RecoverTest is a free data retrieval call binding the contract method 0xecf88871. +// +// Solidity: function recoverTest(bytes32 h, (uint8,bytes32,bytes32) c) pure returns(address) +func (_SigFake *SigFakeCaller) RecoverTest(opts *bind.CallOpts, h [32]byte, c SigComponents) (common.Address, error) { + var out []interface{} + err := _SigFake.contract.Call(opts, &out, "recoverTest", h, c) + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// RecoverTest is a free data retrieval call binding the contract method 0xecf88871. +// +// Solidity: function recoverTest(bytes32 h, (uint8,bytes32,bytes32) c) pure returns(address) +func (_SigFake *SigFakeSession) RecoverTest(h [32]byte, c SigComponents) (common.Address, error) { + return _SigFake.Contract.RecoverTest(&_SigFake.CallOpts, h, c) +} + +// RecoverTest is a free data retrieval call binding the contract method 0xecf88871. +// +// Solidity: function recoverTest(bytes32 h, (uint8,bytes32,bytes32) c) pure returns(address) +func (_SigFake *SigFakeCallerSession) RecoverTest(h [32]byte, c SigComponents) (common.Address, error) { + return _SigFake.Contract.RecoverTest(&_SigFake.CallOpts, h, c) +} + +// SplitTest is a free data retrieval call binding the contract method 0x458b017a. +// +// Solidity: function splitTest(bytes sig) pure returns(uint8 v, bytes32 r, bytes32 s) +func (_SigFake *SigFakeCaller) SplitTest(opts *bind.CallOpts, sig []byte) (struct { + V uint8 + R [32]byte + S [32]byte +}, error) { + var out []interface{} + err := _SigFake.contract.Call(opts, &out, "splitTest", sig) + + outstruct := new(struct { + V uint8 + R [32]byte + S [32]byte + }) + if err != nil { + return *outstruct, err + } + + outstruct.V = out[0].(uint8) + outstruct.R = out[1].([32]byte) + outstruct.S = out[2].([32]byte) + + return *outstruct, err + +} + +// SplitTest is a free data retrieval call binding the contract method 0x458b017a. +// +// Solidity: function splitTest(bytes sig) pure returns(uint8 v, bytes32 r, bytes32 s) +func (_SigFake *SigFakeSession) SplitTest(sig []byte) (struct { + V uint8 + R [32]byte + S [32]byte +}, error) { + return _SigFake.Contract.SplitTest(&_SigFake.CallOpts, sig) +} + +// SplitTest is a free data retrieval call binding the contract method 0x458b017a. +// +// Solidity: function splitTest(bytes sig) pure returns(uint8 v, bytes32 r, bytes32 s) +func (_SigFake *SigFakeCallerSession) SplitTest(sig []byte) (struct { + V uint8 + R [32]byte + S [32]byte +}, error) { + return _SigFake.Contract.SplitTest(&_SigFake.CallOpts, sig) +} diff --git a/gost/test/marketplace/Abstracts.sol b/gost/test/marketplace/Abstracts.sol new file mode 100644 index 0000000..0773314 --- /dev/null +++ b/gost/test/marketplace/Abstracts.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: UNLICENSED + +pragma solidity 0.8.4; + +abstract contract Erc20 { + function approve(address, uint256) virtual external returns (bool); + function transfer(address, uint256) virtual external returns (bool); + function balanceOf(address) virtual external returns (uint256); + function transferFrom(address, address, uint256) virtual public returns (bool); +} + +abstract contract CErc20 is Erc20 { + function mint(uint256) virtual external returns (uint256); + function redeem(uint256) virtual external returns (uint256); + function redeemUnderlying(uint256) virtual external returns (uint256); + function exchangeRateCurrent() virtual external returns (uint256); +} diff --git a/gost/test/marketplace/CErc20.abi b/gost/test/marketplace/CErc20.abi new file mode 100644 index 0000000..03e1ca1 --- /dev/null +++ b/gost/test/marketplace/CErc20.abi @@ -0,0 +1 @@ +[{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"exchangeRateCurrent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"mint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"redeem","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"redeemUnderlying","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file diff --git a/gost/test/marketplace/CErc20.bin b/gost/test/marketplace/CErc20.bin new file mode 100644 index 0000000..e69de29 diff --git a/gost/test/marketplace/Erc20.abi b/gost/test/marketplace/Erc20.abi new file mode 100644 index 0000000..88abe05 --- /dev/null +++ b/gost/test/marketplace/Erc20.abi @@ -0,0 +1 @@ +[{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file diff --git a/gost/test/marketplace/Erc20.bin b/gost/test/marketplace/Erc20.bin new file mode 100644 index 0000000..e69de29 diff --git a/gost/test/marketplace/MarketPlace.abi b/gost/test/marketplace/MarketPlace.abi new file mode 100644 index 0000000..22cc499 --- /dev/null +++ b/gost/test/marketplace/MarketPlace.abi @@ -0,0 +1 @@ +[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"underlying","type":"address"},{"indexed":true,"internalType":"uint256","name":"maturity","type":"uint256"},{"indexed":false,"internalType":"address","name":"cToken","type":"address"},{"indexed":false,"internalType":"address","name":"zcToken","type":"address"},{"indexed":false,"internalType":"address","name":"vaultTracker","type":"address"}],"name":"Create","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"underlying","type":"address"},{"indexed":true,"internalType":"uint256","name":"maturity","type":"uint256"},{"indexed":false,"internalType":"address","name":"zcTarget","type":"address"},{"indexed":false,"internalType":"address","name":"nTarget","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"CustodialExit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"underlying","type":"address"},{"indexed":true,"internalType":"uint256","name":"maturity","type":"uint256"},{"indexed":false,"internalType":"address","name":"zcTarget","type":"address"},{"indexed":false,"internalType":"address","name":"nTarget","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"CustodialInitiate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"underlying","type":"address"},{"indexed":true,"internalType":"uint256","name":"maturity","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"maturityRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"matured","type":"uint256"}],"name":"Mature","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"underlying","type":"address"},{"indexed":true,"internalType":"uint256","name":"maturity","type":"uint256"},{"indexed":false,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"P2pVaultExchange","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"underlying","type":"address"},{"indexed":true,"internalType":"uint256","name":"maturity","type":"uint256"},{"indexed":false,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"P2pZcTokenExchange","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"underlying","type":"address"},{"indexed":true,"internalType":"uint256","name":"maturity","type":"uint256"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RedeemVaultInterest","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"underlying","type":"address"},{"indexed":true,"internalType":"uint256","name":"maturity","type":"uint256"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"RedeemZcToken","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"underlying","type":"address"},{"indexed":true,"internalType":"uint256","name":"maturity","type":"uint256"},{"indexed":false,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"TransferVaultNotional","type":"event"},{"inputs":[],"name":"admin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"u","type":"address"},{"internalType":"uint256","name":"m","type":"uint256"},{"internalType":"address","name":"t","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"burnZcTokenRemovingNotional","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"a","type":"address"},{"internalType":"uint256","name":"m","type":"uint256"}],"name":"cTokenAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"u","type":"address"},{"internalType":"uint256","name":"m","type":"uint256"},{"internalType":"address","name":"c","type":"address"},{"internalType":"string","name":"n","type":"string"},{"internalType":"string","name":"s","type":"string"},{"internalType":"uint8","name":"d","type":"uint8"}],"name":"createMarket","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"u","type":"address"},{"internalType":"uint256","name":"m","type":"uint256"},{"internalType":"address","name":"z","type":"address"},{"internalType":"address","name":"n","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"custodialExit","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"u","type":"address"},{"internalType":"uint256","name":"m","type":"uint256"},{"internalType":"address","name":"z","type":"address"},{"internalType":"address","name":"n","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"custodialInitiate","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"markets","outputs":[{"internalType":"address","name":"cTokenAddr","type":"address"},{"internalType":"address","name":"zcTokenAddr","type":"address"},{"internalType":"address","name":"vaultAddr","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"mature","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"u","type":"address"},{"internalType":"uint256","name":"m","type":"uint256"}],"name":"matureMarket","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"maturityRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"u","type":"address"},{"internalType":"uint256","name":"m","type":"uint256"},{"internalType":"address","name":"t","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"mintZcTokenAddingNotional","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"u","type":"address"},{"internalType":"uint256","name":"m","type":"uint256"},{"internalType":"address","name":"f","type":"address"},{"internalType":"address","name":"t","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"p2pVaultExchange","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"u","type":"address"},{"internalType":"uint256","name":"m","type":"uint256"},{"internalType":"address","name":"f","type":"address"},{"internalType":"address","name":"t","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"p2pZcTokenExchange","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"u","type":"address"},{"internalType":"uint256","name":"m","type":"uint256"},{"internalType":"address","name":"t","type":"address"}],"name":"redeemVaultInterest","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"u","type":"address"},{"internalType":"uint256","name":"m","type":"uint256"},{"internalType":"address","name":"t","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"redeemZcToken","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"s","type":"address"}],"name":"setSwivelAddress","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"swivel","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"u","type":"address"},{"internalType":"uint256","name":"m","type":"uint256"},{"internalType":"address","name":"t","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"transferVaultNotional","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"u","type":"address"},{"internalType":"uint256","name":"m","type":"uint256"},{"internalType":"address","name":"f","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"transferVaultNotionalFee","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file diff --git a/gost/test/marketplace/MarketPlace.bin b/gost/test/marketplace/MarketPlace.bin new file mode 100644 index 0000000..61deca9 --- /dev/null +++ b/gost/test/marketplace/MarketPlace.bin @@ -0,0 +1 @@ +60a060405234801561001057600080fd5b5033606081901b6080526140156100406000396000818161042501528181610f14015261203501526140156000f3fe60806040523480156200001157600080fd5b50600436106200016c5760003560e01c80638c6b9b4111620000dd578063c86adf7c116200008b578063ef267f2c116200006e578063ef267f2c1462000408578063f851a440146200041f578063f8e51bcb146200044757600080fd5b8063c86adf7c14620003c3578063e5a2aa6214620003f157600080fd5b8063b50a66f711620000c0578063b50a66f7146200037e578063bddbfbe41462000395578063c5ee114d14620003ac57600080fd5b80638c6b9b411462000341578063a11f4856146200035857600080fd5b80633cf9a4e3116200013b5780635db0ae58116200011e5780635db0ae5814620002fc57806365a963aa1462000313578063848f5184146200032a57600080fd5b80633cf9a4e314620002ce5780635292ecf214620002e557600080fd5b8063012b264a146200017157806305e1dc2514620001bc57806317b3bba7146200020057806327ee93be146200028c575b600080fd5b600354620001929073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b62000192620001cd366004620029bf565b73ffffffffffffffffffffffffffffffffffffffff91821660009081526020818152604080832093835292905220541690565b6200025462000211366004620029bf565b600060208181529281526040808220909352908152208054600182015460029092015473ffffffffffffffffffffffffffffffffffffffff918216928216911683565b6040805173ffffffffffffffffffffffffffffffffffffffff94851681529284166020840152921691810191909152606001620001b3565b620002bd6200029d366004620029bf565b600160209081526000928352604080842090915290825290205460ff1681565b6040519015158152602001620001b3565b620002bd620002df36600462002b36565b6200045e565b620002bd620002f636600462002b36565b620005c3565b620002bd6200030d366004620029bf565b62000763565b620002bd6200032436600462002a2b565b62000bb7565b620002bd6200033b36600462002a86565b62000f10565b620002bd6200035236600462002a2b565b6200130b565b6200036f62000369366004620029eb565b62001654565b604051908152602001620001b3565b620002bd6200038f36600462002b36565b62001805565b620002bd620003a636600462002a2b565b62001afe565b6200036f620003bd36600462002b36565b62001d1c565b6200036f620003d4366004620029bf565b600260209081526000928352604080842090915290825290205481565b620002bd620004023660046200299b565b62002031565b620002bd6200041936600462002b36565b62002121565b620001927f000000000000000000000000000000000000000000000000000000000000000081565b620002bd6200045836600462002a2b565b6200240e565b60035460009073ffffffffffffffffffffffffffffffffffffffff16338114620004e9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f73656e646572206d7573742062652053776976656c20636f6e7472616374000060448201526064015b60405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff868116600090815260208181526040808320898452909152908190206002015490517fb326258d00000000000000000000000000000000000000000000000000000000815286831660048201526024810186905291169063b326258d90604401602060405180830381600087803b1580156200057957600080fd5b505af11580156200058e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620005b4919062002b7e565b50600191505b50949350505050565b73ffffffffffffffffffffffffffffffffffffffff8481166000908152602081815260408083208784529091528082206002015490517f1779467300000000000000000000000000000000000000000000000000000000815233600482015285841660248201526044810185905291921690631779467390606401602060405180830381600087803b1580156200065957600080fd5b505af11580156200066e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000694919062002b7e565b620006fc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f7661756c74207472616e73666572206661696c656400000000000000000000006044820152606401620004e0565b6040805133815273ffffffffffffffffffffffffffffffffffffffff858116602083015291810184905285918716907f1d06fe04c445804d7b460d2d5f2fee7c4cc5ba874f3311d2768f849c66cf30989060600160405180910390a3506001949350505050565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260016020908152604080832084845290915281205460ff161562000800576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f6d61726b657420616c7265616479206d617475726564000000000000000000006044820152606401620004e0565b73ffffffffffffffffffffffffffffffffffffffff8084166000908152602081815260408083208684528252918290206001015482517f204f83f9000000000000000000000000000000000000000000000000000000008152925193169263204f83f9926004808201939291829003018186803b1580156200088157600080fd5b505afa15801562000896573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620008bc919062002ba0565b42101562000927576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f6d61747572697479206e6f7420726561636865640000000000000000000000006044820152606401620004e0565b73ffffffffffffffffffffffffffffffffffffffff80841660009081526020818152604080832086845282528083205481517fbd6d894d00000000000000000000000000000000000000000000000000000000815291519394169263bd6d894d9260048084019391929182900301818787803b158015620009a757600080fd5b505af1158015620009bc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620009e2919062002ba0565b73ffffffffffffffffffffffffffffffffffffffff80861660008181526002602081815260408084208a8552825280842087905584845260018083528185208b8652835281852080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169091179055938352828152838320898452815291839020015482517f6b868d51000000000000000000000000000000000000000000000000000000008152925194955090921692636b868d5192600480840193919291829003018186803b15801562000ab857600080fd5b505afa15801562000acd573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000af3919062002b7e565b62000b5b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f6d61747572697479206e6f7420726561636865640000000000000000000000006044820152606401620004e0565b6040805142815260208101839052849173ffffffffffffffffffffffffffffffffffffffff8716917e80e09d7b4544aa5a923873be1df3e31945593d40cb1c874d99259ec3ac43a4910160405180910390a35060019392505050565b60035460009073ffffffffffffffffffffffffffffffffffffffff1633811462000c3e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f73656e646572206d7573742062652053776976656c20636f6e747261637400006044820152606401620004e0565b73ffffffffffffffffffffffffffffffffffffffff8781166000908152602081815260408083208a8452909152908190206001015490517f9dc29fac000000000000000000000000000000000000000000000000000000008152878316600482015260248101869052911690639dc29fac90604401602060405180830381600087803b15801562000cce57600080fd5b505af115801562000ce3573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000d09919062002b7e565b62000d71576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f7a63546f6b656e206275726e206661696c6564000000000000000000000000006044820152606401620004e0565b73ffffffffffffffffffffffffffffffffffffffff8781166000908152602081815260408083208a8452909152908190206001015490517f40c10f190000000000000000000000000000000000000000000000000000000081528683166004820152602481018690529116906340c10f1990604401602060405180830381600087803b15801562000e0157600080fd5b505af115801562000e16573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000e3c919062002b7e565b62000ea4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f7a63546f6b656e206d696e74206661696c6564000000000000000000000000006044820152606401620004e0565b6040805173ffffffffffffffffffffffffffffffffffffffff8781168252868116602083015291810185905287918916907f86ac24e4ee753e21fb51afa847265cb350e500593f3204057e40079c3ef54422906060015b60405180910390a35060019695505050505050565b60007f00000000000000000000000000000000000000000000000000000000000000003373ffffffffffffffffffffffffffffffffffffffff82161462000fb4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f73656e646572206d7573742062652061646d696e0000000000000000000000006044820152606401620004e0565b60035473ffffffffffffffffffffffffffffffffffffffff1662001035576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f73776976656c20636f6e74726163742061646472657373206e6f7420736574006044820152606401620004e0565b600088888787876040516200104a90620028a8565b6200105a95949392919062002c25565b604051809103906000f08015801562001077573d6000803e3d6000fd5b50905060008888600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16604051620010af90620028b6565b92835273ffffffffffffffffffffffffffffffffffffffff9182166020840152166040820152606001604051809103906000f080158015620010f5573d6000803e3d6000fd5b50905060405180606001604052808973ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1681526020018273ffffffffffffffffffffffffffffffffffffffff168152506000808c73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008b815260200190815260200160002060008201518160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060208201518160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550905050888a73ffffffffffffffffffffffffffffffffffffffff167f1747a3ed83b35b999b9000df0690f6563f6b016a1cce0c8dfc911866d3b921778a8585604051620012f39392919073ffffffffffffffffffffffffffffffffffffffff93841681529183166020830152909116604082015260600190565b60405180910390a35060019998505050505050505050565b60035460009073ffffffffffffffffffffffffffffffffffffffff1633811462001392576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f73656e646572206d7573742062652053776976656c20636f6e747261637400006044820152606401620004e0565b73ffffffffffffffffffffffffffffffffffffffff8781166000908152602081815260408083208a8452909152908190206001015490517f9dc29fac000000000000000000000000000000000000000000000000000000008152878316600482015260248101869052911690639dc29fac90604401602060405180830381600087803b1580156200142257600080fd5b505af115801562001437573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200145d919062002b7e565b620014c5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f6275726e206661696c65640000000000000000000000000000000000000000006044820152606401620004e0565b73ffffffffffffffffffffffffffffffffffffffff8781166000908152602081815260408083208a8452909152908190206002015490517f613a28d100000000000000000000000000000000000000000000000000000000815286831660048201526024810186905291169063613a28d190604401602060405180830381600087803b1580156200155557600080fd5b505af11580156200156a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001590919062002b7e565b620015f8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f72656d6f7665206e6f74696f6e616c206661696c6564000000000000000000006044820152606401620004e0565b6040805173ffffffffffffffffffffffffffffffffffffffff8781168252868116602083015291810185905287918916907f219a55ae9a5a1822159d55db6dd594a28be30b02c0d18a71469ef28030b3fb599060600162000efb565b60035460009073ffffffffffffffffffffffffffffffffffffffff16338114620016db576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f73656e646572206d7573742062652053776976656c20636f6e747261637400006044820152606401620004e0565b73ffffffffffffffffffffffffffffffffffffffff8581166000908152602081815260408083208884529091528082206002015490517f19caf46c0000000000000000000000000000000000000000000000000000000081528684166004820152919216906319caf46c90602401602060405180830381600087803b1580156200176457600080fd5b505af115801562001779573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200179f919062002ba0565b90508373ffffffffffffffffffffffffffffffffffffffff16858773ffffffffffffffffffffffffffffffffffffffff167f646390328280b54978a07e7bd72dd9b3f9515286196024882943a96d5c27987460405160405180910390a495945050505050565b60035460009073ffffffffffffffffffffffffffffffffffffffff163381146200188c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f73656e646572206d7573742062652053776976656c20636f6e747261637400006044820152606401620004e0565b73ffffffffffffffffffffffffffffffffffffffff868116600090815260208181526040808320898452909152908190206001015490517f9dc29fac000000000000000000000000000000000000000000000000000000008152868316600482015260248101869052911690639dc29fac90604401602060405180830381600087803b1580156200191c57600080fd5b505af115801562001931573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001957919062002b7e565b620019bf576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f6275726e206661696c65640000000000000000000000000000000000000000006044820152606401620004e0565b73ffffffffffffffffffffffffffffffffffffffff868116600090815260208181526040808320898452909152908190206002015490517f613a28d100000000000000000000000000000000000000000000000000000000815286831660048201526024810186905291169063613a28d190604401602060405180830381600087803b15801562001a4f57600080fd5b505af115801562001a64573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001a8a919062002b7e565b62001af2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f72656d6f7665206e6f74696f6e616c206661696c6564000000000000000000006044820152606401620004e0565b50600195945050505050565b60035460009073ffffffffffffffffffffffffffffffffffffffff1633811462001b85576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f73656e646572206d7573742062652053776976656c20636f6e747261637400006044820152606401620004e0565b73ffffffffffffffffffffffffffffffffffffffff8781166000908152602081815260408083208a8452909152908190206002015490517f177946730000000000000000000000000000000000000000000000000000000081528783166004820152868316602482015260448101869052911690631779467390606401602060405180830381600087803b15801562001c1d57600080fd5b505af115801562001c32573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001c58919062002b7e565b62001cc0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f7472616e73666572206e6f74696f6e616c206661696c656400000000000000006044820152606401620004e0565b6040805173ffffffffffffffffffffffffffffffffffffffff8781168252868116602083015291810185905287918916907f31d266c2b6075063717026bd27ba8bb527366457893dc211091b2e1d9713f1529060600162000efb565b60035460009073ffffffffffffffffffffffffffffffffffffffff1633811462001da3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f73656e646572206d7573742062652053776976656c20636f6e747261637400006044820152606401620004e0565b73ffffffffffffffffffffffffffffffffffffffff8087166000818152602081815260408083208a845282528083208151606081018352815487168152600180830154881682860152600290920154909616868301529383529281528282208983529052205460ff168062001e865762001e1e888862000763565b62001e86576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f6661696c656420746f206d617475726520746865206d61726b657400000000006044820152606401620004e0565b60208201516040517f9dc29fac00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff88811660048301526024820188905290911690639dc29fac90604401602060405180830381600087803b15801562001efd57600080fd5b505af115801562001f12573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001f38919062002b7e565b62001fa0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f636f756c64206e6f74206275726e0000000000000000000000000000000000006044820152606401620004e0565b8573ffffffffffffffffffffffffffffffffffffffff16878973ffffffffffffffffffffffffffffffffffffffff167f49dc20daa9f95793b82245100affbf87ad23d1761bdef94975542564f4023e45886040516200200191815260200190565b60405180910390a4806200201a578493505050620005ba565b6200202788888762002757565b93505050620005ba565b60007f00000000000000000000000000000000000000000000000000000000000000003373ffffffffffffffffffffffffffffffffffffffff821614620020d5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f73656e646572206d7573742062652061646d696e0000000000000000000000006044820152606401620004e0565b6003805473ffffffffffffffffffffffffffffffffffffffff85167fffffffffffffffffffffffff00000000000000000000000000000000000000009091161790556001915050919050565b60035460009073ffffffffffffffffffffffffffffffffffffffff16338114620021a8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f73656e646572206d7573742062652053776976656c20636f6e747261637400006044820152606401620004e0565b73ffffffffffffffffffffffffffffffffffffffff868116600090815260208181526040808320898452909152908190206001015490517f40c10f190000000000000000000000000000000000000000000000000000000081528683166004820152602481018690529116906340c10f1990604401602060405180830381600087803b1580156200223857600080fd5b505af11580156200224d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062002273919062002b7e565b620022db576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f6d696e74207a63546f6b656e206661696c6564000000000000000000000000006044820152606401620004e0565b73ffffffffffffffffffffffffffffffffffffffff868116600090815260208181526040808320898452909152908190206002015490517fa01cfffb00000000000000000000000000000000000000000000000000000000815286831660048201526024810186905291169063a01cfffb90604401602060405180830381600087803b1580156200236b57600080fd5b505af115801562002380573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620023a6919062002b7e565b62001af2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f616464206e6f74696f6e616c206661696c6564000000000000000000000000006044820152606401620004e0565b60035460009073ffffffffffffffffffffffffffffffffffffffff1633811462002495576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f73656e646572206d7573742062652053776976656c20636f6e747261637400006044820152606401620004e0565b73ffffffffffffffffffffffffffffffffffffffff8781166000908152602081815260408083208a8452909152908190206001015490517f40c10f190000000000000000000000000000000000000000000000000000000081528783166004820152602481018690529116906340c10f1990604401602060405180830381600087803b1580156200252557600080fd5b505af11580156200253a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062002560919062002b7e565b620025c8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f6d696e74206661696c65640000000000000000000000000000000000000000006044820152606401620004e0565b73ffffffffffffffffffffffffffffffffffffffff8781166000908152602081815260408083208a8452909152908190206002015490517fa01cfffb00000000000000000000000000000000000000000000000000000000815286831660048201526024810186905291169063a01cfffb90604401602060405180830381600087803b1580156200265857600080fd5b505af11580156200266d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062002693919062002b7e565b620026fb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f616464206e6f74696f6e616c206661696c6564000000000000000000000000006044820152606401620004e0565b6040805173ffffffffffffffffffffffffffffffffffffffff8781168252868116602083015291810185905287918916907f8dad4d03bd4209aa6dc2bea238510998bf39bb034bc9c20d52f0bd241fc0c5169060600162000efb565b73ffffffffffffffffffffffffffffffffffffffff808416600081815260026020908152604080832087845282528083205493835282825280832087845282528083205481517fbd6d894d0000000000000000000000000000000000000000000000000000000081529151939586956a52b7d2dcc80cd2e4000000959094929091169263bd6d894d92600480830193919282900301818987803b158015620027fe57600080fd5b505af115801562002813573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062002839919062002ba0565b62002850906a52b7d2dcc80cd2e400000062002cdb565b6200285c919062002ca1565b62002868919062002d1b565b905060006a52b7d2dcc80cd2e400000062002884858462002cdb565b62002890919062002ca1565b90506200289e818562002c86565b9695505050505050565b610a2a8062002d9483390190565b61082280620037be83390190565b803573ffffffffffffffffffffffffffffffffffffffff81168114620028e957600080fd5b919050565b600082601f830112620028ff578081fd5b813567ffffffffffffffff808211156200291d576200291d62002d64565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190828211818310171562002966576200296662002d64565b816040528381528660208588010111156200297f578485fd5b8360208701602083013792830160200193909352509392505050565b600060208284031215620029ad578081fd5b620029b882620028c4565b9392505050565b60008060408385031215620029d2578081fd5b620029dd83620028c4565b946020939093013593505050565b60008060006060848603121562002a00578081fd5b62002a0b84620028c4565b92506020840135915062002a2260408501620028c4565b90509250925092565b600080600080600060a0868803121562002a43578081fd5b62002a4e86620028c4565b94506020860135935062002a6560408701620028c4565b925062002a7560608701620028c4565b949793965091946080013592915050565b60008060008060008060c0878903121562002a9f578081fd5b62002aaa87620028c4565b95506020870135945062002ac160408801620028c4565b9350606087013567ffffffffffffffff8082111562002ade578283fd5b62002aec8a838b01620028ee565b9450608089013591508082111562002b02578283fd5b5062002b1189828a01620028ee565b92505060a087013560ff8116811462002b28578182fd5b809150509295509295509295565b6000806000806080858703121562002b4c578384fd5b62002b5785620028c4565b93506020850135925062002b6e60408601620028c4565b9396929550929360600135925050565b60006020828403121562002b90578081fd5b81518015158114620029b8578182fd5b60006020828403121562002bb2578081fd5b5051919050565b60008151808452815b8181101562002be05760208185018101518683018201520162002bc2565b8181111562002bf25782602083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b73ffffffffffffffffffffffffffffffffffffffff8616815284602082015260a06040820152600062002c5c60a083018662002bb9565b828103606084015262002c70818662002bb9565b91505060ff831660808301529695505050505050565b6000821982111562002c9c5762002c9c62002d35565b500190565b60008262002cd6577f4e487b710000000000000000000000000000000000000000000000000000000081526012600452602481fd5b500490565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048311821515161562002d165762002d1662002d35565b500290565b60008282101562002d305762002d3062002d35565b500390565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fdfe60806040523480156200001157600080fd5b5060405162000a2a38038062000a2a8339810160408190526200003491620001fd565b60058054610100600160a81b0319166101006001600160a01b03881602179055600684905582516200006e906003906020860190620000a4565b50815162000084906004906020850190620000a4565b506005805460ff191660ff9290921691909117905550620002fb92505050565b828054620000b290620002a8565b90600052602060002090601f016020900481019282620000d6576000855562000121565b82601f10620000f157805160ff191683800117855562000121565b8280016001018555821562000121579182015b828111156200012157825182559160200191906001019062000104565b506200012f92915062000133565b5090565b5b808211156200012f576000815560010162000134565b600082601f8301126200015b578081fd5b81516001600160401b0380821115620001785762000178620002e5565b604051601f8301601f19908116603f01168101908282118183101715620001a357620001a3620002e5565b81604052838152602092508683858801011115620001bf578485fd5b8491505b83821015620001e25785820183015181830184015290820190620001c3565b83821115620001f357848385830101525b9695505050505050565b600080600080600060a0868803121562000215578081fd5b85516001600160a01b03811681146200022c578182fd5b6020870151604088015191965094506001600160401b038082111562000250578283fd5b6200025e89838a016200014a565b9450606088015191508082111562000274578283fd5b5062000283888289016200014a565b925050608086015160ff811681146200029a578182fd5b809150509295509295909350565b600181811c90821680620002bd57607f821691505b60208210811415620002df57634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052604160045260246000fd5b61071f806200030b6000396000f3fe608060405234801561001057600080fd5b50600436106101005760003560e01c80639dc29fac11610097578063e541efa211610066578063e541efa214610378578063e7ba6774146103e4578063ee4db5701461043e578063fdfe5f4d1461045e57600080fd5b80639dc29fac146102c7578063b4c4a4c814610306578063b9bb928c14610319578063bba0ad391461035857600080fd5b806340c10f19116100d357806340c10f19146101f05780636521b96a146102345780636f307dc31461027c57806395d89b41146102bf57600080fd5b806306fdde0314610105578063204f83f91461012357806323b872dd14610135578063313ce567146101d1575b600080fd5b61010d6104a3565b60405161011a9190610624565b60405180910390f35b6006545b60405190815260200161011a565b6101c1610143366004610588565b60408051808201825273ffffffffffffffffffffffffffffffffffffffff93841681526020808201938452948416600090815260029095529320925183547fffffffffffffffffffffffff00000000000000000000000000000000000000001692169190911782555160019091015560075462010000900460ff1690565b604051901515815260200161011a565b6005546101de9060ff1681565b60405160ff909116815260200161011a565b6101c16101fe3660046105c3565b73ffffffffffffffffffffffffffffffffffffffff91909116600090815260016020526040902055600754610100900460ff1690565b61027a6102423660046105ec565b6007805491151562010000027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff909216919091179055565b005b600554610100900473ffffffffffffffffffffffffffffffffffffffff1660405173ffffffffffffffffffffffffffffffffffffffff909116815260200161011a565b61010d610531565b6101c16102d53660046105c3565b73ffffffffffffffffffffffffffffffffffffffff9190911660009081526020819052604090205560075460ff1690565b61027a61031436600461060c565b600655565b61027a6103273660046105ec565b600780547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055565b610127610366366004610567565b60006020819052908152604090205481565b6103b8610386366004610567565b6002602052600090815260409020805460019091015473ffffffffffffffffffffffffffffffffffffffff9091169082565b6040805173ffffffffffffffffffffffffffffffffffffffff909316835260208301919091520161011a565b61027a6103f2366004610567565b6005805473ffffffffffffffffffffffffffffffffffffffff909216610100027fffffffffffffffffffffff0000000000000000000000000000000000000000ff909216919091179055565b61012761044c366004610567565b60016020526000908152604090205481565b61027a61046c3660046105ec565b60078054911515610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff909216919091179055565b600380546104b090610695565b80601f01602080910402602001604051908101604052809291908181526020018280546104dc90610695565b80156105295780601f106104fe57610100808354040283529160200191610529565b820191906000526020600020905b81548152906001019060200180831161050c57829003601f168201915b505050505081565b600480546104b090610695565b803573ffffffffffffffffffffffffffffffffffffffff8116811461056257600080fd5b919050565b600060208284031215610578578081fd5b6105818261053e565b9392505050565b60008060006060848603121561059c578182fd5b6105a58461053e565b92506105b36020850161053e565b9150604084013590509250925092565b600080604083850312156105d5578182fd5b6105de8361053e565b946020939093013593505050565b6000602082840312156105fd578081fd5b81358015158114610581578182fd5b60006020828403121561061d578081fd5b5035919050565b6000602080835283518082850152825b8181101561065057858101830151858201604001528201610634565b818111156106615783604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016929092016040019392505050565b600181811c908216806106a957607f821691505b602082108114156106e3577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b5091905056fea2646970667358221220eb8a5eef9e13a196e22e78e58517b46946db88220c910292ae27c5fcd5a37c2964736f6c63430008040033608060405234801561001057600080fd5b5060405161082238038061082283398101604081905261002f91610082565b600792909255600480546001600160a01b039283166001600160a01b031991821617909155600580549290931691161790556100bd565b80516001600160a01b038116811461007d57600080fd5b919050565b600080600060608486031215610096578283fd5b835192506100a660208501610066565b91506100b460408501610066565b90509250925092565b610756806100cc6000396000f3fe608060405234801561001057600080fd5b50600436106101775760003560e01c806382cac89c116100d8578063b7dd34831161008c578063d6cb2c0d11610066578063d6cb2c0d1461057c578063da3de9e91461058f578063e590c362146105ce57600080fd5b8063b7dd3483146104f5578063bbce238614610515578063d0b9d0321461053557600080fd5b8063a701da69116100bd578063a701da6914610453578063b326258d1461049b578063b4c4a4c8146104e257600080fd5b806382cac89c146103ef578063a01cfffb1461040f57600080fd5b80633dfa1f411161012f5780635dfe12ac116101145780635dfe12ac14610359578063613a28d11461039f5780636b868d51146103e457600080fd5b80633dfa1f41146102f25780635c70b7c11461031257600080fd5b8063177946731161016057806317794673146101f457806319caf46c14610291578063204f83f9146102ea57600080fd5b8063012b264a1461017c5780630aa93b9b146101c6575b600080fd5b60055461019c9073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b6101e66101d4366004610663565b60016020526000908152604090205481565b6040519081526020016101bd565b610281610202366004610684565b60408051808201825273ffffffffffffffffffffffffffffffffffffffff93841681526020808201938452948416600090815260029095529320925183547fffffffffffffffffffffffff0000000000000000000000000000000000000000169216919091178255516001909101556009546301000000900460ff1690565b60405190151581526020016101bd565b6101e661029f366004610663565b600680547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9290921691909117905560085490565b6007546101e6565b6101e6610300366004610663565b60006020819052908152604090205481565b6103576103203660046106e8565b60098054911515610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff909216919091179055565b005b6103576103673660046106e8565b6009805491151562010000027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff909216919091179055565b6102816103ad3660046106bf565b73ffffffffffffffffffffffffffffffffffffffff9190911660009081526001602052604090205560095462010000900460ff1690565b60095460ff16610281565b60065461019c9073ffffffffffffffffffffffffffffffffffffffff1681565b61028161041d3660046106bf565b73ffffffffffffffffffffffffffffffffffffffff91909116600090815260208190526040902055600954610100900460ff1690565b6103576104613660046106e8565b60098054911515640100000000027fffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffff909216919091179055565b6102816104a93660046106bf565b73ffffffffffffffffffffffffffffffffffffffff91909116600090815260036020526040902055600954640100000000900460ff1690565b6103576104f0366004610708565b600755565b60045461019c9073ffffffffffffffffffffffffffffffffffffffff1681565b6101e6610523366004610663565b60036020526000908152604090205481565b6103576105433660046106e8565b600980549115156301000000027fffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffff909216919091179055565b61035761058a366004610708565b600855565b61035761059d3660046106e8565b600980547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055565b61060e6105dc366004610663565b6002602052600090815260409020805460019091015473ffffffffffffffffffffffffffffffffffffffff9091169082565b6040805173ffffffffffffffffffffffffffffffffffffffff90931683526020830191909152016101bd565b803573ffffffffffffffffffffffffffffffffffffffff8116811461065e57600080fd5b919050565b600060208284031215610674578081fd5b61067d8261063a565b9392505050565b600080600060608486031215610698578182fd5b6106a18461063a565b92506106af6020850161063a565b9150604084013590509250925092565b600080604083850312156106d1578182fd5b6106da8361063a565b946020939093013593505050565b6000602082840312156106f9578081fd5b8135801515811461067d578182fd5b600060208284031215610719578081fd5b503591905056fea26469706673582212202ce12b1980bd5f82baa5e2ebd47a5978b9f4251b48a4b88ed7b08f2685a21f8e64736f6c63430008040033a26469706673582212207bf7c4d54a4506059c49ac1a544381729f47d9e9facb1921ecb4f8c1746f6a6364736f6c63430008040033 \ No newline at end of file diff --git a/gost/test/marketplace/MarketPlace.sol b/gost/test/marketplace/MarketPlace.sol new file mode 100644 index 0000000..41311a5 --- /dev/null +++ b/gost/test/marketplace/MarketPlace.sol @@ -0,0 +1,259 @@ +// SPDX-License-Identifier: UNLICENSED + +// TODO update to 0.8.4 (or whatever latest is...) + +// NOTE the pattern [underlying, maturity*, cToken, ...] + +pragma solidity 0.8.4; + +import './Abstracts.sol'; +import './ZcToken.sol'; +import './VaultTracker.sol'; + +contract MarketPlace { + struct Market { + address cTokenAddr; + address zcTokenAddr; + address vaultAddr; + } + + mapping (address => mapping (uint256 => Market)) public markets; + mapping (address => mapping (uint256 => bool)) public mature; + mapping (address => mapping (uint256 => uint256)) public maturityRate; + + address public immutable admin; + address public swivel; + + event Create(address indexed underlying, uint256 indexed maturity, address cToken, address zcToken, address vaultTracker); + event Mature(address indexed underlying, uint256 indexed maturity, uint256 maturityRate, uint256 matured); + event RedeemZcToken(address indexed underlying, uint256 indexed maturity, address indexed sender, uint256 amount); + event RedeemVaultInterest(address indexed underlying, uint256 indexed maturity, address indexed sender); + event CustodialInitiate(address indexed underlying, uint256 indexed maturity, address zcTarget, address nTarget, uint256 amount); + event CustodialExit(address indexed underlying, uint256 indexed maturity, address zcTarget, address nTarget, uint256 amount); + event P2pZcTokenExchange(address indexed underlying, uint256 indexed maturity, address from, address to, uint256 amount); + event P2pVaultExchange(address indexed underlying, uint256 indexed maturity, address from, address to, uint256 amount); + event TransferVaultNotional(address indexed underlying, uint256 indexed maturity, address from, address to, uint256 amount); + + constructor() { + admin = msg.sender; + } + + /// @param s Address of the deployed swivel contract + function setSwivelAddress(address s) external onlyAdmin(admin) returns (bool) { + swivel = s; + return true; + } + + /// @notice Allows the owner to create new markets + /// @param u Underlying token address associated with the new market + /// @param m Maturity timestamp of the new market + /// @param c cToken address associated with underlying for the new market + /// @param n Name of the new zcToken market + /// @param s Symbol of the new zcToken market + function createMarket( + address u, + uint256 m, + address c, + string memory n, + string memory s, + uint8 d + ) public onlyAdmin(admin) returns (bool) { + require(swivel != address(0), 'swivel contract address not set'); + // TODO can we live with the factory pattern here both bytecode size wise and CREATE opcode cost wise? + address zctAddr = address(new ZcToken(u, m, n, s, d)); + address vAddr = address(new VaultTracker(m, c, swivel)); + markets[u][m] = Market(c, zctAddr, vAddr); + + emit Create(u, m, c, zctAddr, vAddr); + + return true; + } + + /// @notice Can be called after maturity, allowing all of the zcTokens to earn floating interest on Compound until they release their funds + /// @param u Underlying token address associated with the market + /// @param m Maturity timestamp of the market + function matureMarket(address u, uint256 m) public returns (bool) { + require(!mature[u][m], 'market already matured'); + require(block.timestamp >= ZcToken(markets[u][m].zcTokenAddr).maturity(), "maturity not reached"); + + // set the base maturity cToken exchange rate at maturity to the current cToken exchange rate + uint256 currentExchangeRate = CErc20(markets[u][m].cTokenAddr).exchangeRateCurrent(); + maturityRate[u][m] = currentExchangeRate; + // set the maturity state to true (for zcb market) + mature[u][m] = true; + + // set vault "matured" to true + require(VaultTracker(markets[u][m].vaultAddr).matureVault(), 'maturity not reached'); + + emit Mature(u, m, block.timestamp, currentExchangeRate); + + return true; + } + + /// @notice Allows Swivel caller to deposit their underlying, in the process splitting it - minting both zcTokens and vault notional. + /// @param u Underlying token address associated with the market + /// @param m Maturity timestamp of the market + /// @param t Address of the depositing user + /// @param a Amount of notional being added + function mintZcTokenAddingNotional(address u, uint256 m, address t, uint256 a) external onlySwivel(swivel) returns (bool) { + require(ZcToken(markets[u][m].zcTokenAddr).mint(t, a), 'mint zcToken failed'); + require(VaultTracker(markets[u][m].vaultAddr).addNotional(t, a), 'add notional failed'); + + return true; + } + + /// @notice Allows Swivel caller to deposit/burn both zcTokens + vault notional. This process is "combining" the two and redeeming underlying. + /// @param u Underlying token address associated with the market + /// @param m Maturity timestamp of the market + /// @param t Address of the combining/redeeming user + /// @param a Amount of zcTokens being burned + function burnZcTokenRemovingNotional(address u, uint256 m, address t, uint256 a) external onlySwivel(swivel) returns(bool) { + require(ZcToken(markets[u][m].zcTokenAddr).burn(t, a), 'burn failed'); + require(VaultTracker(markets[u][m].vaultAddr).removeNotional(t, a), 'remove notional failed'); + + return true; + } + + /// @notice Allows (via swivel) zcToken holders to redeem their tokens for underlying tokens after maturity has been reached. + /// @param u Underlying token address associated with the market + /// @param m Maturity timestamp of the market + /// @param t Address of the redeeming user + /// @param a Amount of zcTokens being redeemed + function redeemZcToken(address u, uint256 m, address t, uint256 a) external onlySwivel(swivel) returns (uint256) { + Market memory mkt = markets[u][m]; + bool matured = mature[u][m]; + + if (!matured) { + require(matureMarket(u, m), 'failed to mature the market'); + } + + // burn user's zcTokens + require(ZcToken(mkt.zcTokenAddr).burn(t, a), 'could not burn'); + + emit RedeemZcToken(u, m, t, a); + + if (!matured) { + return a; + } else { + // if the market was already mature the return should include the amount + marginal floating interest generated on Compound since maturity + return calculateReturn(u, m, a); + } + } + + /// @notice Allows Vault owners (via Swivel) to redeem any currently accrued interest + /// @param u Underlying token address associated with the market + /// @param m Maturity timestamp of the market + /// @param t Address of the redeeming user + function redeemVaultInterest(address u, uint256 m, address t) external onlySwivel(swivel) returns (uint256) { + // call to the floating market contract to release the position and calculate the interest generated + uint256 interest = VaultTracker(markets[u][m].vaultAddr).redeemInterest(t); + + emit RedeemVaultInterest(u, m, t); + + return interest; + } + + /// @notice Calculates the total amount of underlying returned including interest generated since the `matureMarket` function has been called + /// @param u Underlying token address associated with the market + /// @param m Maturity timestamp of the market + /// @param a Amount of zcTokens being redeemed + function calculateReturn(address u, uint256 m, uint256 a) internal returns (uint256) { + // calculate difference between the cToken exchange rate @ maturity and the current cToken exchange rate + uint256 yield = ((CErc20(markets[u][m].cTokenAddr).exchangeRateCurrent() * 1e26) / maturityRate[u][m]) - 1e26; + uint256 interest = (yield * a) / 1e26; + + // calculate the total amount of underlying principle to return + return a + interest; + } + + function cTokenAddress(address a, uint256 m) external view returns (address) { + return markets[a][m].cTokenAddr; + } + + /// @notice called by swivel IVFZI && IZFVI + /// @dev call with underlying, maturity, mint-target, add-notional-target and an amount + /// @param u Underlying token address associated with the market + /// @param m Maturity timestamp of the market + /// @param z Recipient of the minted zcToken + /// @param n Recipient of the added notional + /// @param a Amount of zcToken minted and notional added + function custodialInitiate(address u, uint256 m, address z, address n, uint256 a) external onlySwivel(swivel) returns (bool) { + require(ZcToken(markets[u][m].zcTokenAddr).mint(z, a), 'mint failed'); + require(VaultTracker(markets[u][m].vaultAddr).addNotional(n, a), 'add notional failed'); + emit CustodialInitiate(u, m, z, n, a); + return true; + } + + /// @notice called by swivel EVFZE FF EZFVE + /// @dev call with underlying, maturity, burn-target, remove-notional-target and an amount + /// @param u Underlying token address associated with the market + /// @param m Maturity timestamp of the market + /// @param z Owner of the zcToken to be burned + /// @param n Target to remove notional from + /// @param a Amount of zcToken burned and notional removed + function custodialExit(address u, uint256 m, address z, address n, uint256 a) external onlySwivel(swivel) returns (bool) { + require(ZcToken(markets[u][m].zcTokenAddr).burn(z, a), 'burn failed'); + require(VaultTracker(markets[u][m].vaultAddr).removeNotional(n, a), 'remove notional failed'); + emit CustodialExit(u, m, z, n, a); + return true; + } + + /// @notice called by swivel IZFZE, EZFZI + /// @dev call with underlying, maturity, transfer-from, transfer-to, amount + /// @param u Underlying token address associated with the market + /// @param m Maturity timestamp of the market + /// @param f Owner of the zcToken to be burned + /// @param t Target to be minted to + /// @param a Amount of zcToken transfer + function p2pZcTokenExchange(address u, uint256 m, address f, address t, uint256 a) external onlySwivel(swivel) returns (bool) { + require(ZcToken(markets[u][m].zcTokenAddr).burn(f, a), 'zcToken burn failed'); + require(ZcToken(markets[u][m].zcTokenAddr).mint(t, a), 'zcToken mint failed'); + emit P2pZcTokenExchange(u, m, f, t, a); + return true; + } + + /// @notice called by swivel IVFVE, EVFVI + /// @dev call with underlying, maturity, remove-from, add-to, amount + /// @param u Underlying token address associated with the market + /// @param m Maturity timestamp of the market + /// @param f Owner of the notional to be transferred + /// @param t Target to be transferred to + /// @param a Amount of notional transfer + function p2pVaultExchange(address u, uint256 m, address f, address t, uint256 a) external onlySwivel(swivel) returns (bool) { + require(VaultTracker(markets[u][m].vaultAddr).transferNotionalFrom(f, t, a), 'transfer notional failed'); + emit P2pVaultExchange(u, m, f, t, a); + return true; + } + + /// @notice External method giving access to this functionality within a given vault + /// @dev Note that this method calculates yield and interest as well + /// @param u Underlying token address associated with the market + /// @param m Maturity timestamp of the market + /// @param t Target to be transferred to + /// @param a Amount of notional to be transferred + function transferVaultNotional(address u, uint256 m, address t, uint256 a) public returns (bool) { + require(VaultTracker(markets[u][m].vaultAddr).transferNotionalFrom(msg.sender, t, a), 'vault transfer failed'); + emit TransferVaultNotional(u, m, msg.sender, t, a); + return true; + } + + /// @notice transfers notional fee to the Swivel contract without recalculating marginal interest for from + /// @param u Underlying token address associated with the market + /// @param m Maturity timestamp of the market + /// @param f Owner of the amount + /// @param a Amount to transfer + function transferVaultNotionalFee(address u, uint256 m, address f, uint256 a) public onlySwivel(swivel) returns (bool) { + VaultTracker(markets[u][m].vaultAddr).transferNotionalFee(f, a); + return true; + } + + modifier onlyAdmin(address a) { + require(msg.sender == a, 'sender must be admin'); + _; + } + + modifier onlySwivel(address s) { + require(msg.sender == s, 'sender must be Swivel contract'); + _; + } +} diff --git a/gost/test/marketplace/VaultTracker.abi b/gost/test/marketplace/VaultTracker.abi new file mode 100644 index 0000000..df36a83 --- /dev/null +++ b/gost/test/marketplace/VaultTracker.abi @@ -0,0 +1 @@ +[{"inputs":[{"internalType":"uint256","name":"m","type":"uint256"},{"internalType":"address","name":"c","type":"address"},{"internalType":"address","name":"s","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"o","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"addNotional","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"addNotionalCalled","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"b","type":"bool"}],"name":"addNotionalReturns","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"cTokenAddr","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"matureVault","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"b","type":"bool"}],"name":"matureVaultReturns","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"maturity","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"n","type":"uint256"}],"name":"maturityReturns","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"o","type":"address"}],"name":"redeemInterest","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"redeemInterestCalled","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"a","type":"uint256"}],"name":"redeemInterestReturns","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"o","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"removeNotional","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"removeNotionalCalled","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"b","type":"bool"}],"name":"removeNotionalReturns","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"swivel","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"f","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"transferNotionalFee","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"transferNotionalFeeCalled","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"b","type":"bool"}],"name":"transferNotionalFeeReturns","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"f","type":"address"},{"internalType":"address","name":"t","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"transferNotionalFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"transferNotionalFromCalled","outputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"b","type":"bool"}],"name":"transferNotionalFromReturns","outputs":[],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file diff --git a/gost/test/marketplace/VaultTracker.bin b/gost/test/marketplace/VaultTracker.bin new file mode 100644 index 0000000..0792f84 --- /dev/null +++ b/gost/test/marketplace/VaultTracker.bin @@ -0,0 +1 @@ +608060405234801561001057600080fd5b5060405161082238038061082283398101604081905261002f91610082565b600792909255600480546001600160a01b039283166001600160a01b031991821617909155600580549290931691161790556100bd565b80516001600160a01b038116811461007d57600080fd5b919050565b600080600060608486031215610096578283fd5b835192506100a660208501610066565b91506100b460408501610066565b90509250925092565b610756806100cc6000396000f3fe608060405234801561001057600080fd5b50600436106101775760003560e01c806382cac89c116100d8578063b7dd34831161008c578063d6cb2c0d11610066578063d6cb2c0d1461057c578063da3de9e91461058f578063e590c362146105ce57600080fd5b8063b7dd3483146104f5578063bbce238614610515578063d0b9d0321461053557600080fd5b8063a701da69116100bd578063a701da6914610453578063b326258d1461049b578063b4c4a4c8146104e257600080fd5b806382cac89c146103ef578063a01cfffb1461040f57600080fd5b80633dfa1f411161012f5780635dfe12ac116101145780635dfe12ac14610359578063613a28d11461039f5780636b868d51146103e457600080fd5b80633dfa1f41146102f25780635c70b7c11461031257600080fd5b8063177946731161016057806317794673146101f457806319caf46c14610291578063204f83f9146102ea57600080fd5b8063012b264a1461017c5780630aa93b9b146101c6575b600080fd5b60055461019c9073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b6101e66101d4366004610663565b60016020526000908152604090205481565b6040519081526020016101bd565b610281610202366004610684565b60408051808201825273ffffffffffffffffffffffffffffffffffffffff93841681526020808201938452948416600090815260029095529320925183547fffffffffffffffffffffffff0000000000000000000000000000000000000000169216919091178255516001909101556009546301000000900460ff1690565b60405190151581526020016101bd565b6101e661029f366004610663565b600680547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9290921691909117905560085490565b6007546101e6565b6101e6610300366004610663565b60006020819052908152604090205481565b6103576103203660046106e8565b60098054911515610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff909216919091179055565b005b6103576103673660046106e8565b6009805491151562010000027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff909216919091179055565b6102816103ad3660046106bf565b73ffffffffffffffffffffffffffffffffffffffff9190911660009081526001602052604090205560095462010000900460ff1690565b60095460ff16610281565b60065461019c9073ffffffffffffffffffffffffffffffffffffffff1681565b61028161041d3660046106bf565b73ffffffffffffffffffffffffffffffffffffffff91909116600090815260208190526040902055600954610100900460ff1690565b6103576104613660046106e8565b60098054911515640100000000027fffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffff909216919091179055565b6102816104a93660046106bf565b73ffffffffffffffffffffffffffffffffffffffff91909116600090815260036020526040902055600954640100000000900460ff1690565b6103576104f0366004610708565b600755565b60045461019c9073ffffffffffffffffffffffffffffffffffffffff1681565b6101e6610523366004610663565b60036020526000908152604090205481565b6103576105433660046106e8565b600980549115156301000000027fffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffff909216919091179055565b61035761058a366004610708565b600855565b61035761059d3660046106e8565b600980547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055565b61060e6105dc366004610663565b6002602052600090815260409020805460019091015473ffffffffffffffffffffffffffffffffffffffff9091169082565b6040805173ffffffffffffffffffffffffffffffffffffffff90931683526020830191909152016101bd565b803573ffffffffffffffffffffffffffffffffffffffff8116811461065e57600080fd5b919050565b600060208284031215610674578081fd5b61067d8261063a565b9392505050565b600080600060608486031215610698578182fd5b6106a18461063a565b92506106af6020850161063a565b9150604084013590509250925092565b600080604083850312156106d1578182fd5b6106da8361063a565b946020939093013593505050565b6000602082840312156106f9578081fd5b8135801515811461067d578182fd5b600060208284031215610719578081fd5b503591905056fea26469706673582212202ce12b1980bd5f82baa5e2ebd47a5978b9f4251b48a4b88ed7b08f2685a21f8e64736f6c63430008040033 \ No newline at end of file diff --git a/gost/test/marketplace/VaultTracker.sol b/gost/test/marketplace/VaultTracker.sol new file mode 100644 index 0000000..d071e58 --- /dev/null +++ b/gost/test/marketplace/VaultTracker.sol @@ -0,0 +1,113 @@ +// SPDX-License-Identifier: UNLICENSED + +/** + VaultTracker is a mock which records arguments passed to its methods as well as + provides setters allowing us to dictate method return values +*/ + +pragma solidity 0.8.4; + +contract VaultTracker { + struct TransferNotionalFromArgs { + address to; + uint256 amount; + } + + // mapping of arguments sent to addNotional. key is the passed in address. + mapping (address => uint256) public addNotionalCalled; + // mapping of arguments sent to removeNotional. key is the passed in address. + mapping (address => uint256) public removeNotionalCalled; + // mapping of arguments sent to transferNotionalFrom. key is the passed in address. + mapping (address => TransferNotionalFromArgs) public transferNotionalFromCalled; + // mapping of args sent to transferFee, key is the given payer's address + mapping (address => uint256) public transferNotionalFeeCalled; + + address public cTokenAddr; + address public swivel; + address public redeemInterestCalled; + + uint256 private maturityReturn; + uint256 private redeemInterestReturn; + bool private matureVaultReturn; + // a boolean flag which allows us to dictate the return of addNotional(). + bool private addNotionalReturn; + // a boolean flag which allows us to dictate the return of removeNotional(). + bool private removeNotionalReturn; + // a boolean flag which allows us to dictate the return of transferNotionalFrom(). + bool private transferNotionalFromReturn; + bool private transferNotionalFeeReturn; + + /// @param m maturity + /// @param c cToken address + /// @param s deployed swivel contract address + constructor(uint256 m, address c, address s) { + maturityReturn = m; + cTokenAddr = c; + swivel = s; + } + + function redeemInterestReturns(uint256 a) public { + redeemInterestReturn = a; + } + + function redeemInterest(address o) public returns (uint256) { + redeemInterestCalled = o; + return redeemInterestReturn; + } + + function maturityReturns(uint256 n) public { + maturityReturn = n; + } + + // override what would be the autogenerated getter... + function maturity() public view returns (uint256) { + return maturityReturn; + } + + function matureVault() public view returns (bool) { + return matureVaultReturn; + } + + function matureVaultReturns(bool b) public { + matureVaultReturn = b; + } + + function addNotionalReturns(bool b) public { + addNotionalReturn = b; + } + + function addNotional(address o, uint256 a) public returns (bool) { + addNotionalCalled[o] = a; + return addNotionalReturn; + } + + function removeNotionalReturns(bool b) public { + removeNotionalReturn = b; + } + + function removeNotional(address o, uint256 a) public returns (bool) { + removeNotionalCalled[o] = a; + return removeNotionalReturn; + } + + function transferNotionalFromReturns(bool b) public { + transferNotionalFromReturn = b; + } + + function transferNotionalFrom(address f, address t, uint256 a) public returns (bool) { + TransferNotionalFromArgs memory args; + args.to = t; + args.amount = a; + transferNotionalFromCalled[f] = args; + return transferNotionalFromReturn; + } + + function transferNotionalFeeReturns(bool b) public { + transferNotionalFeeReturn = b; + } + + function transferNotionalFee(address f, uint256 a) public returns (bool) { + transferNotionalFeeCalled[f] = a; + return transferNotionalFeeReturn; + } +} diff --git a/gost/test/marketplace/ZcToken.abi b/gost/test/marketplace/ZcToken.abi new file mode 100644 index 0000000..e791d8c --- /dev/null +++ b/gost/test/marketplace/ZcToken.abi @@ -0,0 +1 @@ +[{"inputs":[{"internalType":"address","name":"u","type":"address"},{"internalType":"uint256","name":"m","type":"uint256"},{"internalType":"string","name":"n","type":"string"},{"internalType":"string","name":"s","type":"string"},{"internalType":"uint8","name":"d","type":"uint8"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"f","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"burn","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"burnCalled","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"b","type":"bool"}],"name":"burnReturns","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maturity","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"n","type":"uint256"}],"name":"maturityReturns","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"f","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"mint","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"mintCalled","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"b","type":"bool"}],"name":"mintReturns","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"f","type":"address"},{"internalType":"address","name":"t","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"transferFromCalled","outputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"b","type":"bool"}],"name":"transferFromReturns","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"underlying","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"u","type":"address"}],"name":"underlyingReturns","outputs":[],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file diff --git a/gost/test/marketplace/ZcToken.bin b/gost/test/marketplace/ZcToken.bin new file mode 100644 index 0000000..ef32175 --- /dev/null +++ b/gost/test/marketplace/ZcToken.bin @@ -0,0 +1 @@ +60806040523480156200001157600080fd5b5060405162000a2a38038062000a2a8339810160408190526200003491620001fd565b60058054610100600160a81b0319166101006001600160a01b03881602179055600684905582516200006e906003906020860190620000a4565b50815162000084906004906020850190620000a4565b506005805460ff191660ff9290921691909117905550620002fb92505050565b828054620000b290620002a8565b90600052602060002090601f016020900481019282620000d6576000855562000121565b82601f10620000f157805160ff191683800117855562000121565b8280016001018555821562000121579182015b828111156200012157825182559160200191906001019062000104565b506200012f92915062000133565b5090565b5b808211156200012f576000815560010162000134565b600082601f8301126200015b578081fd5b81516001600160401b0380821115620001785762000178620002e5565b604051601f8301601f19908116603f01168101908282118183101715620001a357620001a3620002e5565b81604052838152602092508683858801011115620001bf578485fd5b8491505b83821015620001e25785820183015181830184015290820190620001c3565b83821115620001f357848385830101525b9695505050505050565b600080600080600060a0868803121562000215578081fd5b85516001600160a01b03811681146200022c578182fd5b6020870151604088015191965094506001600160401b038082111562000250578283fd5b6200025e89838a016200014a565b9450606088015191508082111562000274578283fd5b5062000283888289016200014a565b925050608086015160ff811681146200029a578182fd5b809150509295509295909350565b600181811c90821680620002bd57607f821691505b60208210811415620002df57634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052604160045260246000fd5b61071f806200030b6000396000f3fe608060405234801561001057600080fd5b50600436106101005760003560e01c80639dc29fac11610097578063e541efa211610066578063e541efa214610378578063e7ba6774146103e4578063ee4db5701461043e578063fdfe5f4d1461045e57600080fd5b80639dc29fac146102c7578063b4c4a4c814610306578063b9bb928c14610319578063bba0ad391461035857600080fd5b806340c10f19116100d357806340c10f19146101f05780636521b96a146102345780636f307dc31461027c57806395d89b41146102bf57600080fd5b806306fdde0314610105578063204f83f91461012357806323b872dd14610135578063313ce567146101d1575b600080fd5b61010d6104a3565b60405161011a9190610624565b60405180910390f35b6006545b60405190815260200161011a565b6101c1610143366004610588565b60408051808201825273ffffffffffffffffffffffffffffffffffffffff93841681526020808201938452948416600090815260029095529320925183547fffffffffffffffffffffffff00000000000000000000000000000000000000001692169190911782555160019091015560075462010000900460ff1690565b604051901515815260200161011a565b6005546101de9060ff1681565b60405160ff909116815260200161011a565b6101c16101fe3660046105c3565b73ffffffffffffffffffffffffffffffffffffffff91909116600090815260016020526040902055600754610100900460ff1690565b61027a6102423660046105ec565b6007805491151562010000027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff909216919091179055565b005b600554610100900473ffffffffffffffffffffffffffffffffffffffff1660405173ffffffffffffffffffffffffffffffffffffffff909116815260200161011a565b61010d610531565b6101c16102d53660046105c3565b73ffffffffffffffffffffffffffffffffffffffff9190911660009081526020819052604090205560075460ff1690565b61027a61031436600461060c565b600655565b61027a6103273660046105ec565b600780547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055565b610127610366366004610567565b60006020819052908152604090205481565b6103b8610386366004610567565b6002602052600090815260409020805460019091015473ffffffffffffffffffffffffffffffffffffffff9091169082565b6040805173ffffffffffffffffffffffffffffffffffffffff909316835260208301919091520161011a565b61027a6103f2366004610567565b6005805473ffffffffffffffffffffffffffffffffffffffff909216610100027fffffffffffffffffffffff0000000000000000000000000000000000000000ff909216919091179055565b61012761044c366004610567565b60016020526000908152604090205481565b61027a61046c3660046105ec565b60078054911515610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff909216919091179055565b600380546104b090610695565b80601f01602080910402602001604051908101604052809291908181526020018280546104dc90610695565b80156105295780601f106104fe57610100808354040283529160200191610529565b820191906000526020600020905b81548152906001019060200180831161050c57829003601f168201915b505050505081565b600480546104b090610695565b803573ffffffffffffffffffffffffffffffffffffffff8116811461056257600080fd5b919050565b600060208284031215610578578081fd5b6105818261053e565b9392505050565b60008060006060848603121561059c578182fd5b6105a58461053e565b92506105b36020850161053e565b9150604084013590509250925092565b600080604083850312156105d5578182fd5b6105de8361053e565b946020939093013593505050565b6000602082840312156105fd578081fd5b81358015158114610581578182fd5b60006020828403121561061d578081fd5b5035919050565b6000602080835283518082850152825b8181101561065057858101830151858201604001528201610634565b818111156106615783604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016929092016040019392505050565b600181811c908216806106a957607f821691505b602082108114156106e3577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b5091905056fea2646970667358221220eb8a5eef9e13a196e22e78e58517b46946db88220c910292ae27c5fcd5a37c2964736f6c63430008040033 \ No newline at end of file diff --git a/gost/test/marketplace/ZcToken.sol b/gost/test/marketplace/ZcToken.sol new file mode 100644 index 0000000..2798eac --- /dev/null +++ b/gost/test/marketplace/ZcToken.sol @@ -0,0 +1,98 @@ +// SPDX-License-Identifier: UNLICENSED + +/** + ZcToken is a mock which records arguments passed to its methods as well as + provides setters allowing us to dictate method return values +*/ + +pragma solidity 0.8.4; + +contract ZcToken { + // a struct to hold the arguments passed to transferFrom + struct TransferFromArgs { + address to; + uint256 amount; + } + + // mapping of arguments sent to burn. key is the passed in address. + mapping (address => uint256) public burnCalled; + // mapping of arguments sent to mint. key is the passed in address. + mapping (address => uint256) public mintCalled; + // mapping of arguments sent to transferFrom. key is passed from address. + mapping (address => TransferFromArgs) public transferFromCalled; + + string public name; + string public symbol; + uint8 public decimals; + address private underlyingReturn; + uint256 private maturityReturn; + // a boolean flag which allows us to dictate the return of burn(). + bool private burnReturn; + // a boolean flag which allows us to dictate the return of mint(). + bool private mintReturn; + // a boolean flag which allows us to dictate the return of transferFrom(). + bool private transferFromReturn; + + /// @param u Underlying + /// @param m Maturity + /// @param n Name + /// @param s Symbol + /// @param d Decimals + constructor(address u, uint256 m, string memory n, string memory s, uint8 d) { + // we can set the privates in the constructor as well... + underlyingReturn = u; + maturityReturn = m; + + name = n; + symbol = s; + decimals = d; + } + + function burnReturns(bool b) public { + burnReturn = b; + } + + function burn(address f, uint256 a) public returns(bool) { + burnCalled[f] = a; + return burnReturn; + } + + function mintReturns(bool b) public { + mintReturn = b; + } + + function mint(address f, uint256 a) public returns(bool) { + mintCalled[f] = a; + return mintReturn; + } + + function underlyingReturns(address u) public { + underlyingReturn = u; + } + + // override what would be the autogenerated getter... + function underlying() public view returns (address) { + return underlyingReturn; + } + + function maturityReturns(uint256 n) public { + maturityReturn = n; + } + + // override what would be the autogenerated getter... + function maturity() public view returns (uint256) { + return maturityReturn; + } + + function transferFrom(address f, address t, uint256 a) public returns (bool) { + TransferFromArgs memory args; + args.to = t; + args.amount = a; + transferFromCalled[f] = args; + return transferFromReturn; + } + + function transferFromReturns(bool b) public { + transferFromReturn = b; + } +} diff --git a/gost/test/marketplace/marketplace.go b/gost/test/marketplace/marketplace.go new file mode 100644 index 0000000..262726a --- /dev/null +++ b/gost/test/marketplace/marketplace.go @@ -0,0 +1,2083 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package marketplace + +import ( + "math/big" + "strings" + + ethereum "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/event" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription +) + +// MarketPlaceABI is the input ABI used to generate the binding from. +const MarketPlaceABI = "[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"underlying\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"maturity\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"cToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"zcToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"vaultTracker\",\"type\":\"address\"}],\"name\":\"Create\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"underlying\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"maturity\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"zcTarget\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"nTarget\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"CustodialExit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"underlying\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"maturity\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"zcTarget\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"nTarget\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"CustodialInitiate\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"underlying\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"maturity\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"maturityRate\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"matured\",\"type\":\"uint256\"}],\"name\":\"Mature\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"underlying\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"maturity\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"P2pVaultExchange\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"underlying\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"maturity\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"P2pZcTokenExchange\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"underlying\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"maturity\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RedeemVaultInterest\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"underlying\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"maturity\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"RedeemZcToken\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"underlying\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"maturity\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"TransferVaultNotional\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"admin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"u\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"m\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"t\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"a\",\"type\":\"uint256\"}],\"name\":\"burnZcTokenRemovingNotional\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"a\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"m\",\"type\":\"uint256\"}],\"name\":\"cTokenAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"u\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"m\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"c\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"n\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"s\",\"type\":\"string\"},{\"internalType\":\"uint8\",\"name\":\"d\",\"type\":\"uint8\"}],\"name\":\"createMarket\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"u\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"m\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"z\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"n\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"a\",\"type\":\"uint256\"}],\"name\":\"custodialExit\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"u\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"m\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"z\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"n\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"a\",\"type\":\"uint256\"}],\"name\":\"custodialInitiate\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"markets\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"cTokenAddr\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"zcTokenAddr\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"vaultAddr\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"mature\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"u\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"m\",\"type\":\"uint256\"}],\"name\":\"matureMarket\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"maturityRate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"u\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"m\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"t\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"a\",\"type\":\"uint256\"}],\"name\":\"mintZcTokenAddingNotional\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"u\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"m\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"f\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"t\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"a\",\"type\":\"uint256\"}],\"name\":\"p2pVaultExchange\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"u\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"m\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"f\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"t\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"a\",\"type\":\"uint256\"}],\"name\":\"p2pZcTokenExchange\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"u\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"m\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"t\",\"type\":\"address\"}],\"name\":\"redeemVaultInterest\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"u\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"m\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"t\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"a\",\"type\":\"uint256\"}],\"name\":\"redeemZcToken\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"s\",\"type\":\"address\"}],\"name\":\"setSwivelAddress\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"swivel\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"u\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"m\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"t\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"a\",\"type\":\"uint256\"}],\"name\":\"transferVaultNotional\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"u\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"m\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"f\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"a\",\"type\":\"uint256\"}],\"name\":\"transferVaultNotionalFee\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]" + +// MarketPlaceBin is the compiled bytecode used for deploying new contracts. +var MarketPlaceBin = "0x60a060405234801561001057600080fd5b5033606081901b6080526140156100406000396000818161042501528181610f14015261203501526140156000f3fe60806040523480156200001157600080fd5b50600436106200016c5760003560e01c80638c6b9b4111620000dd578063c86adf7c116200008b578063ef267f2c116200006e578063ef267f2c1462000408578063f851a440146200041f578063f8e51bcb146200044757600080fd5b8063c86adf7c14620003c3578063e5a2aa6214620003f157600080fd5b8063b50a66f711620000c0578063b50a66f7146200037e578063bddbfbe41462000395578063c5ee114d14620003ac57600080fd5b80638c6b9b411462000341578063a11f4856146200035857600080fd5b80633cf9a4e3116200013b5780635db0ae58116200011e5780635db0ae5814620002fc57806365a963aa1462000313578063848f5184146200032a57600080fd5b80633cf9a4e314620002ce5780635292ecf214620002e557600080fd5b8063012b264a146200017157806305e1dc2514620001bc57806317b3bba7146200020057806327ee93be146200028c575b600080fd5b600354620001929073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b62000192620001cd366004620029bf565b73ffffffffffffffffffffffffffffffffffffffff91821660009081526020818152604080832093835292905220541690565b6200025462000211366004620029bf565b600060208181529281526040808220909352908152208054600182015460029092015473ffffffffffffffffffffffffffffffffffffffff918216928216911683565b6040805173ffffffffffffffffffffffffffffffffffffffff94851681529284166020840152921691810191909152606001620001b3565b620002bd6200029d366004620029bf565b600160209081526000928352604080842090915290825290205460ff1681565b6040519015158152602001620001b3565b620002bd620002df36600462002b36565b6200045e565b620002bd620002f636600462002b36565b620005c3565b620002bd6200030d366004620029bf565b62000763565b620002bd6200032436600462002a2b565b62000bb7565b620002bd6200033b36600462002a86565b62000f10565b620002bd6200035236600462002a2b565b6200130b565b6200036f62000369366004620029eb565b62001654565b604051908152602001620001b3565b620002bd6200038f36600462002b36565b62001805565b620002bd620003a636600462002a2b565b62001afe565b6200036f620003bd36600462002b36565b62001d1c565b6200036f620003d4366004620029bf565b600260209081526000928352604080842090915290825290205481565b620002bd620004023660046200299b565b62002031565b620002bd6200041936600462002b36565b62002121565b620001927f000000000000000000000000000000000000000000000000000000000000000081565b620002bd6200045836600462002a2b565b6200240e565b60035460009073ffffffffffffffffffffffffffffffffffffffff16338114620004e9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f73656e646572206d7573742062652053776976656c20636f6e7472616374000060448201526064015b60405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff868116600090815260208181526040808320898452909152908190206002015490517fb326258d00000000000000000000000000000000000000000000000000000000815286831660048201526024810186905291169063b326258d90604401602060405180830381600087803b1580156200057957600080fd5b505af11580156200058e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620005b4919062002b7e565b50600191505b50949350505050565b73ffffffffffffffffffffffffffffffffffffffff8481166000908152602081815260408083208784529091528082206002015490517f1779467300000000000000000000000000000000000000000000000000000000815233600482015285841660248201526044810185905291921690631779467390606401602060405180830381600087803b1580156200065957600080fd5b505af11580156200066e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000694919062002b7e565b620006fc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f7661756c74207472616e73666572206661696c656400000000000000000000006044820152606401620004e0565b6040805133815273ffffffffffffffffffffffffffffffffffffffff858116602083015291810184905285918716907f1d06fe04c445804d7b460d2d5f2fee7c4cc5ba874f3311d2768f849c66cf30989060600160405180910390a3506001949350505050565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260016020908152604080832084845290915281205460ff161562000800576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f6d61726b657420616c7265616479206d617475726564000000000000000000006044820152606401620004e0565b73ffffffffffffffffffffffffffffffffffffffff8084166000908152602081815260408083208684528252918290206001015482517f204f83f9000000000000000000000000000000000000000000000000000000008152925193169263204f83f9926004808201939291829003018186803b1580156200088157600080fd5b505afa15801562000896573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620008bc919062002ba0565b42101562000927576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f6d61747572697479206e6f7420726561636865640000000000000000000000006044820152606401620004e0565b73ffffffffffffffffffffffffffffffffffffffff80841660009081526020818152604080832086845282528083205481517fbd6d894d00000000000000000000000000000000000000000000000000000000815291519394169263bd6d894d9260048084019391929182900301818787803b158015620009a757600080fd5b505af1158015620009bc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620009e2919062002ba0565b73ffffffffffffffffffffffffffffffffffffffff80861660008181526002602081815260408084208a8552825280842087905584845260018083528185208b8652835281852080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169091179055938352828152838320898452815291839020015482517f6b868d51000000000000000000000000000000000000000000000000000000008152925194955090921692636b868d5192600480840193919291829003018186803b15801562000ab857600080fd5b505afa15801562000acd573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000af3919062002b7e565b62000b5b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f6d61747572697479206e6f7420726561636865640000000000000000000000006044820152606401620004e0565b6040805142815260208101839052849173ffffffffffffffffffffffffffffffffffffffff8716917e80e09d7b4544aa5a923873be1df3e31945593d40cb1c874d99259ec3ac43a4910160405180910390a35060019392505050565b60035460009073ffffffffffffffffffffffffffffffffffffffff1633811462000c3e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f73656e646572206d7573742062652053776976656c20636f6e747261637400006044820152606401620004e0565b73ffffffffffffffffffffffffffffffffffffffff8781166000908152602081815260408083208a8452909152908190206001015490517f9dc29fac000000000000000000000000000000000000000000000000000000008152878316600482015260248101869052911690639dc29fac90604401602060405180830381600087803b15801562000cce57600080fd5b505af115801562000ce3573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000d09919062002b7e565b62000d71576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f7a63546f6b656e206275726e206661696c6564000000000000000000000000006044820152606401620004e0565b73ffffffffffffffffffffffffffffffffffffffff8781166000908152602081815260408083208a8452909152908190206001015490517f40c10f190000000000000000000000000000000000000000000000000000000081528683166004820152602481018690529116906340c10f1990604401602060405180830381600087803b15801562000e0157600080fd5b505af115801562000e16573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000e3c919062002b7e565b62000ea4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f7a63546f6b656e206d696e74206661696c6564000000000000000000000000006044820152606401620004e0565b6040805173ffffffffffffffffffffffffffffffffffffffff8781168252868116602083015291810185905287918916907f86ac24e4ee753e21fb51afa847265cb350e500593f3204057e40079c3ef54422906060015b60405180910390a35060019695505050505050565b60007f00000000000000000000000000000000000000000000000000000000000000003373ffffffffffffffffffffffffffffffffffffffff82161462000fb4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f73656e646572206d7573742062652061646d696e0000000000000000000000006044820152606401620004e0565b60035473ffffffffffffffffffffffffffffffffffffffff1662001035576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f73776976656c20636f6e74726163742061646472657373206e6f7420736574006044820152606401620004e0565b600088888787876040516200104a90620028a8565b6200105a95949392919062002c25565b604051809103906000f08015801562001077573d6000803e3d6000fd5b50905060008888600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16604051620010af90620028b6565b92835273ffffffffffffffffffffffffffffffffffffffff9182166020840152166040820152606001604051809103906000f080158015620010f5573d6000803e3d6000fd5b50905060405180606001604052808973ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1681526020018273ffffffffffffffffffffffffffffffffffffffff168152506000808c73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008b815260200190815260200160002060008201518160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060208201518160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550905050888a73ffffffffffffffffffffffffffffffffffffffff167f1747a3ed83b35b999b9000df0690f6563f6b016a1cce0c8dfc911866d3b921778a8585604051620012f39392919073ffffffffffffffffffffffffffffffffffffffff93841681529183166020830152909116604082015260600190565b60405180910390a35060019998505050505050505050565b60035460009073ffffffffffffffffffffffffffffffffffffffff1633811462001392576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f73656e646572206d7573742062652053776976656c20636f6e747261637400006044820152606401620004e0565b73ffffffffffffffffffffffffffffffffffffffff8781166000908152602081815260408083208a8452909152908190206001015490517f9dc29fac000000000000000000000000000000000000000000000000000000008152878316600482015260248101869052911690639dc29fac90604401602060405180830381600087803b1580156200142257600080fd5b505af115801562001437573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200145d919062002b7e565b620014c5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f6275726e206661696c65640000000000000000000000000000000000000000006044820152606401620004e0565b73ffffffffffffffffffffffffffffffffffffffff8781166000908152602081815260408083208a8452909152908190206002015490517f613a28d100000000000000000000000000000000000000000000000000000000815286831660048201526024810186905291169063613a28d190604401602060405180830381600087803b1580156200155557600080fd5b505af11580156200156a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001590919062002b7e565b620015f8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f72656d6f7665206e6f74696f6e616c206661696c6564000000000000000000006044820152606401620004e0565b6040805173ffffffffffffffffffffffffffffffffffffffff8781168252868116602083015291810185905287918916907f219a55ae9a5a1822159d55db6dd594a28be30b02c0d18a71469ef28030b3fb599060600162000efb565b60035460009073ffffffffffffffffffffffffffffffffffffffff16338114620016db576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f73656e646572206d7573742062652053776976656c20636f6e747261637400006044820152606401620004e0565b73ffffffffffffffffffffffffffffffffffffffff8581166000908152602081815260408083208884529091528082206002015490517f19caf46c0000000000000000000000000000000000000000000000000000000081528684166004820152919216906319caf46c90602401602060405180830381600087803b1580156200176457600080fd5b505af115801562001779573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200179f919062002ba0565b90508373ffffffffffffffffffffffffffffffffffffffff16858773ffffffffffffffffffffffffffffffffffffffff167f646390328280b54978a07e7bd72dd9b3f9515286196024882943a96d5c27987460405160405180910390a495945050505050565b60035460009073ffffffffffffffffffffffffffffffffffffffff163381146200188c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f73656e646572206d7573742062652053776976656c20636f6e747261637400006044820152606401620004e0565b73ffffffffffffffffffffffffffffffffffffffff868116600090815260208181526040808320898452909152908190206001015490517f9dc29fac000000000000000000000000000000000000000000000000000000008152868316600482015260248101869052911690639dc29fac90604401602060405180830381600087803b1580156200191c57600080fd5b505af115801562001931573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001957919062002b7e565b620019bf576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f6275726e206661696c65640000000000000000000000000000000000000000006044820152606401620004e0565b73ffffffffffffffffffffffffffffffffffffffff868116600090815260208181526040808320898452909152908190206002015490517f613a28d100000000000000000000000000000000000000000000000000000000815286831660048201526024810186905291169063613a28d190604401602060405180830381600087803b15801562001a4f57600080fd5b505af115801562001a64573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001a8a919062002b7e565b62001af2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f72656d6f7665206e6f74696f6e616c206661696c6564000000000000000000006044820152606401620004e0565b50600195945050505050565b60035460009073ffffffffffffffffffffffffffffffffffffffff1633811462001b85576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f73656e646572206d7573742062652053776976656c20636f6e747261637400006044820152606401620004e0565b73ffffffffffffffffffffffffffffffffffffffff8781166000908152602081815260408083208a8452909152908190206002015490517f177946730000000000000000000000000000000000000000000000000000000081528783166004820152868316602482015260448101869052911690631779467390606401602060405180830381600087803b15801562001c1d57600080fd5b505af115801562001c32573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001c58919062002b7e565b62001cc0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f7472616e73666572206e6f74696f6e616c206661696c656400000000000000006044820152606401620004e0565b6040805173ffffffffffffffffffffffffffffffffffffffff8781168252868116602083015291810185905287918916907f31d266c2b6075063717026bd27ba8bb527366457893dc211091b2e1d9713f1529060600162000efb565b60035460009073ffffffffffffffffffffffffffffffffffffffff1633811462001da3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f73656e646572206d7573742062652053776976656c20636f6e747261637400006044820152606401620004e0565b73ffffffffffffffffffffffffffffffffffffffff8087166000818152602081815260408083208a845282528083208151606081018352815487168152600180830154881682860152600290920154909616868301529383529281528282208983529052205460ff168062001e865762001e1e888862000763565b62001e86576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f6661696c656420746f206d617475726520746865206d61726b657400000000006044820152606401620004e0565b60208201516040517f9dc29fac00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff88811660048301526024820188905290911690639dc29fac90604401602060405180830381600087803b15801562001efd57600080fd5b505af115801562001f12573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001f38919062002b7e565b62001fa0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f636f756c64206e6f74206275726e0000000000000000000000000000000000006044820152606401620004e0565b8573ffffffffffffffffffffffffffffffffffffffff16878973ffffffffffffffffffffffffffffffffffffffff167f49dc20daa9f95793b82245100affbf87ad23d1761bdef94975542564f4023e45886040516200200191815260200190565b60405180910390a4806200201a578493505050620005ba565b6200202788888762002757565b93505050620005ba565b60007f00000000000000000000000000000000000000000000000000000000000000003373ffffffffffffffffffffffffffffffffffffffff821614620020d5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f73656e646572206d7573742062652061646d696e0000000000000000000000006044820152606401620004e0565b6003805473ffffffffffffffffffffffffffffffffffffffff85167fffffffffffffffffffffffff00000000000000000000000000000000000000009091161790556001915050919050565b60035460009073ffffffffffffffffffffffffffffffffffffffff16338114620021a8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f73656e646572206d7573742062652053776976656c20636f6e747261637400006044820152606401620004e0565b73ffffffffffffffffffffffffffffffffffffffff868116600090815260208181526040808320898452909152908190206001015490517f40c10f190000000000000000000000000000000000000000000000000000000081528683166004820152602481018690529116906340c10f1990604401602060405180830381600087803b1580156200223857600080fd5b505af11580156200224d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062002273919062002b7e565b620022db576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f6d696e74207a63546f6b656e206661696c6564000000000000000000000000006044820152606401620004e0565b73ffffffffffffffffffffffffffffffffffffffff868116600090815260208181526040808320898452909152908190206002015490517fa01cfffb00000000000000000000000000000000000000000000000000000000815286831660048201526024810186905291169063a01cfffb90604401602060405180830381600087803b1580156200236b57600080fd5b505af115801562002380573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620023a6919062002b7e565b62001af2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f616464206e6f74696f6e616c206661696c6564000000000000000000000000006044820152606401620004e0565b60035460009073ffffffffffffffffffffffffffffffffffffffff1633811462002495576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f73656e646572206d7573742062652053776976656c20636f6e747261637400006044820152606401620004e0565b73ffffffffffffffffffffffffffffffffffffffff8781166000908152602081815260408083208a8452909152908190206001015490517f40c10f190000000000000000000000000000000000000000000000000000000081528783166004820152602481018690529116906340c10f1990604401602060405180830381600087803b1580156200252557600080fd5b505af11580156200253a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062002560919062002b7e565b620025c8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f6d696e74206661696c65640000000000000000000000000000000000000000006044820152606401620004e0565b73ffffffffffffffffffffffffffffffffffffffff8781166000908152602081815260408083208a8452909152908190206002015490517fa01cfffb00000000000000000000000000000000000000000000000000000000815286831660048201526024810186905291169063a01cfffb90604401602060405180830381600087803b1580156200265857600080fd5b505af11580156200266d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062002693919062002b7e565b620026fb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f616464206e6f74696f6e616c206661696c6564000000000000000000000000006044820152606401620004e0565b6040805173ffffffffffffffffffffffffffffffffffffffff8781168252868116602083015291810185905287918916907f8dad4d03bd4209aa6dc2bea238510998bf39bb034bc9c20d52f0bd241fc0c5169060600162000efb565b73ffffffffffffffffffffffffffffffffffffffff808416600081815260026020908152604080832087845282528083205493835282825280832087845282528083205481517fbd6d894d0000000000000000000000000000000000000000000000000000000081529151939586956a52b7d2dcc80cd2e4000000959094929091169263bd6d894d92600480830193919282900301818987803b158015620027fe57600080fd5b505af115801562002813573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062002839919062002ba0565b62002850906a52b7d2dcc80cd2e400000062002cdb565b6200285c919062002ca1565b62002868919062002d1b565b905060006a52b7d2dcc80cd2e400000062002884858462002cdb565b62002890919062002ca1565b90506200289e818562002c86565b9695505050505050565b610a2a8062002d9483390190565b61082280620037be83390190565b803573ffffffffffffffffffffffffffffffffffffffff81168114620028e957600080fd5b919050565b600082601f830112620028ff578081fd5b813567ffffffffffffffff808211156200291d576200291d62002d64565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190828211818310171562002966576200296662002d64565b816040528381528660208588010111156200297f578485fd5b8360208701602083013792830160200193909352509392505050565b600060208284031215620029ad578081fd5b620029b882620028c4565b9392505050565b60008060408385031215620029d2578081fd5b620029dd83620028c4565b946020939093013593505050565b60008060006060848603121562002a00578081fd5b62002a0b84620028c4565b92506020840135915062002a2260408501620028c4565b90509250925092565b600080600080600060a0868803121562002a43578081fd5b62002a4e86620028c4565b94506020860135935062002a6560408701620028c4565b925062002a7560608701620028c4565b949793965091946080013592915050565b60008060008060008060c0878903121562002a9f578081fd5b62002aaa87620028c4565b95506020870135945062002ac160408801620028c4565b9350606087013567ffffffffffffffff8082111562002ade578283fd5b62002aec8a838b01620028ee565b9450608089013591508082111562002b02578283fd5b5062002b1189828a01620028ee565b92505060a087013560ff8116811462002b28578182fd5b809150509295509295509295565b6000806000806080858703121562002b4c578384fd5b62002b5785620028c4565b93506020850135925062002b6e60408601620028c4565b9396929550929360600135925050565b60006020828403121562002b90578081fd5b81518015158114620029b8578182fd5b60006020828403121562002bb2578081fd5b5051919050565b60008151808452815b8181101562002be05760208185018101518683018201520162002bc2565b8181111562002bf25782602083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b73ffffffffffffffffffffffffffffffffffffffff8616815284602082015260a06040820152600062002c5c60a083018662002bb9565b828103606084015262002c70818662002bb9565b91505060ff831660808301529695505050505050565b6000821982111562002c9c5762002c9c62002d35565b500190565b60008262002cd6577f4e487b710000000000000000000000000000000000000000000000000000000081526012600452602481fd5b500490565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048311821515161562002d165762002d1662002d35565b500290565b60008282101562002d305762002d3062002d35565b500390565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fdfe60806040523480156200001157600080fd5b5060405162000a2a38038062000a2a8339810160408190526200003491620001fd565b60058054610100600160a81b0319166101006001600160a01b03881602179055600684905582516200006e906003906020860190620000a4565b50815162000084906004906020850190620000a4565b506005805460ff191660ff9290921691909117905550620002fb92505050565b828054620000b290620002a8565b90600052602060002090601f016020900481019282620000d6576000855562000121565b82601f10620000f157805160ff191683800117855562000121565b8280016001018555821562000121579182015b828111156200012157825182559160200191906001019062000104565b506200012f92915062000133565b5090565b5b808211156200012f576000815560010162000134565b600082601f8301126200015b578081fd5b81516001600160401b0380821115620001785762000178620002e5565b604051601f8301601f19908116603f01168101908282118183101715620001a357620001a3620002e5565b81604052838152602092508683858801011115620001bf578485fd5b8491505b83821015620001e25785820183015181830184015290820190620001c3565b83821115620001f357848385830101525b9695505050505050565b600080600080600060a0868803121562000215578081fd5b85516001600160a01b03811681146200022c578182fd5b6020870151604088015191965094506001600160401b038082111562000250578283fd5b6200025e89838a016200014a565b9450606088015191508082111562000274578283fd5b5062000283888289016200014a565b925050608086015160ff811681146200029a578182fd5b809150509295509295909350565b600181811c90821680620002bd57607f821691505b60208210811415620002df57634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052604160045260246000fd5b61071f806200030b6000396000f3fe608060405234801561001057600080fd5b50600436106101005760003560e01c80639dc29fac11610097578063e541efa211610066578063e541efa214610378578063e7ba6774146103e4578063ee4db5701461043e578063fdfe5f4d1461045e57600080fd5b80639dc29fac146102c7578063b4c4a4c814610306578063b9bb928c14610319578063bba0ad391461035857600080fd5b806340c10f19116100d357806340c10f19146101f05780636521b96a146102345780636f307dc31461027c57806395d89b41146102bf57600080fd5b806306fdde0314610105578063204f83f91461012357806323b872dd14610135578063313ce567146101d1575b600080fd5b61010d6104a3565b60405161011a9190610624565b60405180910390f35b6006545b60405190815260200161011a565b6101c1610143366004610588565b60408051808201825273ffffffffffffffffffffffffffffffffffffffff93841681526020808201938452948416600090815260029095529320925183547fffffffffffffffffffffffff00000000000000000000000000000000000000001692169190911782555160019091015560075462010000900460ff1690565b604051901515815260200161011a565b6005546101de9060ff1681565b60405160ff909116815260200161011a565b6101c16101fe3660046105c3565b73ffffffffffffffffffffffffffffffffffffffff91909116600090815260016020526040902055600754610100900460ff1690565b61027a6102423660046105ec565b6007805491151562010000027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff909216919091179055565b005b600554610100900473ffffffffffffffffffffffffffffffffffffffff1660405173ffffffffffffffffffffffffffffffffffffffff909116815260200161011a565b61010d610531565b6101c16102d53660046105c3565b73ffffffffffffffffffffffffffffffffffffffff9190911660009081526020819052604090205560075460ff1690565b61027a61031436600461060c565b600655565b61027a6103273660046105ec565b600780547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055565b610127610366366004610567565b60006020819052908152604090205481565b6103b8610386366004610567565b6002602052600090815260409020805460019091015473ffffffffffffffffffffffffffffffffffffffff9091169082565b6040805173ffffffffffffffffffffffffffffffffffffffff909316835260208301919091520161011a565b61027a6103f2366004610567565b6005805473ffffffffffffffffffffffffffffffffffffffff909216610100027fffffffffffffffffffffff0000000000000000000000000000000000000000ff909216919091179055565b61012761044c366004610567565b60016020526000908152604090205481565b61027a61046c3660046105ec565b60078054911515610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff909216919091179055565b600380546104b090610695565b80601f01602080910402602001604051908101604052809291908181526020018280546104dc90610695565b80156105295780601f106104fe57610100808354040283529160200191610529565b820191906000526020600020905b81548152906001019060200180831161050c57829003601f168201915b505050505081565b600480546104b090610695565b803573ffffffffffffffffffffffffffffffffffffffff8116811461056257600080fd5b919050565b600060208284031215610578578081fd5b6105818261053e565b9392505050565b60008060006060848603121561059c578182fd5b6105a58461053e565b92506105b36020850161053e565b9150604084013590509250925092565b600080604083850312156105d5578182fd5b6105de8361053e565b946020939093013593505050565b6000602082840312156105fd578081fd5b81358015158114610581578182fd5b60006020828403121561061d578081fd5b5035919050565b6000602080835283518082850152825b8181101561065057858101830151858201604001528201610634565b818111156106615783604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016929092016040019392505050565b600181811c908216806106a957607f821691505b602082108114156106e3577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b5091905056fea2646970667358221220eb8a5eef9e13a196e22e78e58517b46946db88220c910292ae27c5fcd5a37c2964736f6c63430008040033608060405234801561001057600080fd5b5060405161082238038061082283398101604081905261002f91610082565b600792909255600480546001600160a01b039283166001600160a01b031991821617909155600580549290931691161790556100bd565b80516001600160a01b038116811461007d57600080fd5b919050565b600080600060608486031215610096578283fd5b835192506100a660208501610066565b91506100b460408501610066565b90509250925092565b610756806100cc6000396000f3fe608060405234801561001057600080fd5b50600436106101775760003560e01c806382cac89c116100d8578063b7dd34831161008c578063d6cb2c0d11610066578063d6cb2c0d1461057c578063da3de9e91461058f578063e590c362146105ce57600080fd5b8063b7dd3483146104f5578063bbce238614610515578063d0b9d0321461053557600080fd5b8063a701da69116100bd578063a701da6914610453578063b326258d1461049b578063b4c4a4c8146104e257600080fd5b806382cac89c146103ef578063a01cfffb1461040f57600080fd5b80633dfa1f411161012f5780635dfe12ac116101145780635dfe12ac14610359578063613a28d11461039f5780636b868d51146103e457600080fd5b80633dfa1f41146102f25780635c70b7c11461031257600080fd5b8063177946731161016057806317794673146101f457806319caf46c14610291578063204f83f9146102ea57600080fd5b8063012b264a1461017c5780630aa93b9b146101c6575b600080fd5b60055461019c9073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b6101e66101d4366004610663565b60016020526000908152604090205481565b6040519081526020016101bd565b610281610202366004610684565b60408051808201825273ffffffffffffffffffffffffffffffffffffffff93841681526020808201938452948416600090815260029095529320925183547fffffffffffffffffffffffff0000000000000000000000000000000000000000169216919091178255516001909101556009546301000000900460ff1690565b60405190151581526020016101bd565b6101e661029f366004610663565b600680547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9290921691909117905560085490565b6007546101e6565b6101e6610300366004610663565b60006020819052908152604090205481565b6103576103203660046106e8565b60098054911515610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff909216919091179055565b005b6103576103673660046106e8565b6009805491151562010000027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff909216919091179055565b6102816103ad3660046106bf565b73ffffffffffffffffffffffffffffffffffffffff9190911660009081526001602052604090205560095462010000900460ff1690565b60095460ff16610281565b60065461019c9073ffffffffffffffffffffffffffffffffffffffff1681565b61028161041d3660046106bf565b73ffffffffffffffffffffffffffffffffffffffff91909116600090815260208190526040902055600954610100900460ff1690565b6103576104613660046106e8565b60098054911515640100000000027fffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffff909216919091179055565b6102816104a93660046106bf565b73ffffffffffffffffffffffffffffffffffffffff91909116600090815260036020526040902055600954640100000000900460ff1690565b6103576104f0366004610708565b600755565b60045461019c9073ffffffffffffffffffffffffffffffffffffffff1681565b6101e6610523366004610663565b60036020526000908152604090205481565b6103576105433660046106e8565b600980549115156301000000027fffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffff909216919091179055565b61035761058a366004610708565b600855565b61035761059d3660046106e8565b600980547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055565b61060e6105dc366004610663565b6002602052600090815260409020805460019091015473ffffffffffffffffffffffffffffffffffffffff9091169082565b6040805173ffffffffffffffffffffffffffffffffffffffff90931683526020830191909152016101bd565b803573ffffffffffffffffffffffffffffffffffffffff8116811461065e57600080fd5b919050565b600060208284031215610674578081fd5b61067d8261063a565b9392505050565b600080600060608486031215610698578182fd5b6106a18461063a565b92506106af6020850161063a565b9150604084013590509250925092565b600080604083850312156106d1578182fd5b6106da8361063a565b946020939093013593505050565b6000602082840312156106f9578081fd5b8135801515811461067d578182fd5b600060208284031215610719578081fd5b503591905056fea26469706673582212202ce12b1980bd5f82baa5e2ebd47a5978b9f4251b48a4b88ed7b08f2685a21f8e64736f6c63430008040033a26469706673582212207bf7c4d54a4506059c49ac1a544381729f47d9e9facb1921ecb4f8c1746f6a6364736f6c63430008040033" + +// DeployMarketPlace deploys a new Ethereum contract, binding an instance of MarketPlace to it. +func DeployMarketPlace(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *MarketPlace, error) { + parsed, err := abi.JSON(strings.NewReader(MarketPlaceABI)) + if err != nil { + return common.Address{}, nil, nil, err + } + + address, tx, contract, err := bind.DeployContract(auth, parsed, common.FromHex(MarketPlaceBin), backend) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &MarketPlace{MarketPlaceCaller: MarketPlaceCaller{contract: contract}, MarketPlaceTransactor: MarketPlaceTransactor{contract: contract}, MarketPlaceFilterer: MarketPlaceFilterer{contract: contract}}, nil +} + +// MarketPlace is an auto generated Go binding around an Ethereum contract. +type MarketPlace struct { + MarketPlaceCaller // Read-only binding to the contract + MarketPlaceTransactor // Write-only binding to the contract + MarketPlaceFilterer // Log filterer for contract events +} + +// MarketPlaceCaller is an auto generated read-only Go binding around an Ethereum contract. +type MarketPlaceCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// MarketPlaceTransactor is an auto generated write-only Go binding around an Ethereum contract. +type MarketPlaceTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// MarketPlaceFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type MarketPlaceFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// MarketPlaceSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type MarketPlaceSession struct { + Contract *MarketPlace // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// MarketPlaceCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type MarketPlaceCallerSession struct { + Contract *MarketPlaceCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// MarketPlaceTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type MarketPlaceTransactorSession struct { + Contract *MarketPlaceTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// MarketPlaceRaw is an auto generated low-level Go binding around an Ethereum contract. +type MarketPlaceRaw struct { + Contract *MarketPlace // Generic contract binding to access the raw methods on +} + +// MarketPlaceCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type MarketPlaceCallerRaw struct { + Contract *MarketPlaceCaller // Generic read-only contract binding to access the raw methods on +} + +// MarketPlaceTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type MarketPlaceTransactorRaw struct { + Contract *MarketPlaceTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewMarketPlace creates a new instance of MarketPlace, bound to a specific deployed contract. +func NewMarketPlace(address common.Address, backend bind.ContractBackend) (*MarketPlace, error) { + contract, err := bindMarketPlace(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &MarketPlace{MarketPlaceCaller: MarketPlaceCaller{contract: contract}, MarketPlaceTransactor: MarketPlaceTransactor{contract: contract}, MarketPlaceFilterer: MarketPlaceFilterer{contract: contract}}, nil +} + +// NewMarketPlaceCaller creates a new read-only instance of MarketPlace, bound to a specific deployed contract. +func NewMarketPlaceCaller(address common.Address, caller bind.ContractCaller) (*MarketPlaceCaller, error) { + contract, err := bindMarketPlace(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &MarketPlaceCaller{contract: contract}, nil +} + +// NewMarketPlaceTransactor creates a new write-only instance of MarketPlace, bound to a specific deployed contract. +func NewMarketPlaceTransactor(address common.Address, transactor bind.ContractTransactor) (*MarketPlaceTransactor, error) { + contract, err := bindMarketPlace(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &MarketPlaceTransactor{contract: contract}, nil +} + +// NewMarketPlaceFilterer creates a new log filterer instance of MarketPlace, bound to a specific deployed contract. +func NewMarketPlaceFilterer(address common.Address, filterer bind.ContractFilterer) (*MarketPlaceFilterer, error) { + contract, err := bindMarketPlace(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &MarketPlaceFilterer{contract: contract}, nil +} + +// bindMarketPlace binds a generic wrapper to an already deployed contract. +func bindMarketPlace(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := abi.JSON(strings.NewReader(MarketPlaceABI)) + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_MarketPlace *MarketPlaceRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _MarketPlace.Contract.MarketPlaceCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_MarketPlace *MarketPlaceRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _MarketPlace.Contract.MarketPlaceTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_MarketPlace *MarketPlaceRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _MarketPlace.Contract.MarketPlaceTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_MarketPlace *MarketPlaceCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _MarketPlace.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_MarketPlace *MarketPlaceTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _MarketPlace.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_MarketPlace *MarketPlaceTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _MarketPlace.Contract.contract.Transact(opts, method, params...) +} + +// Admin is a free data retrieval call binding the contract method 0xf851a440. +// +// Solidity: function admin() view returns(address) +func (_MarketPlace *MarketPlaceCaller) Admin(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _MarketPlace.contract.Call(opts, &out, "admin") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// Admin is a free data retrieval call binding the contract method 0xf851a440. +// +// Solidity: function admin() view returns(address) +func (_MarketPlace *MarketPlaceSession) Admin() (common.Address, error) { + return _MarketPlace.Contract.Admin(&_MarketPlace.CallOpts) +} + +// Admin is a free data retrieval call binding the contract method 0xf851a440. +// +// Solidity: function admin() view returns(address) +func (_MarketPlace *MarketPlaceCallerSession) Admin() (common.Address, error) { + return _MarketPlace.Contract.Admin(&_MarketPlace.CallOpts) +} + +// CTokenAddress is a free data retrieval call binding the contract method 0x05e1dc25. +// +// Solidity: function cTokenAddress(address a, uint256 m) view returns(address) +func (_MarketPlace *MarketPlaceCaller) CTokenAddress(opts *bind.CallOpts, a common.Address, m *big.Int) (common.Address, error) { + var out []interface{} + err := _MarketPlace.contract.Call(opts, &out, "cTokenAddress", a, m) + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// CTokenAddress is a free data retrieval call binding the contract method 0x05e1dc25. +// +// Solidity: function cTokenAddress(address a, uint256 m) view returns(address) +func (_MarketPlace *MarketPlaceSession) CTokenAddress(a common.Address, m *big.Int) (common.Address, error) { + return _MarketPlace.Contract.CTokenAddress(&_MarketPlace.CallOpts, a, m) +} + +// CTokenAddress is a free data retrieval call binding the contract method 0x05e1dc25. +// +// Solidity: function cTokenAddress(address a, uint256 m) view returns(address) +func (_MarketPlace *MarketPlaceCallerSession) CTokenAddress(a common.Address, m *big.Int) (common.Address, error) { + return _MarketPlace.Contract.CTokenAddress(&_MarketPlace.CallOpts, a, m) +} + +// Markets is a free data retrieval call binding the contract method 0x17b3bba7. +// +// Solidity: function markets(address , uint256 ) view returns(address cTokenAddr, address zcTokenAddr, address vaultAddr) +func (_MarketPlace *MarketPlaceCaller) Markets(opts *bind.CallOpts, arg0 common.Address, arg1 *big.Int) (struct { + CTokenAddr common.Address + ZcTokenAddr common.Address + VaultAddr common.Address +}, error) { + var out []interface{} + err := _MarketPlace.contract.Call(opts, &out, "markets", arg0, arg1) + + outstruct := new(struct { + CTokenAddr common.Address + ZcTokenAddr common.Address + VaultAddr common.Address + }) + if err != nil { + return *outstruct, err + } + + outstruct.CTokenAddr = out[0].(common.Address) + outstruct.ZcTokenAddr = out[1].(common.Address) + outstruct.VaultAddr = out[2].(common.Address) + + return *outstruct, err + +} + +// Markets is a free data retrieval call binding the contract method 0x17b3bba7. +// +// Solidity: function markets(address , uint256 ) view returns(address cTokenAddr, address zcTokenAddr, address vaultAddr) +func (_MarketPlace *MarketPlaceSession) Markets(arg0 common.Address, arg1 *big.Int) (struct { + CTokenAddr common.Address + ZcTokenAddr common.Address + VaultAddr common.Address +}, error) { + return _MarketPlace.Contract.Markets(&_MarketPlace.CallOpts, arg0, arg1) +} + +// Markets is a free data retrieval call binding the contract method 0x17b3bba7. +// +// Solidity: function markets(address , uint256 ) view returns(address cTokenAddr, address zcTokenAddr, address vaultAddr) +func (_MarketPlace *MarketPlaceCallerSession) Markets(arg0 common.Address, arg1 *big.Int) (struct { + CTokenAddr common.Address + ZcTokenAddr common.Address + VaultAddr common.Address +}, error) { + return _MarketPlace.Contract.Markets(&_MarketPlace.CallOpts, arg0, arg1) +} + +// Mature is a free data retrieval call binding the contract method 0x27ee93be. +// +// Solidity: function mature(address , uint256 ) view returns(bool) +func (_MarketPlace *MarketPlaceCaller) Mature(opts *bind.CallOpts, arg0 common.Address, arg1 *big.Int) (bool, error) { + var out []interface{} + err := _MarketPlace.contract.Call(opts, &out, "mature", arg0, arg1) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// Mature is a free data retrieval call binding the contract method 0x27ee93be. +// +// Solidity: function mature(address , uint256 ) view returns(bool) +func (_MarketPlace *MarketPlaceSession) Mature(arg0 common.Address, arg1 *big.Int) (bool, error) { + return _MarketPlace.Contract.Mature(&_MarketPlace.CallOpts, arg0, arg1) +} + +// Mature is a free data retrieval call binding the contract method 0x27ee93be. +// +// Solidity: function mature(address , uint256 ) view returns(bool) +func (_MarketPlace *MarketPlaceCallerSession) Mature(arg0 common.Address, arg1 *big.Int) (bool, error) { + return _MarketPlace.Contract.Mature(&_MarketPlace.CallOpts, arg0, arg1) +} + +// MaturityRate is a free data retrieval call binding the contract method 0xc86adf7c. +// +// Solidity: function maturityRate(address , uint256 ) view returns(uint256) +func (_MarketPlace *MarketPlaceCaller) MaturityRate(opts *bind.CallOpts, arg0 common.Address, arg1 *big.Int) (*big.Int, error) { + var out []interface{} + err := _MarketPlace.contract.Call(opts, &out, "maturityRate", arg0, arg1) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// MaturityRate is a free data retrieval call binding the contract method 0xc86adf7c. +// +// Solidity: function maturityRate(address , uint256 ) view returns(uint256) +func (_MarketPlace *MarketPlaceSession) MaturityRate(arg0 common.Address, arg1 *big.Int) (*big.Int, error) { + return _MarketPlace.Contract.MaturityRate(&_MarketPlace.CallOpts, arg0, arg1) +} + +// MaturityRate is a free data retrieval call binding the contract method 0xc86adf7c. +// +// Solidity: function maturityRate(address , uint256 ) view returns(uint256) +func (_MarketPlace *MarketPlaceCallerSession) MaturityRate(arg0 common.Address, arg1 *big.Int) (*big.Int, error) { + return _MarketPlace.Contract.MaturityRate(&_MarketPlace.CallOpts, arg0, arg1) +} + +// Swivel is a free data retrieval call binding the contract method 0x012b264a. +// +// Solidity: function swivel() view returns(address) +func (_MarketPlace *MarketPlaceCaller) Swivel(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _MarketPlace.contract.Call(opts, &out, "swivel") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// Swivel is a free data retrieval call binding the contract method 0x012b264a. +// +// Solidity: function swivel() view returns(address) +func (_MarketPlace *MarketPlaceSession) Swivel() (common.Address, error) { + return _MarketPlace.Contract.Swivel(&_MarketPlace.CallOpts) +} + +// Swivel is a free data retrieval call binding the contract method 0x012b264a. +// +// Solidity: function swivel() view returns(address) +func (_MarketPlace *MarketPlaceCallerSession) Swivel() (common.Address, error) { + return _MarketPlace.Contract.Swivel(&_MarketPlace.CallOpts) +} + +// BurnZcTokenRemovingNotional is a paid mutator transaction binding the contract method 0xb50a66f7. +// +// Solidity: function burnZcTokenRemovingNotional(address u, uint256 m, address t, uint256 a) returns(bool) +func (_MarketPlace *MarketPlaceTransactor) BurnZcTokenRemovingNotional(opts *bind.TransactOpts, u common.Address, m *big.Int, t common.Address, a *big.Int) (*types.Transaction, error) { + return _MarketPlace.contract.Transact(opts, "burnZcTokenRemovingNotional", u, m, t, a) +} + +// BurnZcTokenRemovingNotional is a paid mutator transaction binding the contract method 0xb50a66f7. +// +// Solidity: function burnZcTokenRemovingNotional(address u, uint256 m, address t, uint256 a) returns(bool) +func (_MarketPlace *MarketPlaceSession) BurnZcTokenRemovingNotional(u common.Address, m *big.Int, t common.Address, a *big.Int) (*types.Transaction, error) { + return _MarketPlace.Contract.BurnZcTokenRemovingNotional(&_MarketPlace.TransactOpts, u, m, t, a) +} + +// BurnZcTokenRemovingNotional is a paid mutator transaction binding the contract method 0xb50a66f7. +// +// Solidity: function burnZcTokenRemovingNotional(address u, uint256 m, address t, uint256 a) returns(bool) +func (_MarketPlace *MarketPlaceTransactorSession) BurnZcTokenRemovingNotional(u common.Address, m *big.Int, t common.Address, a *big.Int) (*types.Transaction, error) { + return _MarketPlace.Contract.BurnZcTokenRemovingNotional(&_MarketPlace.TransactOpts, u, m, t, a) +} + +// CreateMarket is a paid mutator transaction binding the contract method 0x848f5184. +// +// Solidity: function createMarket(address u, uint256 m, address c, string n, string s, uint8 d) returns(bool) +func (_MarketPlace *MarketPlaceTransactor) CreateMarket(opts *bind.TransactOpts, u common.Address, m *big.Int, c common.Address, n string, s string, d uint8) (*types.Transaction, error) { + return _MarketPlace.contract.Transact(opts, "createMarket", u, m, c, n, s, d) +} + +// CreateMarket is a paid mutator transaction binding the contract method 0x848f5184. +// +// Solidity: function createMarket(address u, uint256 m, address c, string n, string s, uint8 d) returns(bool) +func (_MarketPlace *MarketPlaceSession) CreateMarket(u common.Address, m *big.Int, c common.Address, n string, s string, d uint8) (*types.Transaction, error) { + return _MarketPlace.Contract.CreateMarket(&_MarketPlace.TransactOpts, u, m, c, n, s, d) +} + +// CreateMarket is a paid mutator transaction binding the contract method 0x848f5184. +// +// Solidity: function createMarket(address u, uint256 m, address c, string n, string s, uint8 d) returns(bool) +func (_MarketPlace *MarketPlaceTransactorSession) CreateMarket(u common.Address, m *big.Int, c common.Address, n string, s string, d uint8) (*types.Transaction, error) { + return _MarketPlace.Contract.CreateMarket(&_MarketPlace.TransactOpts, u, m, c, n, s, d) +} + +// CustodialExit is a paid mutator transaction binding the contract method 0x8c6b9b41. +// +// Solidity: function custodialExit(address u, uint256 m, address z, address n, uint256 a) returns(bool) +func (_MarketPlace *MarketPlaceTransactor) CustodialExit(opts *bind.TransactOpts, u common.Address, m *big.Int, z common.Address, n common.Address, a *big.Int) (*types.Transaction, error) { + return _MarketPlace.contract.Transact(opts, "custodialExit", u, m, z, n, a) +} + +// CustodialExit is a paid mutator transaction binding the contract method 0x8c6b9b41. +// +// Solidity: function custodialExit(address u, uint256 m, address z, address n, uint256 a) returns(bool) +func (_MarketPlace *MarketPlaceSession) CustodialExit(u common.Address, m *big.Int, z common.Address, n common.Address, a *big.Int) (*types.Transaction, error) { + return _MarketPlace.Contract.CustodialExit(&_MarketPlace.TransactOpts, u, m, z, n, a) +} + +// CustodialExit is a paid mutator transaction binding the contract method 0x8c6b9b41. +// +// Solidity: function custodialExit(address u, uint256 m, address z, address n, uint256 a) returns(bool) +func (_MarketPlace *MarketPlaceTransactorSession) CustodialExit(u common.Address, m *big.Int, z common.Address, n common.Address, a *big.Int) (*types.Transaction, error) { + return _MarketPlace.Contract.CustodialExit(&_MarketPlace.TransactOpts, u, m, z, n, a) +} + +// CustodialInitiate is a paid mutator transaction binding the contract method 0xf8e51bcb. +// +// Solidity: function custodialInitiate(address u, uint256 m, address z, address n, uint256 a) returns(bool) +func (_MarketPlace *MarketPlaceTransactor) CustodialInitiate(opts *bind.TransactOpts, u common.Address, m *big.Int, z common.Address, n common.Address, a *big.Int) (*types.Transaction, error) { + return _MarketPlace.contract.Transact(opts, "custodialInitiate", u, m, z, n, a) +} + +// CustodialInitiate is a paid mutator transaction binding the contract method 0xf8e51bcb. +// +// Solidity: function custodialInitiate(address u, uint256 m, address z, address n, uint256 a) returns(bool) +func (_MarketPlace *MarketPlaceSession) CustodialInitiate(u common.Address, m *big.Int, z common.Address, n common.Address, a *big.Int) (*types.Transaction, error) { + return _MarketPlace.Contract.CustodialInitiate(&_MarketPlace.TransactOpts, u, m, z, n, a) +} + +// CustodialInitiate is a paid mutator transaction binding the contract method 0xf8e51bcb. +// +// Solidity: function custodialInitiate(address u, uint256 m, address z, address n, uint256 a) returns(bool) +func (_MarketPlace *MarketPlaceTransactorSession) CustodialInitiate(u common.Address, m *big.Int, z common.Address, n common.Address, a *big.Int) (*types.Transaction, error) { + return _MarketPlace.Contract.CustodialInitiate(&_MarketPlace.TransactOpts, u, m, z, n, a) +} + +// MatureMarket is a paid mutator transaction binding the contract method 0x5db0ae58. +// +// Solidity: function matureMarket(address u, uint256 m) returns(bool) +func (_MarketPlace *MarketPlaceTransactor) MatureMarket(opts *bind.TransactOpts, u common.Address, m *big.Int) (*types.Transaction, error) { + return _MarketPlace.contract.Transact(opts, "matureMarket", u, m) +} + +// MatureMarket is a paid mutator transaction binding the contract method 0x5db0ae58. +// +// Solidity: function matureMarket(address u, uint256 m) returns(bool) +func (_MarketPlace *MarketPlaceSession) MatureMarket(u common.Address, m *big.Int) (*types.Transaction, error) { + return _MarketPlace.Contract.MatureMarket(&_MarketPlace.TransactOpts, u, m) +} + +// MatureMarket is a paid mutator transaction binding the contract method 0x5db0ae58. +// +// Solidity: function matureMarket(address u, uint256 m) returns(bool) +func (_MarketPlace *MarketPlaceTransactorSession) MatureMarket(u common.Address, m *big.Int) (*types.Transaction, error) { + return _MarketPlace.Contract.MatureMarket(&_MarketPlace.TransactOpts, u, m) +} + +// MintZcTokenAddingNotional is a paid mutator transaction binding the contract method 0xef267f2c. +// +// Solidity: function mintZcTokenAddingNotional(address u, uint256 m, address t, uint256 a) returns(bool) +func (_MarketPlace *MarketPlaceTransactor) MintZcTokenAddingNotional(opts *bind.TransactOpts, u common.Address, m *big.Int, t common.Address, a *big.Int) (*types.Transaction, error) { + return _MarketPlace.contract.Transact(opts, "mintZcTokenAddingNotional", u, m, t, a) +} + +// MintZcTokenAddingNotional is a paid mutator transaction binding the contract method 0xef267f2c. +// +// Solidity: function mintZcTokenAddingNotional(address u, uint256 m, address t, uint256 a) returns(bool) +func (_MarketPlace *MarketPlaceSession) MintZcTokenAddingNotional(u common.Address, m *big.Int, t common.Address, a *big.Int) (*types.Transaction, error) { + return _MarketPlace.Contract.MintZcTokenAddingNotional(&_MarketPlace.TransactOpts, u, m, t, a) +} + +// MintZcTokenAddingNotional is a paid mutator transaction binding the contract method 0xef267f2c. +// +// Solidity: function mintZcTokenAddingNotional(address u, uint256 m, address t, uint256 a) returns(bool) +func (_MarketPlace *MarketPlaceTransactorSession) MintZcTokenAddingNotional(u common.Address, m *big.Int, t common.Address, a *big.Int) (*types.Transaction, error) { + return _MarketPlace.Contract.MintZcTokenAddingNotional(&_MarketPlace.TransactOpts, u, m, t, a) +} + +// P2pVaultExchange is a paid mutator transaction binding the contract method 0xbddbfbe4. +// +// Solidity: function p2pVaultExchange(address u, uint256 m, address f, address t, uint256 a) returns(bool) +func (_MarketPlace *MarketPlaceTransactor) P2pVaultExchange(opts *bind.TransactOpts, u common.Address, m *big.Int, f common.Address, t common.Address, a *big.Int) (*types.Transaction, error) { + return _MarketPlace.contract.Transact(opts, "p2pVaultExchange", u, m, f, t, a) +} + +// P2pVaultExchange is a paid mutator transaction binding the contract method 0xbddbfbe4. +// +// Solidity: function p2pVaultExchange(address u, uint256 m, address f, address t, uint256 a) returns(bool) +func (_MarketPlace *MarketPlaceSession) P2pVaultExchange(u common.Address, m *big.Int, f common.Address, t common.Address, a *big.Int) (*types.Transaction, error) { + return _MarketPlace.Contract.P2pVaultExchange(&_MarketPlace.TransactOpts, u, m, f, t, a) +} + +// P2pVaultExchange is a paid mutator transaction binding the contract method 0xbddbfbe4. +// +// Solidity: function p2pVaultExchange(address u, uint256 m, address f, address t, uint256 a) returns(bool) +func (_MarketPlace *MarketPlaceTransactorSession) P2pVaultExchange(u common.Address, m *big.Int, f common.Address, t common.Address, a *big.Int) (*types.Transaction, error) { + return _MarketPlace.Contract.P2pVaultExchange(&_MarketPlace.TransactOpts, u, m, f, t, a) +} + +// P2pZcTokenExchange is a paid mutator transaction binding the contract method 0x65a963aa. +// +// Solidity: function p2pZcTokenExchange(address u, uint256 m, address f, address t, uint256 a) returns(bool) +func (_MarketPlace *MarketPlaceTransactor) P2pZcTokenExchange(opts *bind.TransactOpts, u common.Address, m *big.Int, f common.Address, t common.Address, a *big.Int) (*types.Transaction, error) { + return _MarketPlace.contract.Transact(opts, "p2pZcTokenExchange", u, m, f, t, a) +} + +// P2pZcTokenExchange is a paid mutator transaction binding the contract method 0x65a963aa. +// +// Solidity: function p2pZcTokenExchange(address u, uint256 m, address f, address t, uint256 a) returns(bool) +func (_MarketPlace *MarketPlaceSession) P2pZcTokenExchange(u common.Address, m *big.Int, f common.Address, t common.Address, a *big.Int) (*types.Transaction, error) { + return _MarketPlace.Contract.P2pZcTokenExchange(&_MarketPlace.TransactOpts, u, m, f, t, a) +} + +// P2pZcTokenExchange is a paid mutator transaction binding the contract method 0x65a963aa. +// +// Solidity: function p2pZcTokenExchange(address u, uint256 m, address f, address t, uint256 a) returns(bool) +func (_MarketPlace *MarketPlaceTransactorSession) P2pZcTokenExchange(u common.Address, m *big.Int, f common.Address, t common.Address, a *big.Int) (*types.Transaction, error) { + return _MarketPlace.Contract.P2pZcTokenExchange(&_MarketPlace.TransactOpts, u, m, f, t, a) +} + +// RedeemVaultInterest is a paid mutator transaction binding the contract method 0xa11f4856. +// +// Solidity: function redeemVaultInterest(address u, uint256 m, address t) returns(uint256) +func (_MarketPlace *MarketPlaceTransactor) RedeemVaultInterest(opts *bind.TransactOpts, u common.Address, m *big.Int, t common.Address) (*types.Transaction, error) { + return _MarketPlace.contract.Transact(opts, "redeemVaultInterest", u, m, t) +} + +// RedeemVaultInterest is a paid mutator transaction binding the contract method 0xa11f4856. +// +// Solidity: function redeemVaultInterest(address u, uint256 m, address t) returns(uint256) +func (_MarketPlace *MarketPlaceSession) RedeemVaultInterest(u common.Address, m *big.Int, t common.Address) (*types.Transaction, error) { + return _MarketPlace.Contract.RedeemVaultInterest(&_MarketPlace.TransactOpts, u, m, t) +} + +// RedeemVaultInterest is a paid mutator transaction binding the contract method 0xa11f4856. +// +// Solidity: function redeemVaultInterest(address u, uint256 m, address t) returns(uint256) +func (_MarketPlace *MarketPlaceTransactorSession) RedeemVaultInterest(u common.Address, m *big.Int, t common.Address) (*types.Transaction, error) { + return _MarketPlace.Contract.RedeemVaultInterest(&_MarketPlace.TransactOpts, u, m, t) +} + +// RedeemZcToken is a paid mutator transaction binding the contract method 0xc5ee114d. +// +// Solidity: function redeemZcToken(address u, uint256 m, address t, uint256 a) returns(uint256) +func (_MarketPlace *MarketPlaceTransactor) RedeemZcToken(opts *bind.TransactOpts, u common.Address, m *big.Int, t common.Address, a *big.Int) (*types.Transaction, error) { + return _MarketPlace.contract.Transact(opts, "redeemZcToken", u, m, t, a) +} + +// RedeemZcToken is a paid mutator transaction binding the contract method 0xc5ee114d. +// +// Solidity: function redeemZcToken(address u, uint256 m, address t, uint256 a) returns(uint256) +func (_MarketPlace *MarketPlaceSession) RedeemZcToken(u common.Address, m *big.Int, t common.Address, a *big.Int) (*types.Transaction, error) { + return _MarketPlace.Contract.RedeemZcToken(&_MarketPlace.TransactOpts, u, m, t, a) +} + +// RedeemZcToken is a paid mutator transaction binding the contract method 0xc5ee114d. +// +// Solidity: function redeemZcToken(address u, uint256 m, address t, uint256 a) returns(uint256) +func (_MarketPlace *MarketPlaceTransactorSession) RedeemZcToken(u common.Address, m *big.Int, t common.Address, a *big.Int) (*types.Transaction, error) { + return _MarketPlace.Contract.RedeemZcToken(&_MarketPlace.TransactOpts, u, m, t, a) +} + +// SetSwivelAddress is a paid mutator transaction binding the contract method 0xe5a2aa62. +// +// Solidity: function setSwivelAddress(address s) returns(bool) +func (_MarketPlace *MarketPlaceTransactor) SetSwivelAddress(opts *bind.TransactOpts, s common.Address) (*types.Transaction, error) { + return _MarketPlace.contract.Transact(opts, "setSwivelAddress", s) +} + +// SetSwivelAddress is a paid mutator transaction binding the contract method 0xe5a2aa62. +// +// Solidity: function setSwivelAddress(address s) returns(bool) +func (_MarketPlace *MarketPlaceSession) SetSwivelAddress(s common.Address) (*types.Transaction, error) { + return _MarketPlace.Contract.SetSwivelAddress(&_MarketPlace.TransactOpts, s) +} + +// SetSwivelAddress is a paid mutator transaction binding the contract method 0xe5a2aa62. +// +// Solidity: function setSwivelAddress(address s) returns(bool) +func (_MarketPlace *MarketPlaceTransactorSession) SetSwivelAddress(s common.Address) (*types.Transaction, error) { + return _MarketPlace.Contract.SetSwivelAddress(&_MarketPlace.TransactOpts, s) +} + +// TransferVaultNotional is a paid mutator transaction binding the contract method 0x5292ecf2. +// +// Solidity: function transferVaultNotional(address u, uint256 m, address t, uint256 a) returns(bool) +func (_MarketPlace *MarketPlaceTransactor) TransferVaultNotional(opts *bind.TransactOpts, u common.Address, m *big.Int, t common.Address, a *big.Int) (*types.Transaction, error) { + return _MarketPlace.contract.Transact(opts, "transferVaultNotional", u, m, t, a) +} + +// TransferVaultNotional is a paid mutator transaction binding the contract method 0x5292ecf2. +// +// Solidity: function transferVaultNotional(address u, uint256 m, address t, uint256 a) returns(bool) +func (_MarketPlace *MarketPlaceSession) TransferVaultNotional(u common.Address, m *big.Int, t common.Address, a *big.Int) (*types.Transaction, error) { + return _MarketPlace.Contract.TransferVaultNotional(&_MarketPlace.TransactOpts, u, m, t, a) +} + +// TransferVaultNotional is a paid mutator transaction binding the contract method 0x5292ecf2. +// +// Solidity: function transferVaultNotional(address u, uint256 m, address t, uint256 a) returns(bool) +func (_MarketPlace *MarketPlaceTransactorSession) TransferVaultNotional(u common.Address, m *big.Int, t common.Address, a *big.Int) (*types.Transaction, error) { + return _MarketPlace.Contract.TransferVaultNotional(&_MarketPlace.TransactOpts, u, m, t, a) +} + +// TransferVaultNotionalFee is a paid mutator transaction binding the contract method 0x3cf9a4e3. +// +// Solidity: function transferVaultNotionalFee(address u, uint256 m, address f, uint256 a) returns(bool) +func (_MarketPlace *MarketPlaceTransactor) TransferVaultNotionalFee(opts *bind.TransactOpts, u common.Address, m *big.Int, f common.Address, a *big.Int) (*types.Transaction, error) { + return _MarketPlace.contract.Transact(opts, "transferVaultNotionalFee", u, m, f, a) +} + +// TransferVaultNotionalFee is a paid mutator transaction binding the contract method 0x3cf9a4e3. +// +// Solidity: function transferVaultNotionalFee(address u, uint256 m, address f, uint256 a) returns(bool) +func (_MarketPlace *MarketPlaceSession) TransferVaultNotionalFee(u common.Address, m *big.Int, f common.Address, a *big.Int) (*types.Transaction, error) { + return _MarketPlace.Contract.TransferVaultNotionalFee(&_MarketPlace.TransactOpts, u, m, f, a) +} + +// TransferVaultNotionalFee is a paid mutator transaction binding the contract method 0x3cf9a4e3. +// +// Solidity: function transferVaultNotionalFee(address u, uint256 m, address f, uint256 a) returns(bool) +func (_MarketPlace *MarketPlaceTransactorSession) TransferVaultNotionalFee(u common.Address, m *big.Int, f common.Address, a *big.Int) (*types.Transaction, error) { + return _MarketPlace.Contract.TransferVaultNotionalFee(&_MarketPlace.TransactOpts, u, m, f, a) +} + +// MarketPlaceCreateIterator is returned from FilterCreate and is used to iterate over the raw logs and unpacked data for Create events raised by the MarketPlace contract. +type MarketPlaceCreateIterator struct { + Event *MarketPlaceCreate // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *MarketPlaceCreateIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(MarketPlaceCreate) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(MarketPlaceCreate) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *MarketPlaceCreateIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *MarketPlaceCreateIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// MarketPlaceCreate represents a Create event raised by the MarketPlace contract. +type MarketPlaceCreate struct { + Underlying common.Address + Maturity *big.Int + CToken common.Address + ZcToken common.Address + VaultTracker common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterCreate is a free log retrieval operation binding the contract event 0x1747a3ed83b35b999b9000df0690f6563f6b016a1cce0c8dfc911866d3b92177. +// +// Solidity: event Create(address indexed underlying, uint256 indexed maturity, address cToken, address zcToken, address vaultTracker) +func (_MarketPlace *MarketPlaceFilterer) FilterCreate(opts *bind.FilterOpts, underlying []common.Address, maturity []*big.Int) (*MarketPlaceCreateIterator, error) { + + var underlyingRule []interface{} + for _, underlyingItem := range underlying { + underlyingRule = append(underlyingRule, underlyingItem) + } + var maturityRule []interface{} + for _, maturityItem := range maturity { + maturityRule = append(maturityRule, maturityItem) + } + + logs, sub, err := _MarketPlace.contract.FilterLogs(opts, "Create", underlyingRule, maturityRule) + if err != nil { + return nil, err + } + return &MarketPlaceCreateIterator{contract: _MarketPlace.contract, event: "Create", logs: logs, sub: sub}, nil +} + +// WatchCreate is a free log subscription operation binding the contract event 0x1747a3ed83b35b999b9000df0690f6563f6b016a1cce0c8dfc911866d3b92177. +// +// Solidity: event Create(address indexed underlying, uint256 indexed maturity, address cToken, address zcToken, address vaultTracker) +func (_MarketPlace *MarketPlaceFilterer) WatchCreate(opts *bind.WatchOpts, sink chan<- *MarketPlaceCreate, underlying []common.Address, maturity []*big.Int) (event.Subscription, error) { + + var underlyingRule []interface{} + for _, underlyingItem := range underlying { + underlyingRule = append(underlyingRule, underlyingItem) + } + var maturityRule []interface{} + for _, maturityItem := range maturity { + maturityRule = append(maturityRule, maturityItem) + } + + logs, sub, err := _MarketPlace.contract.WatchLogs(opts, "Create", underlyingRule, maturityRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(MarketPlaceCreate) + if err := _MarketPlace.contract.UnpackLog(event, "Create", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseCreate is a log parse operation binding the contract event 0x1747a3ed83b35b999b9000df0690f6563f6b016a1cce0c8dfc911866d3b92177. +// +// Solidity: event Create(address indexed underlying, uint256 indexed maturity, address cToken, address zcToken, address vaultTracker) +func (_MarketPlace *MarketPlaceFilterer) ParseCreate(log types.Log) (*MarketPlaceCreate, error) { + event := new(MarketPlaceCreate) + if err := _MarketPlace.contract.UnpackLog(event, "Create", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// MarketPlaceCustodialExitIterator is returned from FilterCustodialExit and is used to iterate over the raw logs and unpacked data for CustodialExit events raised by the MarketPlace contract. +type MarketPlaceCustodialExitIterator struct { + Event *MarketPlaceCustodialExit // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *MarketPlaceCustodialExitIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(MarketPlaceCustodialExit) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(MarketPlaceCustodialExit) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *MarketPlaceCustodialExitIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *MarketPlaceCustodialExitIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// MarketPlaceCustodialExit represents a CustodialExit event raised by the MarketPlace contract. +type MarketPlaceCustodialExit struct { + Underlying common.Address + Maturity *big.Int + ZcTarget common.Address + NTarget common.Address + Amount *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterCustodialExit is a free log retrieval operation binding the contract event 0x219a55ae9a5a1822159d55db6dd594a28be30b02c0d18a71469ef28030b3fb59. +// +// Solidity: event CustodialExit(address indexed underlying, uint256 indexed maturity, address zcTarget, address nTarget, uint256 amount) +func (_MarketPlace *MarketPlaceFilterer) FilterCustodialExit(opts *bind.FilterOpts, underlying []common.Address, maturity []*big.Int) (*MarketPlaceCustodialExitIterator, error) { + + var underlyingRule []interface{} + for _, underlyingItem := range underlying { + underlyingRule = append(underlyingRule, underlyingItem) + } + var maturityRule []interface{} + for _, maturityItem := range maturity { + maturityRule = append(maturityRule, maturityItem) + } + + logs, sub, err := _MarketPlace.contract.FilterLogs(opts, "CustodialExit", underlyingRule, maturityRule) + if err != nil { + return nil, err + } + return &MarketPlaceCustodialExitIterator{contract: _MarketPlace.contract, event: "CustodialExit", logs: logs, sub: sub}, nil +} + +// WatchCustodialExit is a free log subscription operation binding the contract event 0x219a55ae9a5a1822159d55db6dd594a28be30b02c0d18a71469ef28030b3fb59. +// +// Solidity: event CustodialExit(address indexed underlying, uint256 indexed maturity, address zcTarget, address nTarget, uint256 amount) +func (_MarketPlace *MarketPlaceFilterer) WatchCustodialExit(opts *bind.WatchOpts, sink chan<- *MarketPlaceCustodialExit, underlying []common.Address, maturity []*big.Int) (event.Subscription, error) { + + var underlyingRule []interface{} + for _, underlyingItem := range underlying { + underlyingRule = append(underlyingRule, underlyingItem) + } + var maturityRule []interface{} + for _, maturityItem := range maturity { + maturityRule = append(maturityRule, maturityItem) + } + + logs, sub, err := _MarketPlace.contract.WatchLogs(opts, "CustodialExit", underlyingRule, maturityRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(MarketPlaceCustodialExit) + if err := _MarketPlace.contract.UnpackLog(event, "CustodialExit", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseCustodialExit is a log parse operation binding the contract event 0x219a55ae9a5a1822159d55db6dd594a28be30b02c0d18a71469ef28030b3fb59. +// +// Solidity: event CustodialExit(address indexed underlying, uint256 indexed maturity, address zcTarget, address nTarget, uint256 amount) +func (_MarketPlace *MarketPlaceFilterer) ParseCustodialExit(log types.Log) (*MarketPlaceCustodialExit, error) { + event := new(MarketPlaceCustodialExit) + if err := _MarketPlace.contract.UnpackLog(event, "CustodialExit", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// MarketPlaceCustodialInitiateIterator is returned from FilterCustodialInitiate and is used to iterate over the raw logs and unpacked data for CustodialInitiate events raised by the MarketPlace contract. +type MarketPlaceCustodialInitiateIterator struct { + Event *MarketPlaceCustodialInitiate // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *MarketPlaceCustodialInitiateIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(MarketPlaceCustodialInitiate) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(MarketPlaceCustodialInitiate) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *MarketPlaceCustodialInitiateIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *MarketPlaceCustodialInitiateIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// MarketPlaceCustodialInitiate represents a CustodialInitiate event raised by the MarketPlace contract. +type MarketPlaceCustodialInitiate struct { + Underlying common.Address + Maturity *big.Int + ZcTarget common.Address + NTarget common.Address + Amount *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterCustodialInitiate is a free log retrieval operation binding the contract event 0x8dad4d03bd4209aa6dc2bea238510998bf39bb034bc9c20d52f0bd241fc0c516. +// +// Solidity: event CustodialInitiate(address indexed underlying, uint256 indexed maturity, address zcTarget, address nTarget, uint256 amount) +func (_MarketPlace *MarketPlaceFilterer) FilterCustodialInitiate(opts *bind.FilterOpts, underlying []common.Address, maturity []*big.Int) (*MarketPlaceCustodialInitiateIterator, error) { + + var underlyingRule []interface{} + for _, underlyingItem := range underlying { + underlyingRule = append(underlyingRule, underlyingItem) + } + var maturityRule []interface{} + for _, maturityItem := range maturity { + maturityRule = append(maturityRule, maturityItem) + } + + logs, sub, err := _MarketPlace.contract.FilterLogs(opts, "CustodialInitiate", underlyingRule, maturityRule) + if err != nil { + return nil, err + } + return &MarketPlaceCustodialInitiateIterator{contract: _MarketPlace.contract, event: "CustodialInitiate", logs: logs, sub: sub}, nil +} + +// WatchCustodialInitiate is a free log subscription operation binding the contract event 0x8dad4d03bd4209aa6dc2bea238510998bf39bb034bc9c20d52f0bd241fc0c516. +// +// Solidity: event CustodialInitiate(address indexed underlying, uint256 indexed maturity, address zcTarget, address nTarget, uint256 amount) +func (_MarketPlace *MarketPlaceFilterer) WatchCustodialInitiate(opts *bind.WatchOpts, sink chan<- *MarketPlaceCustodialInitiate, underlying []common.Address, maturity []*big.Int) (event.Subscription, error) { + + var underlyingRule []interface{} + for _, underlyingItem := range underlying { + underlyingRule = append(underlyingRule, underlyingItem) + } + var maturityRule []interface{} + for _, maturityItem := range maturity { + maturityRule = append(maturityRule, maturityItem) + } + + logs, sub, err := _MarketPlace.contract.WatchLogs(opts, "CustodialInitiate", underlyingRule, maturityRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(MarketPlaceCustodialInitiate) + if err := _MarketPlace.contract.UnpackLog(event, "CustodialInitiate", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseCustodialInitiate is a log parse operation binding the contract event 0x8dad4d03bd4209aa6dc2bea238510998bf39bb034bc9c20d52f0bd241fc0c516. +// +// Solidity: event CustodialInitiate(address indexed underlying, uint256 indexed maturity, address zcTarget, address nTarget, uint256 amount) +func (_MarketPlace *MarketPlaceFilterer) ParseCustodialInitiate(log types.Log) (*MarketPlaceCustodialInitiate, error) { + event := new(MarketPlaceCustodialInitiate) + if err := _MarketPlace.contract.UnpackLog(event, "CustodialInitiate", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// MarketPlaceMatureIterator is returned from FilterMature and is used to iterate over the raw logs and unpacked data for Mature events raised by the MarketPlace contract. +type MarketPlaceMatureIterator struct { + Event *MarketPlaceMature // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *MarketPlaceMatureIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(MarketPlaceMature) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(MarketPlaceMature) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *MarketPlaceMatureIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *MarketPlaceMatureIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// MarketPlaceMature represents a Mature event raised by the MarketPlace contract. +type MarketPlaceMature struct { + Underlying common.Address + Maturity *big.Int + MaturityRate *big.Int + Matured *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterMature is a free log retrieval operation binding the contract event 0x0080e09d7b4544aa5a923873be1df3e31945593d40cb1c874d99259ec3ac43a4. +// +// Solidity: event Mature(address indexed underlying, uint256 indexed maturity, uint256 maturityRate, uint256 matured) +func (_MarketPlace *MarketPlaceFilterer) FilterMature(opts *bind.FilterOpts, underlying []common.Address, maturity []*big.Int) (*MarketPlaceMatureIterator, error) { + + var underlyingRule []interface{} + for _, underlyingItem := range underlying { + underlyingRule = append(underlyingRule, underlyingItem) + } + var maturityRule []interface{} + for _, maturityItem := range maturity { + maturityRule = append(maturityRule, maturityItem) + } + + logs, sub, err := _MarketPlace.contract.FilterLogs(opts, "Mature", underlyingRule, maturityRule) + if err != nil { + return nil, err + } + return &MarketPlaceMatureIterator{contract: _MarketPlace.contract, event: "Mature", logs: logs, sub: sub}, nil +} + +// WatchMature is a free log subscription operation binding the contract event 0x0080e09d7b4544aa5a923873be1df3e31945593d40cb1c874d99259ec3ac43a4. +// +// Solidity: event Mature(address indexed underlying, uint256 indexed maturity, uint256 maturityRate, uint256 matured) +func (_MarketPlace *MarketPlaceFilterer) WatchMature(opts *bind.WatchOpts, sink chan<- *MarketPlaceMature, underlying []common.Address, maturity []*big.Int) (event.Subscription, error) { + + var underlyingRule []interface{} + for _, underlyingItem := range underlying { + underlyingRule = append(underlyingRule, underlyingItem) + } + var maturityRule []interface{} + for _, maturityItem := range maturity { + maturityRule = append(maturityRule, maturityItem) + } + + logs, sub, err := _MarketPlace.contract.WatchLogs(opts, "Mature", underlyingRule, maturityRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(MarketPlaceMature) + if err := _MarketPlace.contract.UnpackLog(event, "Mature", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseMature is a log parse operation binding the contract event 0x0080e09d7b4544aa5a923873be1df3e31945593d40cb1c874d99259ec3ac43a4. +// +// Solidity: event Mature(address indexed underlying, uint256 indexed maturity, uint256 maturityRate, uint256 matured) +func (_MarketPlace *MarketPlaceFilterer) ParseMature(log types.Log) (*MarketPlaceMature, error) { + event := new(MarketPlaceMature) + if err := _MarketPlace.contract.UnpackLog(event, "Mature", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// MarketPlaceP2pVaultExchangeIterator is returned from FilterP2pVaultExchange and is used to iterate over the raw logs and unpacked data for P2pVaultExchange events raised by the MarketPlace contract. +type MarketPlaceP2pVaultExchangeIterator struct { + Event *MarketPlaceP2pVaultExchange // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *MarketPlaceP2pVaultExchangeIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(MarketPlaceP2pVaultExchange) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(MarketPlaceP2pVaultExchange) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *MarketPlaceP2pVaultExchangeIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *MarketPlaceP2pVaultExchangeIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// MarketPlaceP2pVaultExchange represents a P2pVaultExchange event raised by the MarketPlace contract. +type MarketPlaceP2pVaultExchange struct { + Underlying common.Address + Maturity *big.Int + From common.Address + To common.Address + Amount *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterP2pVaultExchange is a free log retrieval operation binding the contract event 0x31d266c2b6075063717026bd27ba8bb527366457893dc211091b2e1d9713f152. +// +// Solidity: event P2pVaultExchange(address indexed underlying, uint256 indexed maturity, address from, address to, uint256 amount) +func (_MarketPlace *MarketPlaceFilterer) FilterP2pVaultExchange(opts *bind.FilterOpts, underlying []common.Address, maturity []*big.Int) (*MarketPlaceP2pVaultExchangeIterator, error) { + + var underlyingRule []interface{} + for _, underlyingItem := range underlying { + underlyingRule = append(underlyingRule, underlyingItem) + } + var maturityRule []interface{} + for _, maturityItem := range maturity { + maturityRule = append(maturityRule, maturityItem) + } + + logs, sub, err := _MarketPlace.contract.FilterLogs(opts, "P2pVaultExchange", underlyingRule, maturityRule) + if err != nil { + return nil, err + } + return &MarketPlaceP2pVaultExchangeIterator{contract: _MarketPlace.contract, event: "P2pVaultExchange", logs: logs, sub: sub}, nil +} + +// WatchP2pVaultExchange is a free log subscription operation binding the contract event 0x31d266c2b6075063717026bd27ba8bb527366457893dc211091b2e1d9713f152. +// +// Solidity: event P2pVaultExchange(address indexed underlying, uint256 indexed maturity, address from, address to, uint256 amount) +func (_MarketPlace *MarketPlaceFilterer) WatchP2pVaultExchange(opts *bind.WatchOpts, sink chan<- *MarketPlaceP2pVaultExchange, underlying []common.Address, maturity []*big.Int) (event.Subscription, error) { + + var underlyingRule []interface{} + for _, underlyingItem := range underlying { + underlyingRule = append(underlyingRule, underlyingItem) + } + var maturityRule []interface{} + for _, maturityItem := range maturity { + maturityRule = append(maturityRule, maturityItem) + } + + logs, sub, err := _MarketPlace.contract.WatchLogs(opts, "P2pVaultExchange", underlyingRule, maturityRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(MarketPlaceP2pVaultExchange) + if err := _MarketPlace.contract.UnpackLog(event, "P2pVaultExchange", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseP2pVaultExchange is a log parse operation binding the contract event 0x31d266c2b6075063717026bd27ba8bb527366457893dc211091b2e1d9713f152. +// +// Solidity: event P2pVaultExchange(address indexed underlying, uint256 indexed maturity, address from, address to, uint256 amount) +func (_MarketPlace *MarketPlaceFilterer) ParseP2pVaultExchange(log types.Log) (*MarketPlaceP2pVaultExchange, error) { + event := new(MarketPlaceP2pVaultExchange) + if err := _MarketPlace.contract.UnpackLog(event, "P2pVaultExchange", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// MarketPlaceP2pZcTokenExchangeIterator is returned from FilterP2pZcTokenExchange and is used to iterate over the raw logs and unpacked data for P2pZcTokenExchange events raised by the MarketPlace contract. +type MarketPlaceP2pZcTokenExchangeIterator struct { + Event *MarketPlaceP2pZcTokenExchange // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *MarketPlaceP2pZcTokenExchangeIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(MarketPlaceP2pZcTokenExchange) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(MarketPlaceP2pZcTokenExchange) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *MarketPlaceP2pZcTokenExchangeIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *MarketPlaceP2pZcTokenExchangeIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// MarketPlaceP2pZcTokenExchange represents a P2pZcTokenExchange event raised by the MarketPlace contract. +type MarketPlaceP2pZcTokenExchange struct { + Underlying common.Address + Maturity *big.Int + From common.Address + To common.Address + Amount *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterP2pZcTokenExchange is a free log retrieval operation binding the contract event 0x86ac24e4ee753e21fb51afa847265cb350e500593f3204057e40079c3ef54422. +// +// Solidity: event P2pZcTokenExchange(address indexed underlying, uint256 indexed maturity, address from, address to, uint256 amount) +func (_MarketPlace *MarketPlaceFilterer) FilterP2pZcTokenExchange(opts *bind.FilterOpts, underlying []common.Address, maturity []*big.Int) (*MarketPlaceP2pZcTokenExchangeIterator, error) { + + var underlyingRule []interface{} + for _, underlyingItem := range underlying { + underlyingRule = append(underlyingRule, underlyingItem) + } + var maturityRule []interface{} + for _, maturityItem := range maturity { + maturityRule = append(maturityRule, maturityItem) + } + + logs, sub, err := _MarketPlace.contract.FilterLogs(opts, "P2pZcTokenExchange", underlyingRule, maturityRule) + if err != nil { + return nil, err + } + return &MarketPlaceP2pZcTokenExchangeIterator{contract: _MarketPlace.contract, event: "P2pZcTokenExchange", logs: logs, sub: sub}, nil +} + +// WatchP2pZcTokenExchange is a free log subscription operation binding the contract event 0x86ac24e4ee753e21fb51afa847265cb350e500593f3204057e40079c3ef54422. +// +// Solidity: event P2pZcTokenExchange(address indexed underlying, uint256 indexed maturity, address from, address to, uint256 amount) +func (_MarketPlace *MarketPlaceFilterer) WatchP2pZcTokenExchange(opts *bind.WatchOpts, sink chan<- *MarketPlaceP2pZcTokenExchange, underlying []common.Address, maturity []*big.Int) (event.Subscription, error) { + + var underlyingRule []interface{} + for _, underlyingItem := range underlying { + underlyingRule = append(underlyingRule, underlyingItem) + } + var maturityRule []interface{} + for _, maturityItem := range maturity { + maturityRule = append(maturityRule, maturityItem) + } + + logs, sub, err := _MarketPlace.contract.WatchLogs(opts, "P2pZcTokenExchange", underlyingRule, maturityRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(MarketPlaceP2pZcTokenExchange) + if err := _MarketPlace.contract.UnpackLog(event, "P2pZcTokenExchange", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseP2pZcTokenExchange is a log parse operation binding the contract event 0x86ac24e4ee753e21fb51afa847265cb350e500593f3204057e40079c3ef54422. +// +// Solidity: event P2pZcTokenExchange(address indexed underlying, uint256 indexed maturity, address from, address to, uint256 amount) +func (_MarketPlace *MarketPlaceFilterer) ParseP2pZcTokenExchange(log types.Log) (*MarketPlaceP2pZcTokenExchange, error) { + event := new(MarketPlaceP2pZcTokenExchange) + if err := _MarketPlace.contract.UnpackLog(event, "P2pZcTokenExchange", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// MarketPlaceRedeemVaultInterestIterator is returned from FilterRedeemVaultInterest and is used to iterate over the raw logs and unpacked data for RedeemVaultInterest events raised by the MarketPlace contract. +type MarketPlaceRedeemVaultInterestIterator struct { + Event *MarketPlaceRedeemVaultInterest // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *MarketPlaceRedeemVaultInterestIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(MarketPlaceRedeemVaultInterest) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(MarketPlaceRedeemVaultInterest) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *MarketPlaceRedeemVaultInterestIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *MarketPlaceRedeemVaultInterestIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// MarketPlaceRedeemVaultInterest represents a RedeemVaultInterest event raised by the MarketPlace contract. +type MarketPlaceRedeemVaultInterest struct { + Underlying common.Address + Maturity *big.Int + Sender common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterRedeemVaultInterest is a free log retrieval operation binding the contract event 0x646390328280b54978a07e7bd72dd9b3f9515286196024882943a96d5c279874. +// +// Solidity: event RedeemVaultInterest(address indexed underlying, uint256 indexed maturity, address indexed sender) +func (_MarketPlace *MarketPlaceFilterer) FilterRedeemVaultInterest(opts *bind.FilterOpts, underlying []common.Address, maturity []*big.Int, sender []common.Address) (*MarketPlaceRedeemVaultInterestIterator, error) { + + var underlyingRule []interface{} + for _, underlyingItem := range underlying { + underlyingRule = append(underlyingRule, underlyingItem) + } + var maturityRule []interface{} + for _, maturityItem := range maturity { + maturityRule = append(maturityRule, maturityItem) + } + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _MarketPlace.contract.FilterLogs(opts, "RedeemVaultInterest", underlyingRule, maturityRule, senderRule) + if err != nil { + return nil, err + } + return &MarketPlaceRedeemVaultInterestIterator{contract: _MarketPlace.contract, event: "RedeemVaultInterest", logs: logs, sub: sub}, nil +} + +// WatchRedeemVaultInterest is a free log subscription operation binding the contract event 0x646390328280b54978a07e7bd72dd9b3f9515286196024882943a96d5c279874. +// +// Solidity: event RedeemVaultInterest(address indexed underlying, uint256 indexed maturity, address indexed sender) +func (_MarketPlace *MarketPlaceFilterer) WatchRedeemVaultInterest(opts *bind.WatchOpts, sink chan<- *MarketPlaceRedeemVaultInterest, underlying []common.Address, maturity []*big.Int, sender []common.Address) (event.Subscription, error) { + + var underlyingRule []interface{} + for _, underlyingItem := range underlying { + underlyingRule = append(underlyingRule, underlyingItem) + } + var maturityRule []interface{} + for _, maturityItem := range maturity { + maturityRule = append(maturityRule, maturityItem) + } + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _MarketPlace.contract.WatchLogs(opts, "RedeemVaultInterest", underlyingRule, maturityRule, senderRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(MarketPlaceRedeemVaultInterest) + if err := _MarketPlace.contract.UnpackLog(event, "RedeemVaultInterest", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseRedeemVaultInterest is a log parse operation binding the contract event 0x646390328280b54978a07e7bd72dd9b3f9515286196024882943a96d5c279874. +// +// Solidity: event RedeemVaultInterest(address indexed underlying, uint256 indexed maturity, address indexed sender) +func (_MarketPlace *MarketPlaceFilterer) ParseRedeemVaultInterest(log types.Log) (*MarketPlaceRedeemVaultInterest, error) { + event := new(MarketPlaceRedeemVaultInterest) + if err := _MarketPlace.contract.UnpackLog(event, "RedeemVaultInterest", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// MarketPlaceRedeemZcTokenIterator is returned from FilterRedeemZcToken and is used to iterate over the raw logs and unpacked data for RedeemZcToken events raised by the MarketPlace contract. +type MarketPlaceRedeemZcTokenIterator struct { + Event *MarketPlaceRedeemZcToken // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *MarketPlaceRedeemZcTokenIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(MarketPlaceRedeemZcToken) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(MarketPlaceRedeemZcToken) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *MarketPlaceRedeemZcTokenIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *MarketPlaceRedeemZcTokenIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// MarketPlaceRedeemZcToken represents a RedeemZcToken event raised by the MarketPlace contract. +type MarketPlaceRedeemZcToken struct { + Underlying common.Address + Maturity *big.Int + Sender common.Address + Amount *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterRedeemZcToken is a free log retrieval operation binding the contract event 0x49dc20daa9f95793b82245100affbf87ad23d1761bdef94975542564f4023e45. +// +// Solidity: event RedeemZcToken(address indexed underlying, uint256 indexed maturity, address indexed sender, uint256 amount) +func (_MarketPlace *MarketPlaceFilterer) FilterRedeemZcToken(opts *bind.FilterOpts, underlying []common.Address, maturity []*big.Int, sender []common.Address) (*MarketPlaceRedeemZcTokenIterator, error) { + + var underlyingRule []interface{} + for _, underlyingItem := range underlying { + underlyingRule = append(underlyingRule, underlyingItem) + } + var maturityRule []interface{} + for _, maturityItem := range maturity { + maturityRule = append(maturityRule, maturityItem) + } + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _MarketPlace.contract.FilterLogs(opts, "RedeemZcToken", underlyingRule, maturityRule, senderRule) + if err != nil { + return nil, err + } + return &MarketPlaceRedeemZcTokenIterator{contract: _MarketPlace.contract, event: "RedeemZcToken", logs: logs, sub: sub}, nil +} + +// WatchRedeemZcToken is a free log subscription operation binding the contract event 0x49dc20daa9f95793b82245100affbf87ad23d1761bdef94975542564f4023e45. +// +// Solidity: event RedeemZcToken(address indexed underlying, uint256 indexed maturity, address indexed sender, uint256 amount) +func (_MarketPlace *MarketPlaceFilterer) WatchRedeemZcToken(opts *bind.WatchOpts, sink chan<- *MarketPlaceRedeemZcToken, underlying []common.Address, maturity []*big.Int, sender []common.Address) (event.Subscription, error) { + + var underlyingRule []interface{} + for _, underlyingItem := range underlying { + underlyingRule = append(underlyingRule, underlyingItem) + } + var maturityRule []interface{} + for _, maturityItem := range maturity { + maturityRule = append(maturityRule, maturityItem) + } + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _MarketPlace.contract.WatchLogs(opts, "RedeemZcToken", underlyingRule, maturityRule, senderRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(MarketPlaceRedeemZcToken) + if err := _MarketPlace.contract.UnpackLog(event, "RedeemZcToken", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseRedeemZcToken is a log parse operation binding the contract event 0x49dc20daa9f95793b82245100affbf87ad23d1761bdef94975542564f4023e45. +// +// Solidity: event RedeemZcToken(address indexed underlying, uint256 indexed maturity, address indexed sender, uint256 amount) +func (_MarketPlace *MarketPlaceFilterer) ParseRedeemZcToken(log types.Log) (*MarketPlaceRedeemZcToken, error) { + event := new(MarketPlaceRedeemZcToken) + if err := _MarketPlace.contract.UnpackLog(event, "RedeemZcToken", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// MarketPlaceTransferVaultNotionalIterator is returned from FilterTransferVaultNotional and is used to iterate over the raw logs and unpacked data for TransferVaultNotional events raised by the MarketPlace contract. +type MarketPlaceTransferVaultNotionalIterator struct { + Event *MarketPlaceTransferVaultNotional // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *MarketPlaceTransferVaultNotionalIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(MarketPlaceTransferVaultNotional) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(MarketPlaceTransferVaultNotional) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *MarketPlaceTransferVaultNotionalIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *MarketPlaceTransferVaultNotionalIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// MarketPlaceTransferVaultNotional represents a TransferVaultNotional event raised by the MarketPlace contract. +type MarketPlaceTransferVaultNotional struct { + Underlying common.Address + Maturity *big.Int + From common.Address + To common.Address + Amount *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterTransferVaultNotional is a free log retrieval operation binding the contract event 0x1d06fe04c445804d7b460d2d5f2fee7c4cc5ba874f3311d2768f849c66cf3098. +// +// Solidity: event TransferVaultNotional(address indexed underlying, uint256 indexed maturity, address from, address to, uint256 amount) +func (_MarketPlace *MarketPlaceFilterer) FilterTransferVaultNotional(opts *bind.FilterOpts, underlying []common.Address, maturity []*big.Int) (*MarketPlaceTransferVaultNotionalIterator, error) { + + var underlyingRule []interface{} + for _, underlyingItem := range underlying { + underlyingRule = append(underlyingRule, underlyingItem) + } + var maturityRule []interface{} + for _, maturityItem := range maturity { + maturityRule = append(maturityRule, maturityItem) + } + + logs, sub, err := _MarketPlace.contract.FilterLogs(opts, "TransferVaultNotional", underlyingRule, maturityRule) + if err != nil { + return nil, err + } + return &MarketPlaceTransferVaultNotionalIterator{contract: _MarketPlace.contract, event: "TransferVaultNotional", logs: logs, sub: sub}, nil +} + +// WatchTransferVaultNotional is a free log subscription operation binding the contract event 0x1d06fe04c445804d7b460d2d5f2fee7c4cc5ba874f3311d2768f849c66cf3098. +// +// Solidity: event TransferVaultNotional(address indexed underlying, uint256 indexed maturity, address from, address to, uint256 amount) +func (_MarketPlace *MarketPlaceFilterer) WatchTransferVaultNotional(opts *bind.WatchOpts, sink chan<- *MarketPlaceTransferVaultNotional, underlying []common.Address, maturity []*big.Int) (event.Subscription, error) { + + var underlyingRule []interface{} + for _, underlyingItem := range underlying { + underlyingRule = append(underlyingRule, underlyingItem) + } + var maturityRule []interface{} + for _, maturityItem := range maturity { + maturityRule = append(maturityRule, maturityItem) + } + + logs, sub, err := _MarketPlace.contract.WatchLogs(opts, "TransferVaultNotional", underlyingRule, maturityRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(MarketPlaceTransferVaultNotional) + if err := _MarketPlace.contract.UnpackLog(event, "TransferVaultNotional", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseTransferVaultNotional is a log parse operation binding the contract event 0x1d06fe04c445804d7b460d2d5f2fee7c4cc5ba874f3311d2768f849c66cf3098. +// +// Solidity: event TransferVaultNotional(address indexed underlying, uint256 indexed maturity, address from, address to, uint256 amount) +func (_MarketPlace *MarketPlaceFilterer) ParseTransferVaultNotional(log types.Log) (*MarketPlaceTransferVaultNotional, error) { + event := new(MarketPlaceTransferVaultNotional) + if err := _MarketPlace.contract.UnpackLog(event, "TransferVaultNotional", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} diff --git a/gost/test/mocks/CErc20.abi b/gost/test/mocks/CErc20.abi new file mode 100644 index 0000000..1ed913b --- /dev/null +++ b/gost/test/mocks/CErc20.abi @@ -0,0 +1 @@ +[{"inputs":[],"name":"exchangeRateCurrent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"n","type":"uint256"}],"name":"exchangeRateCurrentReturns","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"n","type":"uint256"}],"name":"mint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"mintCalled","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"n","type":"uint256"}],"name":"mintReturns","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"n","type":"uint256"}],"name":"redeem","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"redeemCalled","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"n","type":"uint256"}],"name":"redeemReturns","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"n","type":"uint256"}],"name":"redeemUnderlying","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"redeemUnderlyingCalled","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"n","type":"uint256"}],"name":"redeemUnderlyingReturns","outputs":[],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file diff --git a/gost/test/mocks/CErc20.bin b/gost/test/mocks/CErc20.bin new file mode 100644 index 0000000..89308a6 --- /dev/null +++ b/gost/test/mocks/CErc20.bin @@ -0,0 +1 @@ +608060405234801561001057600080fd5b50610362806100206000396000f3fe608060405234801561001057600080fd5b50600436106100a95760003560e01c8063be6babbf11610071578063be6babbf14610164578063d4e7fdd414610182578063d6bcd7aa146101a0578063db006a75146101be578063de9d2a72146101ee578063e7a7b9ce1461020a576100a9565b806329d9ce3e146100ae578063852a12e3146100ca5780639ff9f1d4146100fa578063a0712d6814610116578063bd6d894d14610146575b600080fd5b6100c860048036038101906100c391906102b8565b610226565b005b6100e460048036038101906100df91906102b8565b610230565b6040516100f191906102f0565b60405180910390f35b610114600480360381019061010f91906102b8565b610243565b005b610130600480360381019061012b91906102b8565b61024d565b60405161013d91906102f0565b60405180910390f35b61014e610260565b60405161015b91906102f0565b60405180910390f35b61016c61026a565b60405161017991906102f0565b60405180910390f35b61018a610270565b60405161019791906102f0565b60405180910390f35b6101a8610276565b6040516101b591906102f0565b60405180910390f35b6101d860048036038101906101d391906102b8565b61027c565b6040516101e591906102f0565b60405180910390f35b610208600480360381019061020391906102b8565b61028f565b005b610224600480360381019061021f91906102b8565b610299565b005b8060048190555050565b6000816005819055506004549050919050565b8060068190555050565b6000816001819055506000549050919050565b6000600654905090565b60035481565b60015481565b60055481565b6000816003819055506002549050919050565b8060028190555050565b8060008190555050565b6000813590506102b281610315565b92915050565b6000602082840312156102ca57600080fd5b60006102d8848285016102a3565b91505092915050565b6102ea8161030b565b82525050565b600060208201905061030560008301846102e1565b92915050565b6000819050919050565b61031e8161030b565b811461032957600080fd5b5056fea2646970667358221220ddfaaf48e10553118ec44cd18879e4407f44441670b2f4daa8e5cfc9340a70d464736f6c63430008040033 \ No newline at end of file diff --git a/gost/test/mocks/CErc20.sol b/gost/test/mocks/CErc20.sol new file mode 100644 index 0000000..3231b09 --- /dev/null +++ b/gost/test/mocks/CErc20.sol @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: UNLICENSED + +/** + CErc20 is a mock compound token with stubs of the methods we need for testing. +*/ + +pragma solidity 0.8.4; + +// TODO this could inherit from the ERC20 mock if needed +contract CErc20 { + /// @dev allows us to dictate return from mint(). + uint256 private mintReturn; + /// @dev the last amount mint was called with + uint256 public mintCalled; + + /// @dev allows us to dictate return from redeem(). + uint256 private redeemReturn; + /// @dev the last amount redeem was called with + uint256 public redeemCalled; + + /// @dev allows us to dictate return from redeemUnderlying(). + uint256 private redeemUnderlyingReturn; + /// @dev the last amount redeemUnderlying was called with + uint256 public redeemUnderlyingCalled; + + /// @dev allows us to dictate return from exchangeRateCurrent(). + uint256 private exchangeRateCurrentReturn; + + function mint(uint256 n) public returns (uint256) { + mintCalled = n; + return mintReturn; + } + + function mintReturns(uint256 n) public { + mintReturn = n; + } + + function redeem(uint256 n) public returns (uint256) { + redeemCalled = n; + return redeemReturn; + } + + function redeemReturns(uint256 n) public { + redeemReturn = n; + } + + function redeemUnderlying(uint256 n) public returns (uint256) { + redeemUnderlyingCalled = n; + return redeemUnderlyingReturn; + } + + function redeemUnderlyingReturns(uint256 n) public { + redeemUnderlyingReturn = n; + } + + function exchangeRateCurrent() public view returns (uint256) { + return exchangeRateCurrentReturn; + } + + function exchangeRateCurrentReturns(uint256 n) public { + exchangeRateCurrentReturn = n; + } + +} diff --git a/gost/test/mocks/Erc20.abi b/gost/test/mocks/Erc20.abi new file mode 100644 index 0000000..c5769dc --- /dev/null +++ b/gost/test/mocks/Erc20.abi @@ -0,0 +1 @@ +[{"inputs":[{"internalType":"address","name":"s","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"approveCalled","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"b","type":"bool"}],"name":"approveReturns","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"t","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"balanceOfCalled","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"b","type":"uint256"}],"name":"balanceOfReturns","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"t","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"transferCalled","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"f","type":"address"},{"internalType":"address","name":"t","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"transferFromCalled","outputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"b","type":"bool"}],"name":"transferFromReturns","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"b","type":"bool"}],"name":"transferReturns","outputs":[],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file diff --git a/gost/test/mocks/Erc20.bin b/gost/test/mocks/Erc20.bin new file mode 100644 index 0000000..bae3f2f --- /dev/null +++ b/gost/test/mocks/Erc20.bin @@ -0,0 +1 @@ +608060405234801561001057600080fd5b50610874806100206000396000f3fe608060405234801561001057600080fd5b50600436106100b45760003560e01c806370a082311161007157806370a082311461019d5780639dd0ff37146101cd578063a9059cbb146101e9578063c1d2e9a114610219578063dea1a7e214610249578063e541efa214610267576100b4565b8063095ea7b3146100b957806323b872dd146100e9578063391008381461011957806342b6cdbc146101355780636521b96a146101515780636581d5431461016d575b600080fd5b6100d360048036038101906100ce919061067c565b610298565b6040516100e0919061077b565b60405180910390f35b61010360048036038101906100fe919061062d565b6102f5565b604051610110919061077b565b60405180910390f35b610133600480360381019061012e91906106e1565b6103ef565b005b61014f600480360381019061014a91906106b8565b6103f9565b005b61016b600480360381019061016691906106b8565b610416565b005b61018760048036038101906101829190610604565b610433565b6040516101949190610796565b60405180910390f35b6101b760048036038101906101b29190610604565b61044b565b6040516101c49190610796565b60405180910390f35b6101e760048036038101906101e291906106b8565b610498565b005b61020360048036038101906101fe919061067c565b6104b5565b604051610210919061077b565b60405180910390f35b610233600480360381019061022e9190610604565b610513565b6040516102409190610796565b60405180910390f35b61025161052b565b60405161025e9190610737565b60405180910390f35b610281600480360381019061027c9190610604565b610551565b60405161028f929190610752565b60405180910390f35b6000816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550600360149054906101000a900460ff16905092915050565b60006102ff610595565b83816000019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508281602001818152505080600260008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008201518160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060208201518160010155905050600560019054906101000a900460ff169150509392505050565b8060048190555050565b80600560006101000a81548160ff02191690831515021790555050565b80600560016101000a81548160ff02191690831515021790555050565b60006020528060005260406000206000915090505481565b600081600360006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506004549050919050565b80600360146101000a81548160ff02191690831515021790555050565b600081600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550600560009054906101000a900460ff16905092915050565b60016020528060005260406000206000915090505481565b600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60026020528060005260406000206000915090508060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060010154905082565b6040518060400160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600081525090565b6000813590506105d4816107f9565b92915050565b6000813590506105e981610810565b92915050565b6000813590506105fe81610827565b92915050565b60006020828403121561061657600080fd5b6000610624848285016105c5565b91505092915050565b60008060006060848603121561064257600080fd5b6000610650868287016105c5565b9350506020610661868287016105c5565b9250506040610672868287016105ef565b9150509250925092565b6000806040838503121561068f57600080fd5b600061069d858286016105c5565b92505060206106ae858286016105ef565b9150509250929050565b6000602082840312156106ca57600080fd5b60006106d8848285016105da565b91505092915050565b6000602082840312156106f357600080fd5b6000610701848285016105ef565b91505092915050565b610713816107b1565b82525050565b610722816107c3565b82525050565b610731816107ef565b82525050565b600060208201905061074c600083018461070a565b92915050565b6000604082019050610767600083018561070a565b6107746020830184610728565b9392505050565b60006020820190506107906000830184610719565b92915050565b60006020820190506107ab6000830184610728565b92915050565b60006107bc826107cf565b9050919050565b60008115159050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b610802816107b1565b811461080d57600080fd5b50565b610819816107c3565b811461082457600080fd5b50565b610830816107ef565b811461083b57600080fd5b5056fea26469706673582212205c49e2ec19f2e3bcd87bf0ebeb7efcc9ac2fda4f153bea6694de1f4912d35d6264736f6c63430008040033 \ No newline at end of file diff --git a/gost/test/mocks/Erc20.sol b/gost/test/mocks/Erc20.sol new file mode 100644 index 0000000..71a3988 --- /dev/null +++ b/gost/test/mocks/Erc20.sol @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: UNLICENSED + +/** + Erc20 is a mock which records arguments passed to its methods as well as + provides setters allowing us to dictate method return values +*/ + +pragma solidity 0.8.4; + +contract Erc20 { + // a struct to hold the arguments passed to transferFrom + struct TransferFromArgs { + address to; + uint256 amount; + } + + // mapping for arguments passed to approve + mapping (address => uint256) public approveCalled; + // mapping of arguments sent to transfer. key is the passed in address. + mapping (address => uint256) public transferCalled; + // mapping of arguments sent to transferFrom. key is passed from address. + mapping (address => TransferFromArgs) public transferFromCalled; + // balanceOf does not require a mapping. + address public balanceOfCalled; + + // a boolean flag which allows us to dictate the return of approve(). + bool private approveReturn; + // a uint to return for balanceOf calls + uint256 private balanceOfReturn; + // a boolean flag which allows us to dictate the return of transfer(). + bool private transferReturn; + // a boolean flag which allows us to dictate the return of transferFrom(). + bool private transferFromReturn; + + function approve(address s, uint256 a) public returns (bool) { + approveCalled[s] = a; + return approveReturn; + } + + function approveReturns(bool b) public { + approveReturn = b; + } + + function balanceOfReturns(uint256 b) public { + balanceOfReturn = b; + } + + function balanceOf(address t) public returns (uint256) { + balanceOfCalled = t; + return balanceOfReturn; + } + + function transfer(address t, uint256 a) public returns (bool) { + transferCalled[t] = a; + return transferReturn; + } + + function transferReturns(bool b) public { + transferReturn = b; + } + + function transferFrom(address f, address t, uint256 a) public returns (bool) { + TransferFromArgs memory args; + args.to = t; + args.amount = a; + transferFromCalled[f] = args; + return transferFromReturn; + } + + function transferFromReturns(bool b) public { + transferFromReturn = b; + } + +} diff --git a/gost/test/mocks/MarketPlace.abi b/gost/test/mocks/MarketPlace.abi new file mode 100644 index 0000000..794baaa --- /dev/null +++ b/gost/test/mocks/MarketPlace.abi @@ -0,0 +1 @@ +[{"inputs":[{"internalType":"address","name":"u","type":"address"},{"internalType":"uint256","name":"m","type":"uint256"},{"internalType":"address","name":"t","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"burnZcTokenRemovingNotional","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"burnZcTokenRemovingNotionalCalled","outputs":[{"internalType":"uint256","name":"maturity","type":"uint256"},{"internalType":"address","name":"one","type":"address"},{"internalType":"address","name":"two","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"b","type":"bool"}],"name":"burnZcTokenRemovingNotionalReturns","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"u","type":"address"},{"internalType":"uint256","name":"m","type":"uint256"}],"name":"cTokenAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"cTokenAddressCalled","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"a","type":"address"}],"name":"cTokenAddressReturns","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"u","type":"address"},{"internalType":"uint256","name":"m","type":"uint256"},{"internalType":"address","name":"o","type":"address"},{"internalType":"address","name":"t","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"custodialExit","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"custodialExitCalled","outputs":[{"internalType":"uint256","name":"maturity","type":"uint256"},{"internalType":"address","name":"one","type":"address"},{"internalType":"address","name":"two","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"b","type":"bool"}],"name":"custodialExitReturns","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"u","type":"address"},{"internalType":"uint256","name":"m","type":"uint256"},{"internalType":"address","name":"o","type":"address"},{"internalType":"address","name":"t","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"custodialInitiate","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"custodialInitiateCalled","outputs":[{"internalType":"uint256","name":"maturity","type":"uint256"},{"internalType":"address","name":"one","type":"address"},{"internalType":"address","name":"two","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"b","type":"bool"}],"name":"custodialInitiateReturns","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"u","type":"address"},{"internalType":"uint256","name":"m","type":"uint256"},{"internalType":"address","name":"t","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"mintZcTokenAddingNotional","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"mintZcTokenAddingNotionalCalled","outputs":[{"internalType":"uint256","name":"maturity","type":"uint256"},{"internalType":"address","name":"one","type":"address"},{"internalType":"address","name":"two","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"b","type":"bool"}],"name":"mintZcTokenAddingNotionalReturns","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"u","type":"address"},{"internalType":"uint256","name":"m","type":"uint256"},{"internalType":"address","name":"o","type":"address"},{"internalType":"address","name":"t","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"p2pVaultExchange","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"p2pVaultExchangeCalled","outputs":[{"internalType":"uint256","name":"maturity","type":"uint256"},{"internalType":"address","name":"one","type":"address"},{"internalType":"address","name":"two","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"b","type":"bool"}],"name":"p2pVaultExchangeReturns","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"u","type":"address"},{"internalType":"uint256","name":"m","type":"uint256"},{"internalType":"address","name":"o","type":"address"},{"internalType":"address","name":"t","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"p2pZcTokenExchange","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"p2pZcTokenExchangeCalled","outputs":[{"internalType":"uint256","name":"maturity","type":"uint256"},{"internalType":"address","name":"one","type":"address"},{"internalType":"address","name":"two","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"b","type":"bool"}],"name":"p2pZcTokenExchangeReturns","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"u","type":"address"},{"internalType":"uint256","name":"m","type":"uint256"},{"internalType":"address","name":"t","type":"address"}],"name":"redeemVaultInterest","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"redeemVaultInterestCalled","outputs":[{"internalType":"uint256","name":"maturity","type":"uint256"},{"internalType":"address","name":"one","type":"address"},{"internalType":"address","name":"two","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"a","type":"uint256"}],"name":"redeemVaultInterestReturns","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"u","type":"address"},{"internalType":"uint256","name":"m","type":"uint256"},{"internalType":"address","name":"t","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"redeemZcToken","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"redeemZcTokenCalled","outputs":[{"internalType":"uint256","name":"maturity","type":"uint256"},{"internalType":"address","name":"one","type":"address"},{"internalType":"address","name":"two","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"a","type":"uint256"}],"name":"redeemZcTokenReturns","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"u","type":"address"},{"internalType":"uint256","name":"m","type":"uint256"},{"internalType":"address","name":"f","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"transferVaultNotionalFee","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"transferVaultNotionalFeeCalled","outputs":[{"internalType":"uint256","name":"maturity","type":"uint256"},{"internalType":"address","name":"one","type":"address"},{"internalType":"address","name":"two","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"b","type":"bool"}],"name":"transferVaultNotionalFeeReturns","outputs":[],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file diff --git a/gost/test/mocks/MarketPlace.bin b/gost/test/mocks/MarketPlace.bin new file mode 100644 index 0000000..b57bfb1 --- /dev/null +++ b/gost/test/mocks/MarketPlace.bin @@ -0,0 +1 @@ +608060405234801561001057600080fd5b50611d2b806100206000396000f3fe608060405234801561001057600080fd5b50600436106101da5760003560e01c80637d04cd1511610104578063c4c25726116100a2578063ddcfbbda11610071578063ddcfbbda1461060c578063eee6e8141461063f578063ef267f2c14610672578063f8e51bcb146106a2576101da565b8063c4c2572614610571578063c5ee114d146105a4578063d557ee85146105d4578063dc098af9146105f0576101da565b8063a11f4856116100de578063a11f4856146104c5578063b50a66f7146104f5578063bddbfbe414610525578063beaff41e14610555576101da565b80637d04cd151461044657806389de80aa146104625780638c6b9b4114610495576101da565b806333fe997a1161017c5780634521d3031161014b5780634521d303146103ab5780634bc81e09146103de57806365a963aa146103fa5780636ac910331461042a576101da565b806333fe997a146102e55780633cf9a4e3146103185780633f25be9d146103485780633f73df2c1461037b576101da565b80631cd7aed3116101b85780631cd7aed31461025e5780631cd9be91146102915780632634de19146102ad578063295b25f2146102c9576101da565b806303f5e400146101df57806304aa1dfd1461021257806305e1dc251461022e575b600080fd5b6101f960048036038101906101f491906119c5565b6106d2565b6040516102099493929190611c23565b60405180910390f35b61022c60048036038101906102279190611b53565b610742565b005b610248600480360381019061024391906119ee565b61075f565b6040516102559190611bd2565b60405180910390f35b610278600480360381019061027391906119c5565b6107cf565b6040516102889493929190611c23565b60405180910390f35b6102ab60048036038101906102a69190611b53565b61083f565b005b6102c760048036038101906102c29190611b53565b61085c565b005b6102e360048036038101906102de9190611b7c565b610879565b005b6102ff60048036038101906102fa91906119c5565b610883565b60405161030f9493929190611c23565b60405180910390f35b610332600480360381019061032d9190611af0565b6108f3565b60405161033f9190611bed565b60405180910390f35b610362600480360381019061035d91906119c5565b610a49565b6040516103729493929190611c23565b60405180910390f35b610395600480360381019061039091906119c5565b610ab9565b6040516103a29190611c08565b60405180910390f35b6103c560048036038101906103c091906119c5565b610ad1565b6040516103d59493929190611c23565b60405180910390f35b6103f860048036038101906103f39190611b53565b610b41565b005b610414600480360381019061040f9190611a79565b610b5e565b6040516104219190611bed565b60405180910390f35b610444600480360381019061043f9190611b7c565b610ced565b005b610460600480360381019061045b9190611b53565b610cf7565b005b61047c600480360381019061047791906119c5565b610d14565b60405161048c9493929190611c23565b60405180910390f35b6104af60048036038101906104aa9190611a79565b610d84565b6040516104bc9190611bed565b60405180910390f35b6104df60048036038101906104da9190611a2a565b610f13565b6040516104ec9190611c08565b60405180910390f35b61050f600480360381019061050a9190611af0565b611051565b60405161051c9190611bed565b60405180910390f35b61053f600480360381019061053a9190611a79565b6111a7565b60405161054c9190611bed565b60405180910390f35b61056f600480360381019061056a9190611b53565b611336565b005b61058b600480360381019061058691906119c5565b611353565b60405161059b9493929190611c23565b60405180910390f35b6105be60048036038101906105b99190611af0565b6113c3565b6040516105cb9190611c08565b60405180910390f35b6105ee60048036038101906105e991906119c5565b61150c565b005b61060a60048036038101906106059190611b53565b611550565b005b610626600480360381019061062191906119c5565b61156d565b6040516106369493929190611c23565b60405180910390f35b610659600480360381019061065491906119c5565b6115dd565b6040516106699493929190611c23565b60405180910390f35b61068c60048036038101906106879190611af0565b61164d565b6040516106999190611bed565b60405180910390f35b6106bc60048036038101906106b79190611a79565b6117a3565b6040516106c99190611bed565b60405180910390f35b60066020528060005260406000206000915090508060000154908060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060030154905084565b80600a601a6101000a81548160ff02191690831515021790555050565b6000816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550600a60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905092915050565b60096020528060005260406000206000915090508060000154908060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060030154905084565b80600a60156101000a81548160ff02191690831515021790555050565b80600a60146101000a81548160ff02191690831515021790555050565b80600c8190555050565b60076020528060005260406000206000915090508060000154908060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060030154905084565b60006108fd611932565b8481600001818152505083816020019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508281606001818152505080600760008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000820151816000015560208201518160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060608201518160030155905050600a601a9054906101000a900460ff16915050949350505050565b60016020528060005260406000206000915090508060000154908060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060030154905084565b60006020528060005260406000206000915090505481565b60026020528060005260406000206000915090508060000154908060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060030154905084565b80600a60186101000a81548160ff02191690831515021790555050565b6000610b68611932565b8581600001818152505084816020019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505083816040019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508281606001818152505080600360008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000820151816000015560208201518160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060608201518160030155905050600a60169054906101000a900460ff1691505095945050505050565b80600b8190555050565b80600a60176101000a81548160ff02191690831515021790555050565b60056020528060005260406000206000915090508060000154908060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060030154905084565b6000610d8e611932565b8581600001818152505084816020019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505083816040019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508281606001818152505080600260008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000820151816000015560208201518160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060608201518160030155905050600a60159054906101000a900460ff1691505095945050505050565b6000610f1d611932565b8381600001818152505082816020019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505080600960008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000820151816000015560208201518160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060608201518160030155905050600c549150509392505050565b600061105b611932565b8481600001818152505083816020019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508281606001818152505080600660008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000820151816000015560208201518160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060608201518160030155905050600a60199054906101000a900460ff16915050949350505050565b60006111b1611932565b8581600001818152505084816020019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505083816040019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508281606001818152505080600460008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000820151816000015560208201518160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060608201518160030155905050600a60179054906101000a900460ff1691505095945050505050565b80600a60166101000a81548160ff02191690831515021790555050565b60036020528060005260406000206000915090508060000154908060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060030154905084565b60006113cd611932565b8481600001818152505083816020019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508281606001818152505080600860008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000820151816000015560208201518160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060608201518160030155905050600b54915050949350505050565b80600a60006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b80600a60196101000a81548160ff02191690831515021790555050565b60086020528060005260406000206000915090508060000154908060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060030154905084565b60046020528060005260406000206000915090508060000154908060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060030154905084565b6000611657611932565b8481600001818152505083816020019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508281606001818152505080600560008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000820151816000015560208201518160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060608201518160030155905050600a60189054906101000a900460ff16915050949350505050565b60006117ad611932565b8581600001818152505084816020019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505083816040019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508281606001818152505080600160008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000820151816000015560208201518160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060608201518160030155905050600a60149054906101000a900460ff1691505095945050505050565b604051806080016040528060008152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600081525090565b60008135905061199581611cb0565b92915050565b6000813590506119aa81611cc7565b92915050565b6000813590506119bf81611cde565b92915050565b6000602082840312156119d757600080fd5b60006119e584828501611986565b91505092915050565b60008060408385031215611a0157600080fd5b6000611a0f85828601611986565b9250506020611a20858286016119b0565b9150509250929050565b600080600060608486031215611a3f57600080fd5b6000611a4d86828701611986565b9350506020611a5e868287016119b0565b9250506040611a6f86828701611986565b9150509250925092565b600080600080600060a08688031215611a9157600080fd5b6000611a9f88828901611986565b9550506020611ab0888289016119b0565b9450506040611ac188828901611986565b9350506060611ad288828901611986565b9250506080611ae3888289016119b0565b9150509295509295909350565b60008060008060808587031215611b0657600080fd5b6000611b1487828801611986565b9450506020611b25878288016119b0565b9350506040611b3687828801611986565b9250506060611b47878288016119b0565b91505092959194509250565b600060208284031215611b6557600080fd5b6000611b738482850161199b565b91505092915050565b600060208284031215611b8e57600080fd5b6000611b9c848285016119b0565b91505092915050565b611bae81611c68565b82525050565b611bbd81611c7a565b82525050565b611bcc81611ca6565b82525050565b6000602082019050611be76000830184611ba5565b92915050565b6000602082019050611c026000830184611bb4565b92915050565b6000602082019050611c1d6000830184611bc3565b92915050565b6000608082019050611c386000830187611bc3565b611c456020830186611ba5565b611c526040830185611ba5565b611c5f6060830184611bc3565b95945050505050565b6000611c7382611c86565b9050919050565b60008115159050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b611cb981611c68565b8114611cc457600080fd5b50565b611cd081611c7a565b8114611cdb57600080fd5b50565b611ce781611ca6565b8114611cf257600080fd5b5056fea264697066735822122032a3e970c3b9ef18601f746540da687b1bafb565338274208ceefc96c681682564736f6c63430008040033 \ No newline at end of file diff --git a/gost/test/mocks/MarketPlace.sol b/gost/test/mocks/MarketPlace.sol new file mode 100644 index 0000000..fd36176 --- /dev/null +++ b/gost/test/mocks/MarketPlace.sol @@ -0,0 +1,183 @@ +// SPDX-License-Identifier: UNLICENSED + +pragma solidity 0.8.4; + +/// @dev MarketPlace is a mock whose bindings are imported by unit tests in any pkg/*testing that needs it +contract MarketPlace { + struct MethodArgs { + uint256 maturity; + address one; // is sender or maker depending on method + address two; // same as above + uint256 amount; + } + + mapping (address => uint256) public cTokenAddressCalled; + mapping (address => MethodArgs) public custodialInitiateCalled; + mapping (address => MethodArgs) public custodialExitCalled; + mapping (address => MethodArgs) public p2pZcTokenExchangeCalled; + mapping (address => MethodArgs) public p2pVaultExchangeCalled; + mapping (address => MethodArgs) public mintZcTokenAddingNotionalCalled; + mapping (address => MethodArgs) public burnZcTokenRemovingNotionalCalled; + mapping (address => MethodArgs) public transferVaultNotionalFeeCalled; + mapping (address => MethodArgs) public redeemZcTokenCalled; + mapping (address => MethodArgs) public redeemVaultInterestCalled; + + address private cTokenAddr; + bool private custodialInitiateReturn; + bool private custodialExitReturn; + bool private p2pZcTokenExchangeReturn; + bool private p2pVaultExchangeReturn; + bool private mintZcTokenAddingNotionalReturn; + bool private burnZcTokenRemovingNotionalReturn; + bool private transferVaultNotionalFeeReturn; + uint256 private redeemZcTokenReturn; + uint256 private redeemVaultInterestReturn; + + function cTokenAddressReturns(address a) external { + cTokenAddr = a; + } + + function cTokenAddress(address u, uint256 m) external returns (address) { + cTokenAddressCalled[u] = m; + return cTokenAddr; + } + + function custodialInitiateReturns(bool b) external { + custodialInitiateReturn = b; + } + + // called by swivel IVFZI && IZFVI + // call with underlying, maturity, mint-target, add-notional-target and an amount + function custodialInitiate(address u, uint256 m, address o, address t, uint256 a) external returns (bool) { + MethodArgs memory args; + args.maturity = m; + args.one = o; // will be the recipient of minted zctoken + args.two = t; // will be the recipient of added notional + args.amount = a; // the amount of minted zctoken and notional added + custodialInitiateCalled[u] = args; + + return custodialInitiateReturn; + } + + function custodialExitReturns(bool b) external { + custodialExitReturn = b; + } + + // called by swivel EVFZE FF EZFVE + // call with underlying, maturity, burn-target, remove-notional-target and an amount + function custodialExit(address u, uint256 m, address o, address t, uint256 a) external returns (bool) { + MethodArgs memory args; + args.maturity = m; + args.one = o; // will be the burn-from target + args.two = t; // will be the remove-notional target + args.amount = a; // zctoken burned, notional removed + custodialExitCalled[u] = args; + + return custodialExitReturn; + } + + function p2pZcTokenExchangeReturns(bool b) external { + p2pZcTokenExchangeReturn = b; + } + + // called by swivel IZFZE, EZFZI + // call with underlying, maturity, transfer-from, transfer-to, amount + function p2pZcTokenExchange(address u, uint256 m, address o, address t, uint256 a) external returns (bool) { + MethodArgs memory args; + args.maturity = m; + args.one = o; + args.two = t; + args.amount = a; + p2pZcTokenExchangeCalled[u] = args; + + return p2pZcTokenExchangeReturn; + } + + function p2pVaultExchangeReturns(bool b) external { + p2pVaultExchangeReturn = b; + } + + // called by swivel IVFVE, EVFVI + // call with underlying, maturity, remove-from, add-to, amount + function p2pVaultExchange(address u, uint256 m, address o, address t, uint256 a) external returns (bool) { + MethodArgs memory args; + args.maturity = m; + args.one = o; + args.two = t; + args.amount = a; + p2pVaultExchangeCalled[u] = args; + + return p2pVaultExchangeReturn; + } + + function mintZcTokenAddingNotionalReturns(bool b) external { + mintZcTokenAddingNotionalReturn = b; + } + + // call with underlying, maturity, mint-to, amount + function mintZcTokenAddingNotional(address u, uint256 m, address t, uint256 a) external returns (bool) { + MethodArgs memory args; + args.maturity = m; + args.one = t; + args.amount = a; + mintZcTokenAddingNotionalCalled[u] = args; + + return mintZcTokenAddingNotionalReturn; + } + + function burnZcTokenRemovingNotionalReturns(bool b) external { + burnZcTokenRemovingNotionalReturn = b; + } + + // call with underlying, maturity, mint-to, amount + function burnZcTokenRemovingNotional(address u, uint256 m, address t, uint256 a) external returns (bool) { + MethodArgs memory args; + args.maturity = m; + args.one = t; + args.amount = a; + burnZcTokenRemovingNotionalCalled[u] = args; + + return burnZcTokenRemovingNotionalReturn; + } + + function transferVaultNotionalFeeReturns(bool b) external { + transferVaultNotionalFeeReturn = b; + } + + function transferVaultNotionalFee(address u, uint256 m, address f, uint256 a) external returns (bool) { + MethodArgs memory args; + args.maturity = m; + args.one = f; + args.amount = a; + transferVaultNotionalFeeCalled[u] = args; + + return transferVaultNotionalFeeReturn; + } + + function redeemZcTokenReturns(uint256 a) external { + redeemZcTokenReturn = a; + } + + function redeemZcToken(address u, uint256 m, address t, uint256 a) external returns (uint256) { + MethodArgs memory args; + args.maturity = m; + args.one = t; + args.amount = a; + redeemZcTokenCalled[u] = args; + + return redeemZcTokenReturn; + } + + function redeemVaultInterestReturns(uint256 a) external { + redeemVaultInterestReturn = a; + } + + function redeemVaultInterest(address u, uint256 m, address t) external returns (uint256) { + MethodArgs memory args; + args.maturity = m; + args.one = t; + redeemVaultInterestCalled[u] = args; + + return redeemVaultInterestReturn; + } +} diff --git a/gost/test/mocks/cerc20.go b/gost/test/mocks/cerc20.go new file mode 100644 index 0000000..d6c2ad9 --- /dev/null +++ b/gost/test/mocks/cerc20.go @@ -0,0 +1,460 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package mocks + +import ( + "math/big" + "strings" + + ethereum "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/event" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription +) + +// CErc20ABI is the input ABI used to generate the binding from. +const CErc20ABI = "[{\"inputs\":[],\"name\":\"exchangeRateCurrent\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"n\",\"type\":\"uint256\"}],\"name\":\"exchangeRateCurrentReturns\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"n\",\"type\":\"uint256\"}],\"name\":\"mint\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"mintCalled\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"n\",\"type\":\"uint256\"}],\"name\":\"mintReturns\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"n\",\"type\":\"uint256\"}],\"name\":\"redeem\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"redeemCalled\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"n\",\"type\":\"uint256\"}],\"name\":\"redeemReturns\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"n\",\"type\":\"uint256\"}],\"name\":\"redeemUnderlying\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"redeemUnderlyingCalled\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"n\",\"type\":\"uint256\"}],\"name\":\"redeemUnderlyingReturns\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]" + +// CErc20Bin is the compiled bytecode used for deploying new contracts. +var CErc20Bin = "0x608060405234801561001057600080fd5b50610362806100206000396000f3fe608060405234801561001057600080fd5b50600436106100a95760003560e01c8063be6babbf11610071578063be6babbf14610164578063d4e7fdd414610182578063d6bcd7aa146101a0578063db006a75146101be578063de9d2a72146101ee578063e7a7b9ce1461020a576100a9565b806329d9ce3e146100ae578063852a12e3146100ca5780639ff9f1d4146100fa578063a0712d6814610116578063bd6d894d14610146575b600080fd5b6100c860048036038101906100c391906102b8565b610226565b005b6100e460048036038101906100df91906102b8565b610230565b6040516100f191906102f0565b60405180910390f35b610114600480360381019061010f91906102b8565b610243565b005b610130600480360381019061012b91906102b8565b61024d565b60405161013d91906102f0565b60405180910390f35b61014e610260565b60405161015b91906102f0565b60405180910390f35b61016c61026a565b60405161017991906102f0565b60405180910390f35b61018a610270565b60405161019791906102f0565b60405180910390f35b6101a8610276565b6040516101b591906102f0565b60405180910390f35b6101d860048036038101906101d391906102b8565b61027c565b6040516101e591906102f0565b60405180910390f35b610208600480360381019061020391906102b8565b61028f565b005b610224600480360381019061021f91906102b8565b610299565b005b8060048190555050565b6000816005819055506004549050919050565b8060068190555050565b6000816001819055506000549050919050565b6000600654905090565b60035481565b60015481565b60055481565b6000816003819055506002549050919050565b8060028190555050565b8060008190555050565b6000813590506102b281610315565b92915050565b6000602082840312156102ca57600080fd5b60006102d8848285016102a3565b91505092915050565b6102ea8161030b565b82525050565b600060208201905061030560008301846102e1565b92915050565b6000819050919050565b61031e8161030b565b811461032957600080fd5b5056fea2646970667358221220ddfaaf48e10553118ec44cd18879e4407f44441670b2f4daa8e5cfc9340a70d464736f6c63430008040033" + +// DeployCErc20 deploys a new Ethereum contract, binding an instance of CErc20 to it. +func DeployCErc20(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *CErc20, error) { + parsed, err := abi.JSON(strings.NewReader(CErc20ABI)) + if err != nil { + return common.Address{}, nil, nil, err + } + + address, tx, contract, err := bind.DeployContract(auth, parsed, common.FromHex(CErc20Bin), backend) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &CErc20{CErc20Caller: CErc20Caller{contract: contract}, CErc20Transactor: CErc20Transactor{contract: contract}, CErc20Filterer: CErc20Filterer{contract: contract}}, nil +} + +// CErc20 is an auto generated Go binding around an Ethereum contract. +type CErc20 struct { + CErc20Caller // Read-only binding to the contract + CErc20Transactor // Write-only binding to the contract + CErc20Filterer // Log filterer for contract events +} + +// CErc20Caller is an auto generated read-only Go binding around an Ethereum contract. +type CErc20Caller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// CErc20Transactor is an auto generated write-only Go binding around an Ethereum contract. +type CErc20Transactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// CErc20Filterer is an auto generated log filtering Go binding around an Ethereum contract events. +type CErc20Filterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// CErc20Session is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type CErc20Session struct { + Contract *CErc20 // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// CErc20CallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type CErc20CallerSession struct { + Contract *CErc20Caller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// CErc20TransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type CErc20TransactorSession struct { + Contract *CErc20Transactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// CErc20Raw is an auto generated low-level Go binding around an Ethereum contract. +type CErc20Raw struct { + Contract *CErc20 // Generic contract binding to access the raw methods on +} + +// CErc20CallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type CErc20CallerRaw struct { + Contract *CErc20Caller // Generic read-only contract binding to access the raw methods on +} + +// CErc20TransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type CErc20TransactorRaw struct { + Contract *CErc20Transactor // Generic write-only contract binding to access the raw methods on +} + +// NewCErc20 creates a new instance of CErc20, bound to a specific deployed contract. +func NewCErc20(address common.Address, backend bind.ContractBackend) (*CErc20, error) { + contract, err := bindCErc20(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &CErc20{CErc20Caller: CErc20Caller{contract: contract}, CErc20Transactor: CErc20Transactor{contract: contract}, CErc20Filterer: CErc20Filterer{contract: contract}}, nil +} + +// NewCErc20Caller creates a new read-only instance of CErc20, bound to a specific deployed contract. +func NewCErc20Caller(address common.Address, caller bind.ContractCaller) (*CErc20Caller, error) { + contract, err := bindCErc20(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &CErc20Caller{contract: contract}, nil +} + +// NewCErc20Transactor creates a new write-only instance of CErc20, bound to a specific deployed contract. +func NewCErc20Transactor(address common.Address, transactor bind.ContractTransactor) (*CErc20Transactor, error) { + contract, err := bindCErc20(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &CErc20Transactor{contract: contract}, nil +} + +// NewCErc20Filterer creates a new log filterer instance of CErc20, bound to a specific deployed contract. +func NewCErc20Filterer(address common.Address, filterer bind.ContractFilterer) (*CErc20Filterer, error) { + contract, err := bindCErc20(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &CErc20Filterer{contract: contract}, nil +} + +// bindCErc20 binds a generic wrapper to an already deployed contract. +func bindCErc20(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := abi.JSON(strings.NewReader(CErc20ABI)) + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_CErc20 *CErc20Raw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _CErc20.Contract.CErc20Caller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_CErc20 *CErc20Raw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _CErc20.Contract.CErc20Transactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_CErc20 *CErc20Raw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _CErc20.Contract.CErc20Transactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_CErc20 *CErc20CallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _CErc20.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_CErc20 *CErc20TransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _CErc20.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_CErc20 *CErc20TransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _CErc20.Contract.contract.Transact(opts, method, params...) +} + +// ExchangeRateCurrent is a free data retrieval call binding the contract method 0xbd6d894d. +// +// Solidity: function exchangeRateCurrent() view returns(uint256) +func (_CErc20 *CErc20Caller) ExchangeRateCurrent(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _CErc20.contract.Call(opts, &out, "exchangeRateCurrent") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// ExchangeRateCurrent is a free data retrieval call binding the contract method 0xbd6d894d. +// +// Solidity: function exchangeRateCurrent() view returns(uint256) +func (_CErc20 *CErc20Session) ExchangeRateCurrent() (*big.Int, error) { + return _CErc20.Contract.ExchangeRateCurrent(&_CErc20.CallOpts) +} + +// ExchangeRateCurrent is a free data retrieval call binding the contract method 0xbd6d894d. +// +// Solidity: function exchangeRateCurrent() view returns(uint256) +func (_CErc20 *CErc20CallerSession) ExchangeRateCurrent() (*big.Int, error) { + return _CErc20.Contract.ExchangeRateCurrent(&_CErc20.CallOpts) +} + +// MintCalled is a free data retrieval call binding the contract method 0xd4e7fdd4. +// +// Solidity: function mintCalled() view returns(uint256) +func (_CErc20 *CErc20Caller) MintCalled(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _CErc20.contract.Call(opts, &out, "mintCalled") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// MintCalled is a free data retrieval call binding the contract method 0xd4e7fdd4. +// +// Solidity: function mintCalled() view returns(uint256) +func (_CErc20 *CErc20Session) MintCalled() (*big.Int, error) { + return _CErc20.Contract.MintCalled(&_CErc20.CallOpts) +} + +// MintCalled is a free data retrieval call binding the contract method 0xd4e7fdd4. +// +// Solidity: function mintCalled() view returns(uint256) +func (_CErc20 *CErc20CallerSession) MintCalled() (*big.Int, error) { + return _CErc20.Contract.MintCalled(&_CErc20.CallOpts) +} + +// RedeemCalled is a free data retrieval call binding the contract method 0xbe6babbf. +// +// Solidity: function redeemCalled() view returns(uint256) +func (_CErc20 *CErc20Caller) RedeemCalled(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _CErc20.contract.Call(opts, &out, "redeemCalled") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// RedeemCalled is a free data retrieval call binding the contract method 0xbe6babbf. +// +// Solidity: function redeemCalled() view returns(uint256) +func (_CErc20 *CErc20Session) RedeemCalled() (*big.Int, error) { + return _CErc20.Contract.RedeemCalled(&_CErc20.CallOpts) +} + +// RedeemCalled is a free data retrieval call binding the contract method 0xbe6babbf. +// +// Solidity: function redeemCalled() view returns(uint256) +func (_CErc20 *CErc20CallerSession) RedeemCalled() (*big.Int, error) { + return _CErc20.Contract.RedeemCalled(&_CErc20.CallOpts) +} + +// RedeemUnderlyingCalled is a free data retrieval call binding the contract method 0xd6bcd7aa. +// +// Solidity: function redeemUnderlyingCalled() view returns(uint256) +func (_CErc20 *CErc20Caller) RedeemUnderlyingCalled(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _CErc20.contract.Call(opts, &out, "redeemUnderlyingCalled") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// RedeemUnderlyingCalled is a free data retrieval call binding the contract method 0xd6bcd7aa. +// +// Solidity: function redeemUnderlyingCalled() view returns(uint256) +func (_CErc20 *CErc20Session) RedeemUnderlyingCalled() (*big.Int, error) { + return _CErc20.Contract.RedeemUnderlyingCalled(&_CErc20.CallOpts) +} + +// RedeemUnderlyingCalled is a free data retrieval call binding the contract method 0xd6bcd7aa. +// +// Solidity: function redeemUnderlyingCalled() view returns(uint256) +func (_CErc20 *CErc20CallerSession) RedeemUnderlyingCalled() (*big.Int, error) { + return _CErc20.Contract.RedeemUnderlyingCalled(&_CErc20.CallOpts) +} + +// ExchangeRateCurrentReturns is a paid mutator transaction binding the contract method 0x9ff9f1d4. +// +// Solidity: function exchangeRateCurrentReturns(uint256 n) returns() +func (_CErc20 *CErc20Transactor) ExchangeRateCurrentReturns(opts *bind.TransactOpts, n *big.Int) (*types.Transaction, error) { + return _CErc20.contract.Transact(opts, "exchangeRateCurrentReturns", n) +} + +// ExchangeRateCurrentReturns is a paid mutator transaction binding the contract method 0x9ff9f1d4. +// +// Solidity: function exchangeRateCurrentReturns(uint256 n) returns() +func (_CErc20 *CErc20Session) ExchangeRateCurrentReturns(n *big.Int) (*types.Transaction, error) { + return _CErc20.Contract.ExchangeRateCurrentReturns(&_CErc20.TransactOpts, n) +} + +// ExchangeRateCurrentReturns is a paid mutator transaction binding the contract method 0x9ff9f1d4. +// +// Solidity: function exchangeRateCurrentReturns(uint256 n) returns() +func (_CErc20 *CErc20TransactorSession) ExchangeRateCurrentReturns(n *big.Int) (*types.Transaction, error) { + return _CErc20.Contract.ExchangeRateCurrentReturns(&_CErc20.TransactOpts, n) +} + +// Mint is a paid mutator transaction binding the contract method 0xa0712d68. +// +// Solidity: function mint(uint256 n) returns(uint256) +func (_CErc20 *CErc20Transactor) Mint(opts *bind.TransactOpts, n *big.Int) (*types.Transaction, error) { + return _CErc20.contract.Transact(opts, "mint", n) +} + +// Mint is a paid mutator transaction binding the contract method 0xa0712d68. +// +// Solidity: function mint(uint256 n) returns(uint256) +func (_CErc20 *CErc20Session) Mint(n *big.Int) (*types.Transaction, error) { + return _CErc20.Contract.Mint(&_CErc20.TransactOpts, n) +} + +// Mint is a paid mutator transaction binding the contract method 0xa0712d68. +// +// Solidity: function mint(uint256 n) returns(uint256) +func (_CErc20 *CErc20TransactorSession) Mint(n *big.Int) (*types.Transaction, error) { + return _CErc20.Contract.Mint(&_CErc20.TransactOpts, n) +} + +// MintReturns is a paid mutator transaction binding the contract method 0xe7a7b9ce. +// +// Solidity: function mintReturns(uint256 n) returns() +func (_CErc20 *CErc20Transactor) MintReturns(opts *bind.TransactOpts, n *big.Int) (*types.Transaction, error) { + return _CErc20.contract.Transact(opts, "mintReturns", n) +} + +// MintReturns is a paid mutator transaction binding the contract method 0xe7a7b9ce. +// +// Solidity: function mintReturns(uint256 n) returns() +func (_CErc20 *CErc20Session) MintReturns(n *big.Int) (*types.Transaction, error) { + return _CErc20.Contract.MintReturns(&_CErc20.TransactOpts, n) +} + +// MintReturns is a paid mutator transaction binding the contract method 0xe7a7b9ce. +// +// Solidity: function mintReturns(uint256 n) returns() +func (_CErc20 *CErc20TransactorSession) MintReturns(n *big.Int) (*types.Transaction, error) { + return _CErc20.Contract.MintReturns(&_CErc20.TransactOpts, n) +} + +// Redeem is a paid mutator transaction binding the contract method 0xdb006a75. +// +// Solidity: function redeem(uint256 n) returns(uint256) +func (_CErc20 *CErc20Transactor) Redeem(opts *bind.TransactOpts, n *big.Int) (*types.Transaction, error) { + return _CErc20.contract.Transact(opts, "redeem", n) +} + +// Redeem is a paid mutator transaction binding the contract method 0xdb006a75. +// +// Solidity: function redeem(uint256 n) returns(uint256) +func (_CErc20 *CErc20Session) Redeem(n *big.Int) (*types.Transaction, error) { + return _CErc20.Contract.Redeem(&_CErc20.TransactOpts, n) +} + +// Redeem is a paid mutator transaction binding the contract method 0xdb006a75. +// +// Solidity: function redeem(uint256 n) returns(uint256) +func (_CErc20 *CErc20TransactorSession) Redeem(n *big.Int) (*types.Transaction, error) { + return _CErc20.Contract.Redeem(&_CErc20.TransactOpts, n) +} + +// RedeemReturns is a paid mutator transaction binding the contract method 0xde9d2a72. +// +// Solidity: function redeemReturns(uint256 n) returns() +func (_CErc20 *CErc20Transactor) RedeemReturns(opts *bind.TransactOpts, n *big.Int) (*types.Transaction, error) { + return _CErc20.contract.Transact(opts, "redeemReturns", n) +} + +// RedeemReturns is a paid mutator transaction binding the contract method 0xde9d2a72. +// +// Solidity: function redeemReturns(uint256 n) returns() +func (_CErc20 *CErc20Session) RedeemReturns(n *big.Int) (*types.Transaction, error) { + return _CErc20.Contract.RedeemReturns(&_CErc20.TransactOpts, n) +} + +// RedeemReturns is a paid mutator transaction binding the contract method 0xde9d2a72. +// +// Solidity: function redeemReturns(uint256 n) returns() +func (_CErc20 *CErc20TransactorSession) RedeemReturns(n *big.Int) (*types.Transaction, error) { + return _CErc20.Contract.RedeemReturns(&_CErc20.TransactOpts, n) +} + +// RedeemUnderlying is a paid mutator transaction binding the contract method 0x852a12e3. +// +// Solidity: function redeemUnderlying(uint256 n) returns(uint256) +func (_CErc20 *CErc20Transactor) RedeemUnderlying(opts *bind.TransactOpts, n *big.Int) (*types.Transaction, error) { + return _CErc20.contract.Transact(opts, "redeemUnderlying", n) +} + +// RedeemUnderlying is a paid mutator transaction binding the contract method 0x852a12e3. +// +// Solidity: function redeemUnderlying(uint256 n) returns(uint256) +func (_CErc20 *CErc20Session) RedeemUnderlying(n *big.Int) (*types.Transaction, error) { + return _CErc20.Contract.RedeemUnderlying(&_CErc20.TransactOpts, n) +} + +// RedeemUnderlying is a paid mutator transaction binding the contract method 0x852a12e3. +// +// Solidity: function redeemUnderlying(uint256 n) returns(uint256) +func (_CErc20 *CErc20TransactorSession) RedeemUnderlying(n *big.Int) (*types.Transaction, error) { + return _CErc20.Contract.RedeemUnderlying(&_CErc20.TransactOpts, n) +} + +// RedeemUnderlyingReturns is a paid mutator transaction binding the contract method 0x29d9ce3e. +// +// Solidity: function redeemUnderlyingReturns(uint256 n) returns() +func (_CErc20 *CErc20Transactor) RedeemUnderlyingReturns(opts *bind.TransactOpts, n *big.Int) (*types.Transaction, error) { + return _CErc20.contract.Transact(opts, "redeemUnderlyingReturns", n) +} + +// RedeemUnderlyingReturns is a paid mutator transaction binding the contract method 0x29d9ce3e. +// +// Solidity: function redeemUnderlyingReturns(uint256 n) returns() +func (_CErc20 *CErc20Session) RedeemUnderlyingReturns(n *big.Int) (*types.Transaction, error) { + return _CErc20.Contract.RedeemUnderlyingReturns(&_CErc20.TransactOpts, n) +} + +// RedeemUnderlyingReturns is a paid mutator transaction binding the contract method 0x29d9ce3e. +// +// Solidity: function redeemUnderlyingReturns(uint256 n) returns() +func (_CErc20 *CErc20TransactorSession) RedeemUnderlyingReturns(n *big.Int) (*types.Transaction, error) { + return _CErc20.Contract.RedeemUnderlyingReturns(&_CErc20.TransactOpts, n) +} diff --git a/gost/test/mocks/erc20.go b/gost/test/mocks/erc20.go new file mode 100644 index 0000000..65f4d59 --- /dev/null +++ b/gost/test/mocks/erc20.go @@ -0,0 +1,495 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package mocks + +import ( + "math/big" + "strings" + + ethereum "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/event" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription +) + +// Erc20ABI is the input ABI used to generate the binding from. +const Erc20ABI = "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"s\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"a\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"approveCalled\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"b\",\"type\":\"bool\"}],\"name\":\"approveReturns\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"t\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"balanceOfCalled\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"b\",\"type\":\"uint256\"}],\"name\":\"balanceOfReturns\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"t\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"a\",\"type\":\"uint256\"}],\"name\":\"transfer\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"transferCalled\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"f\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"t\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"a\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"transferFromCalled\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"b\",\"type\":\"bool\"}],\"name\":\"transferFromReturns\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"b\",\"type\":\"bool\"}],\"name\":\"transferReturns\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]" + +// Erc20Bin is the compiled bytecode used for deploying new contracts. +var Erc20Bin = "0x608060405234801561001057600080fd5b50610874806100206000396000f3fe608060405234801561001057600080fd5b50600436106100b45760003560e01c806370a082311161007157806370a082311461019d5780639dd0ff37146101cd578063a9059cbb146101e9578063c1d2e9a114610219578063dea1a7e214610249578063e541efa214610267576100b4565b8063095ea7b3146100b957806323b872dd146100e9578063391008381461011957806342b6cdbc146101355780636521b96a146101515780636581d5431461016d575b600080fd5b6100d360048036038101906100ce919061067c565b610298565b6040516100e0919061077b565b60405180910390f35b61010360048036038101906100fe919061062d565b6102f5565b604051610110919061077b565b60405180910390f35b610133600480360381019061012e91906106e1565b6103ef565b005b61014f600480360381019061014a91906106b8565b6103f9565b005b61016b600480360381019061016691906106b8565b610416565b005b61018760048036038101906101829190610604565b610433565b6040516101949190610796565b60405180910390f35b6101b760048036038101906101b29190610604565b61044b565b6040516101c49190610796565b60405180910390f35b6101e760048036038101906101e291906106b8565b610498565b005b61020360048036038101906101fe919061067c565b6104b5565b604051610210919061077b565b60405180910390f35b610233600480360381019061022e9190610604565b610513565b6040516102409190610796565b60405180910390f35b61025161052b565b60405161025e9190610737565b60405180910390f35b610281600480360381019061027c9190610604565b610551565b60405161028f929190610752565b60405180910390f35b6000816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550600360149054906101000a900460ff16905092915050565b60006102ff610595565b83816000019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508281602001818152505080600260008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008201518160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060208201518160010155905050600560019054906101000a900460ff169150509392505050565b8060048190555050565b80600560006101000a81548160ff02191690831515021790555050565b80600560016101000a81548160ff02191690831515021790555050565b60006020528060005260406000206000915090505481565b600081600360006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506004549050919050565b80600360146101000a81548160ff02191690831515021790555050565b600081600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550600560009054906101000a900460ff16905092915050565b60016020528060005260406000206000915090505481565b600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60026020528060005260406000206000915090508060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060010154905082565b6040518060400160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600081525090565b6000813590506105d4816107f9565b92915050565b6000813590506105e981610810565b92915050565b6000813590506105fe81610827565b92915050565b60006020828403121561061657600080fd5b6000610624848285016105c5565b91505092915050565b60008060006060848603121561064257600080fd5b6000610650868287016105c5565b9350506020610661868287016105c5565b9250506040610672868287016105ef565b9150509250925092565b6000806040838503121561068f57600080fd5b600061069d858286016105c5565b92505060206106ae858286016105ef565b9150509250929050565b6000602082840312156106ca57600080fd5b60006106d8848285016105da565b91505092915050565b6000602082840312156106f357600080fd5b6000610701848285016105ef565b91505092915050565b610713816107b1565b82525050565b610722816107c3565b82525050565b610731816107ef565b82525050565b600060208201905061074c600083018461070a565b92915050565b6000604082019050610767600083018561070a565b6107746020830184610728565b9392505050565b60006020820190506107906000830184610719565b92915050565b60006020820190506107ab6000830184610728565b92915050565b60006107bc826107cf565b9050919050565b60008115159050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b610802816107b1565b811461080d57600080fd5b50565b610819816107c3565b811461082457600080fd5b50565b610830816107ef565b811461083b57600080fd5b5056fea26469706673582212205c49e2ec19f2e3bcd87bf0ebeb7efcc9ac2fda4f153bea6694de1f4912d35d6264736f6c63430008040033" + +// DeployErc20 deploys a new Ethereum contract, binding an instance of Erc20 to it. +func DeployErc20(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *Erc20, error) { + parsed, err := abi.JSON(strings.NewReader(Erc20ABI)) + if err != nil { + return common.Address{}, nil, nil, err + } + + address, tx, contract, err := bind.DeployContract(auth, parsed, common.FromHex(Erc20Bin), backend) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &Erc20{Erc20Caller: Erc20Caller{contract: contract}, Erc20Transactor: Erc20Transactor{contract: contract}, Erc20Filterer: Erc20Filterer{contract: contract}}, nil +} + +// Erc20 is an auto generated Go binding around an Ethereum contract. +type Erc20 struct { + Erc20Caller // Read-only binding to the contract + Erc20Transactor // Write-only binding to the contract + Erc20Filterer // Log filterer for contract events +} + +// Erc20Caller is an auto generated read-only Go binding around an Ethereum contract. +type Erc20Caller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// Erc20Transactor is an auto generated write-only Go binding around an Ethereum contract. +type Erc20Transactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// Erc20Filterer is an auto generated log filtering Go binding around an Ethereum contract events. +type Erc20Filterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// Erc20Session is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type Erc20Session struct { + Contract *Erc20 // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// Erc20CallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type Erc20CallerSession struct { + Contract *Erc20Caller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// Erc20TransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type Erc20TransactorSession struct { + Contract *Erc20Transactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// Erc20Raw is an auto generated low-level Go binding around an Ethereum contract. +type Erc20Raw struct { + Contract *Erc20 // Generic contract binding to access the raw methods on +} + +// Erc20CallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type Erc20CallerRaw struct { + Contract *Erc20Caller // Generic read-only contract binding to access the raw methods on +} + +// Erc20TransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type Erc20TransactorRaw struct { + Contract *Erc20Transactor // Generic write-only contract binding to access the raw methods on +} + +// NewErc20 creates a new instance of Erc20, bound to a specific deployed contract. +func NewErc20(address common.Address, backend bind.ContractBackend) (*Erc20, error) { + contract, err := bindErc20(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &Erc20{Erc20Caller: Erc20Caller{contract: contract}, Erc20Transactor: Erc20Transactor{contract: contract}, Erc20Filterer: Erc20Filterer{contract: contract}}, nil +} + +// NewErc20Caller creates a new read-only instance of Erc20, bound to a specific deployed contract. +func NewErc20Caller(address common.Address, caller bind.ContractCaller) (*Erc20Caller, error) { + contract, err := bindErc20(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &Erc20Caller{contract: contract}, nil +} + +// NewErc20Transactor creates a new write-only instance of Erc20, bound to a specific deployed contract. +func NewErc20Transactor(address common.Address, transactor bind.ContractTransactor) (*Erc20Transactor, error) { + contract, err := bindErc20(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &Erc20Transactor{contract: contract}, nil +} + +// NewErc20Filterer creates a new log filterer instance of Erc20, bound to a specific deployed contract. +func NewErc20Filterer(address common.Address, filterer bind.ContractFilterer) (*Erc20Filterer, error) { + contract, err := bindErc20(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &Erc20Filterer{contract: contract}, nil +} + +// bindErc20 binds a generic wrapper to an already deployed contract. +func bindErc20(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := abi.JSON(strings.NewReader(Erc20ABI)) + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_Erc20 *Erc20Raw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _Erc20.Contract.Erc20Caller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_Erc20 *Erc20Raw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Erc20.Contract.Erc20Transactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_Erc20 *Erc20Raw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _Erc20.Contract.Erc20Transactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_Erc20 *Erc20CallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _Erc20.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_Erc20 *Erc20TransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Erc20.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_Erc20 *Erc20TransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _Erc20.Contract.contract.Transact(opts, method, params...) +} + +// ApproveCalled is a free data retrieval call binding the contract method 0x6581d543. +// +// Solidity: function approveCalled(address ) view returns(uint256) +func (_Erc20 *Erc20Caller) ApproveCalled(opts *bind.CallOpts, arg0 common.Address) (*big.Int, error) { + var out []interface{} + err := _Erc20.contract.Call(opts, &out, "approveCalled", arg0) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// ApproveCalled is a free data retrieval call binding the contract method 0x6581d543. +// +// Solidity: function approveCalled(address ) view returns(uint256) +func (_Erc20 *Erc20Session) ApproveCalled(arg0 common.Address) (*big.Int, error) { + return _Erc20.Contract.ApproveCalled(&_Erc20.CallOpts, arg0) +} + +// ApproveCalled is a free data retrieval call binding the contract method 0x6581d543. +// +// Solidity: function approveCalled(address ) view returns(uint256) +func (_Erc20 *Erc20CallerSession) ApproveCalled(arg0 common.Address) (*big.Int, error) { + return _Erc20.Contract.ApproveCalled(&_Erc20.CallOpts, arg0) +} + +// BalanceOfCalled is a free data retrieval call binding the contract method 0xdea1a7e2. +// +// Solidity: function balanceOfCalled() view returns(address) +func (_Erc20 *Erc20Caller) BalanceOfCalled(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _Erc20.contract.Call(opts, &out, "balanceOfCalled") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// BalanceOfCalled is a free data retrieval call binding the contract method 0xdea1a7e2. +// +// Solidity: function balanceOfCalled() view returns(address) +func (_Erc20 *Erc20Session) BalanceOfCalled() (common.Address, error) { + return _Erc20.Contract.BalanceOfCalled(&_Erc20.CallOpts) +} + +// BalanceOfCalled is a free data retrieval call binding the contract method 0xdea1a7e2. +// +// Solidity: function balanceOfCalled() view returns(address) +func (_Erc20 *Erc20CallerSession) BalanceOfCalled() (common.Address, error) { + return _Erc20.Contract.BalanceOfCalled(&_Erc20.CallOpts) +} + +// TransferCalled is a free data retrieval call binding the contract method 0xc1d2e9a1. +// +// Solidity: function transferCalled(address ) view returns(uint256) +func (_Erc20 *Erc20Caller) TransferCalled(opts *bind.CallOpts, arg0 common.Address) (*big.Int, error) { + var out []interface{} + err := _Erc20.contract.Call(opts, &out, "transferCalled", arg0) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// TransferCalled is a free data retrieval call binding the contract method 0xc1d2e9a1. +// +// Solidity: function transferCalled(address ) view returns(uint256) +func (_Erc20 *Erc20Session) TransferCalled(arg0 common.Address) (*big.Int, error) { + return _Erc20.Contract.TransferCalled(&_Erc20.CallOpts, arg0) +} + +// TransferCalled is a free data retrieval call binding the contract method 0xc1d2e9a1. +// +// Solidity: function transferCalled(address ) view returns(uint256) +func (_Erc20 *Erc20CallerSession) TransferCalled(arg0 common.Address) (*big.Int, error) { + return _Erc20.Contract.TransferCalled(&_Erc20.CallOpts, arg0) +} + +// TransferFromCalled is a free data retrieval call binding the contract method 0xe541efa2. +// +// Solidity: function transferFromCalled(address ) view returns(address to, uint256 amount) +func (_Erc20 *Erc20Caller) TransferFromCalled(opts *bind.CallOpts, arg0 common.Address) (struct { + To common.Address + Amount *big.Int +}, error) { + var out []interface{} + err := _Erc20.contract.Call(opts, &out, "transferFromCalled", arg0) + + outstruct := new(struct { + To common.Address + Amount *big.Int + }) + if err != nil { + return *outstruct, err + } + + outstruct.To = out[0].(common.Address) + outstruct.Amount = out[1].(*big.Int) + + return *outstruct, err + +} + +// TransferFromCalled is a free data retrieval call binding the contract method 0xe541efa2. +// +// Solidity: function transferFromCalled(address ) view returns(address to, uint256 amount) +func (_Erc20 *Erc20Session) TransferFromCalled(arg0 common.Address) (struct { + To common.Address + Amount *big.Int +}, error) { + return _Erc20.Contract.TransferFromCalled(&_Erc20.CallOpts, arg0) +} + +// TransferFromCalled is a free data retrieval call binding the contract method 0xe541efa2. +// +// Solidity: function transferFromCalled(address ) view returns(address to, uint256 amount) +func (_Erc20 *Erc20CallerSession) TransferFromCalled(arg0 common.Address) (struct { + To common.Address + Amount *big.Int +}, error) { + return _Erc20.Contract.TransferFromCalled(&_Erc20.CallOpts, arg0) +} + +// Approve is a paid mutator transaction binding the contract method 0x095ea7b3. +// +// Solidity: function approve(address s, uint256 a) returns(bool) +func (_Erc20 *Erc20Transactor) Approve(opts *bind.TransactOpts, s common.Address, a *big.Int) (*types.Transaction, error) { + return _Erc20.contract.Transact(opts, "approve", s, a) +} + +// Approve is a paid mutator transaction binding the contract method 0x095ea7b3. +// +// Solidity: function approve(address s, uint256 a) returns(bool) +func (_Erc20 *Erc20Session) Approve(s common.Address, a *big.Int) (*types.Transaction, error) { + return _Erc20.Contract.Approve(&_Erc20.TransactOpts, s, a) +} + +// Approve is a paid mutator transaction binding the contract method 0x095ea7b3. +// +// Solidity: function approve(address s, uint256 a) returns(bool) +func (_Erc20 *Erc20TransactorSession) Approve(s common.Address, a *big.Int) (*types.Transaction, error) { + return _Erc20.Contract.Approve(&_Erc20.TransactOpts, s, a) +} + +// ApproveReturns is a paid mutator transaction binding the contract method 0x9dd0ff37. +// +// Solidity: function approveReturns(bool b) returns() +func (_Erc20 *Erc20Transactor) ApproveReturns(opts *bind.TransactOpts, b bool) (*types.Transaction, error) { + return _Erc20.contract.Transact(opts, "approveReturns", b) +} + +// ApproveReturns is a paid mutator transaction binding the contract method 0x9dd0ff37. +// +// Solidity: function approveReturns(bool b) returns() +func (_Erc20 *Erc20Session) ApproveReturns(b bool) (*types.Transaction, error) { + return _Erc20.Contract.ApproveReturns(&_Erc20.TransactOpts, b) +} + +// ApproveReturns is a paid mutator transaction binding the contract method 0x9dd0ff37. +// +// Solidity: function approveReturns(bool b) returns() +func (_Erc20 *Erc20TransactorSession) ApproveReturns(b bool) (*types.Transaction, error) { + return _Erc20.Contract.ApproveReturns(&_Erc20.TransactOpts, b) +} + +// BalanceOf is a paid mutator transaction binding the contract method 0x70a08231. +// +// Solidity: function balanceOf(address t) returns(uint256) +func (_Erc20 *Erc20Transactor) BalanceOf(opts *bind.TransactOpts, t common.Address) (*types.Transaction, error) { + return _Erc20.contract.Transact(opts, "balanceOf", t) +} + +// BalanceOf is a paid mutator transaction binding the contract method 0x70a08231. +// +// Solidity: function balanceOf(address t) returns(uint256) +func (_Erc20 *Erc20Session) BalanceOf(t common.Address) (*types.Transaction, error) { + return _Erc20.Contract.BalanceOf(&_Erc20.TransactOpts, t) +} + +// BalanceOf is a paid mutator transaction binding the contract method 0x70a08231. +// +// Solidity: function balanceOf(address t) returns(uint256) +func (_Erc20 *Erc20TransactorSession) BalanceOf(t common.Address) (*types.Transaction, error) { + return _Erc20.Contract.BalanceOf(&_Erc20.TransactOpts, t) +} + +// BalanceOfReturns is a paid mutator transaction binding the contract method 0x39100838. +// +// Solidity: function balanceOfReturns(uint256 b) returns() +func (_Erc20 *Erc20Transactor) BalanceOfReturns(opts *bind.TransactOpts, b *big.Int) (*types.Transaction, error) { + return _Erc20.contract.Transact(opts, "balanceOfReturns", b) +} + +// BalanceOfReturns is a paid mutator transaction binding the contract method 0x39100838. +// +// Solidity: function balanceOfReturns(uint256 b) returns() +func (_Erc20 *Erc20Session) BalanceOfReturns(b *big.Int) (*types.Transaction, error) { + return _Erc20.Contract.BalanceOfReturns(&_Erc20.TransactOpts, b) +} + +// BalanceOfReturns is a paid mutator transaction binding the contract method 0x39100838. +// +// Solidity: function balanceOfReturns(uint256 b) returns() +func (_Erc20 *Erc20TransactorSession) BalanceOfReturns(b *big.Int) (*types.Transaction, error) { + return _Erc20.Contract.BalanceOfReturns(&_Erc20.TransactOpts, b) +} + +// Transfer is a paid mutator transaction binding the contract method 0xa9059cbb. +// +// Solidity: function transfer(address t, uint256 a) returns(bool) +func (_Erc20 *Erc20Transactor) Transfer(opts *bind.TransactOpts, t common.Address, a *big.Int) (*types.Transaction, error) { + return _Erc20.contract.Transact(opts, "transfer", t, a) +} + +// Transfer is a paid mutator transaction binding the contract method 0xa9059cbb. +// +// Solidity: function transfer(address t, uint256 a) returns(bool) +func (_Erc20 *Erc20Session) Transfer(t common.Address, a *big.Int) (*types.Transaction, error) { + return _Erc20.Contract.Transfer(&_Erc20.TransactOpts, t, a) +} + +// Transfer is a paid mutator transaction binding the contract method 0xa9059cbb. +// +// Solidity: function transfer(address t, uint256 a) returns(bool) +func (_Erc20 *Erc20TransactorSession) Transfer(t common.Address, a *big.Int) (*types.Transaction, error) { + return _Erc20.Contract.Transfer(&_Erc20.TransactOpts, t, a) +} + +// TransferFrom is a paid mutator transaction binding the contract method 0x23b872dd. +// +// Solidity: function transferFrom(address f, address t, uint256 a) returns(bool) +func (_Erc20 *Erc20Transactor) TransferFrom(opts *bind.TransactOpts, f common.Address, t common.Address, a *big.Int) (*types.Transaction, error) { + return _Erc20.contract.Transact(opts, "transferFrom", f, t, a) +} + +// TransferFrom is a paid mutator transaction binding the contract method 0x23b872dd. +// +// Solidity: function transferFrom(address f, address t, uint256 a) returns(bool) +func (_Erc20 *Erc20Session) TransferFrom(f common.Address, t common.Address, a *big.Int) (*types.Transaction, error) { + return _Erc20.Contract.TransferFrom(&_Erc20.TransactOpts, f, t, a) +} + +// TransferFrom is a paid mutator transaction binding the contract method 0x23b872dd. +// +// Solidity: function transferFrom(address f, address t, uint256 a) returns(bool) +func (_Erc20 *Erc20TransactorSession) TransferFrom(f common.Address, t common.Address, a *big.Int) (*types.Transaction, error) { + return _Erc20.Contract.TransferFrom(&_Erc20.TransactOpts, f, t, a) +} + +// TransferFromReturns is a paid mutator transaction binding the contract method 0x6521b96a. +// +// Solidity: function transferFromReturns(bool b) returns() +func (_Erc20 *Erc20Transactor) TransferFromReturns(opts *bind.TransactOpts, b bool) (*types.Transaction, error) { + return _Erc20.contract.Transact(opts, "transferFromReturns", b) +} + +// TransferFromReturns is a paid mutator transaction binding the contract method 0x6521b96a. +// +// Solidity: function transferFromReturns(bool b) returns() +func (_Erc20 *Erc20Session) TransferFromReturns(b bool) (*types.Transaction, error) { + return _Erc20.Contract.TransferFromReturns(&_Erc20.TransactOpts, b) +} + +// TransferFromReturns is a paid mutator transaction binding the contract method 0x6521b96a. +// +// Solidity: function transferFromReturns(bool b) returns() +func (_Erc20 *Erc20TransactorSession) TransferFromReturns(b bool) (*types.Transaction, error) { + return _Erc20.Contract.TransferFromReturns(&_Erc20.TransactOpts, b) +} + +// TransferReturns is a paid mutator transaction binding the contract method 0x42b6cdbc. +// +// Solidity: function transferReturns(bool b) returns() +func (_Erc20 *Erc20Transactor) TransferReturns(opts *bind.TransactOpts, b bool) (*types.Transaction, error) { + return _Erc20.contract.Transact(opts, "transferReturns", b) +} + +// TransferReturns is a paid mutator transaction binding the contract method 0x42b6cdbc. +// +// Solidity: function transferReturns(bool b) returns() +func (_Erc20 *Erc20Session) TransferReturns(b bool) (*types.Transaction, error) { + return _Erc20.Contract.TransferReturns(&_Erc20.TransactOpts, b) +} + +// TransferReturns is a paid mutator transaction binding the contract method 0x42b6cdbc. +// +// Solidity: function transferReturns(bool b) returns() +func (_Erc20 *Erc20TransactorSession) TransferReturns(b bool) (*types.Transaction, error) { + return _Erc20.Contract.TransferReturns(&_Erc20.TransactOpts, b) +} diff --git a/gost/test/mocks/marketplace.go b/gost/test/mocks/marketplace.go new file mode 100644 index 0000000..297b375 --- /dev/null +++ b/gost/test/mocks/marketplace.go @@ -0,0 +1,1135 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package mocks + +import ( + "math/big" + "strings" + + ethereum "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/event" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription +) + +// MarketPlaceABI is the input ABI used to generate the binding from. +const MarketPlaceABI = "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"u\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"m\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"t\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"a\",\"type\":\"uint256\"}],\"name\":\"burnZcTokenRemovingNotional\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"burnZcTokenRemovingNotionalCalled\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"maturity\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"one\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"two\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"b\",\"type\":\"bool\"}],\"name\":\"burnZcTokenRemovingNotionalReturns\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"u\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"m\",\"type\":\"uint256\"}],\"name\":\"cTokenAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"cTokenAddressCalled\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"a\",\"type\":\"address\"}],\"name\":\"cTokenAddressReturns\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"u\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"m\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"o\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"t\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"a\",\"type\":\"uint256\"}],\"name\":\"custodialExit\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"custodialExitCalled\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"maturity\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"one\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"two\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"b\",\"type\":\"bool\"}],\"name\":\"custodialExitReturns\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"u\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"m\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"o\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"t\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"a\",\"type\":\"uint256\"}],\"name\":\"custodialInitiate\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"custodialInitiateCalled\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"maturity\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"one\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"two\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"b\",\"type\":\"bool\"}],\"name\":\"custodialInitiateReturns\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"u\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"m\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"t\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"a\",\"type\":\"uint256\"}],\"name\":\"mintZcTokenAddingNotional\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"mintZcTokenAddingNotionalCalled\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"maturity\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"one\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"two\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"b\",\"type\":\"bool\"}],\"name\":\"mintZcTokenAddingNotionalReturns\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"u\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"m\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"o\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"t\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"a\",\"type\":\"uint256\"}],\"name\":\"p2pVaultExchange\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"p2pVaultExchangeCalled\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"maturity\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"one\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"two\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"b\",\"type\":\"bool\"}],\"name\":\"p2pVaultExchangeReturns\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"u\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"m\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"o\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"t\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"a\",\"type\":\"uint256\"}],\"name\":\"p2pZcTokenExchange\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"p2pZcTokenExchangeCalled\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"maturity\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"one\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"two\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"b\",\"type\":\"bool\"}],\"name\":\"p2pZcTokenExchangeReturns\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"u\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"m\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"t\",\"type\":\"address\"}],\"name\":\"redeemVaultInterest\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"redeemVaultInterestCalled\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"maturity\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"one\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"two\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"a\",\"type\":\"uint256\"}],\"name\":\"redeemVaultInterestReturns\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"u\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"m\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"t\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"a\",\"type\":\"uint256\"}],\"name\":\"redeemZcToken\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"redeemZcTokenCalled\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"maturity\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"one\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"two\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"a\",\"type\":\"uint256\"}],\"name\":\"redeemZcTokenReturns\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"u\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"m\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"f\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"a\",\"type\":\"uint256\"}],\"name\":\"transferVaultNotionalFee\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"transferVaultNotionalFeeCalled\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"maturity\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"one\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"two\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"b\",\"type\":\"bool\"}],\"name\":\"transferVaultNotionalFeeReturns\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]" + +// MarketPlaceBin is the compiled bytecode used for deploying new contracts. +var MarketPlaceBin = "0x608060405234801561001057600080fd5b50611d2b806100206000396000f3fe608060405234801561001057600080fd5b50600436106101da5760003560e01c80637d04cd1511610104578063c4c25726116100a2578063ddcfbbda11610071578063ddcfbbda1461060c578063eee6e8141461063f578063ef267f2c14610672578063f8e51bcb146106a2576101da565b8063c4c2572614610571578063c5ee114d146105a4578063d557ee85146105d4578063dc098af9146105f0576101da565b8063a11f4856116100de578063a11f4856146104c5578063b50a66f7146104f5578063bddbfbe414610525578063beaff41e14610555576101da565b80637d04cd151461044657806389de80aa146104625780638c6b9b4114610495576101da565b806333fe997a1161017c5780634521d3031161014b5780634521d303146103ab5780634bc81e09146103de57806365a963aa146103fa5780636ac910331461042a576101da565b806333fe997a146102e55780633cf9a4e3146103185780633f25be9d146103485780633f73df2c1461037b576101da565b80631cd7aed3116101b85780631cd7aed31461025e5780631cd9be91146102915780632634de19146102ad578063295b25f2146102c9576101da565b806303f5e400146101df57806304aa1dfd1461021257806305e1dc251461022e575b600080fd5b6101f960048036038101906101f491906119c5565b6106d2565b6040516102099493929190611c23565b60405180910390f35b61022c60048036038101906102279190611b53565b610742565b005b610248600480360381019061024391906119ee565b61075f565b6040516102559190611bd2565b60405180910390f35b610278600480360381019061027391906119c5565b6107cf565b6040516102889493929190611c23565b60405180910390f35b6102ab60048036038101906102a69190611b53565b61083f565b005b6102c760048036038101906102c29190611b53565b61085c565b005b6102e360048036038101906102de9190611b7c565b610879565b005b6102ff60048036038101906102fa91906119c5565b610883565b60405161030f9493929190611c23565b60405180910390f35b610332600480360381019061032d9190611af0565b6108f3565b60405161033f9190611bed565b60405180910390f35b610362600480360381019061035d91906119c5565b610a49565b6040516103729493929190611c23565b60405180910390f35b610395600480360381019061039091906119c5565b610ab9565b6040516103a29190611c08565b60405180910390f35b6103c560048036038101906103c091906119c5565b610ad1565b6040516103d59493929190611c23565b60405180910390f35b6103f860048036038101906103f39190611b53565b610b41565b005b610414600480360381019061040f9190611a79565b610b5e565b6040516104219190611bed565b60405180910390f35b610444600480360381019061043f9190611b7c565b610ced565b005b610460600480360381019061045b9190611b53565b610cf7565b005b61047c600480360381019061047791906119c5565b610d14565b60405161048c9493929190611c23565b60405180910390f35b6104af60048036038101906104aa9190611a79565b610d84565b6040516104bc9190611bed565b60405180910390f35b6104df60048036038101906104da9190611a2a565b610f13565b6040516104ec9190611c08565b60405180910390f35b61050f600480360381019061050a9190611af0565b611051565b60405161051c9190611bed565b60405180910390f35b61053f600480360381019061053a9190611a79565b6111a7565b60405161054c9190611bed565b60405180910390f35b61056f600480360381019061056a9190611b53565b611336565b005b61058b600480360381019061058691906119c5565b611353565b60405161059b9493929190611c23565b60405180910390f35b6105be60048036038101906105b99190611af0565b6113c3565b6040516105cb9190611c08565b60405180910390f35b6105ee60048036038101906105e991906119c5565b61150c565b005b61060a60048036038101906106059190611b53565b611550565b005b610626600480360381019061062191906119c5565b61156d565b6040516106369493929190611c23565b60405180910390f35b610659600480360381019061065491906119c5565b6115dd565b6040516106699493929190611c23565b60405180910390f35b61068c60048036038101906106879190611af0565b61164d565b6040516106999190611bed565b60405180910390f35b6106bc60048036038101906106b79190611a79565b6117a3565b6040516106c99190611bed565b60405180910390f35b60066020528060005260406000206000915090508060000154908060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060030154905084565b80600a601a6101000a81548160ff02191690831515021790555050565b6000816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550600a60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905092915050565b60096020528060005260406000206000915090508060000154908060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060030154905084565b80600a60156101000a81548160ff02191690831515021790555050565b80600a60146101000a81548160ff02191690831515021790555050565b80600c8190555050565b60076020528060005260406000206000915090508060000154908060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060030154905084565b60006108fd611932565b8481600001818152505083816020019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508281606001818152505080600760008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000820151816000015560208201518160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060608201518160030155905050600a601a9054906101000a900460ff16915050949350505050565b60016020528060005260406000206000915090508060000154908060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060030154905084565b60006020528060005260406000206000915090505481565b60026020528060005260406000206000915090508060000154908060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060030154905084565b80600a60186101000a81548160ff02191690831515021790555050565b6000610b68611932565b8581600001818152505084816020019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505083816040019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508281606001818152505080600360008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000820151816000015560208201518160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060608201518160030155905050600a60169054906101000a900460ff1691505095945050505050565b80600b8190555050565b80600a60176101000a81548160ff02191690831515021790555050565b60056020528060005260406000206000915090508060000154908060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060030154905084565b6000610d8e611932565b8581600001818152505084816020019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505083816040019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508281606001818152505080600260008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000820151816000015560208201518160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060608201518160030155905050600a60159054906101000a900460ff1691505095945050505050565b6000610f1d611932565b8381600001818152505082816020019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505080600960008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000820151816000015560208201518160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060608201518160030155905050600c549150509392505050565b600061105b611932565b8481600001818152505083816020019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508281606001818152505080600660008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000820151816000015560208201518160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060608201518160030155905050600a60199054906101000a900460ff16915050949350505050565b60006111b1611932565b8581600001818152505084816020019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505083816040019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508281606001818152505080600460008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000820151816000015560208201518160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060608201518160030155905050600a60179054906101000a900460ff1691505095945050505050565b80600a60166101000a81548160ff02191690831515021790555050565b60036020528060005260406000206000915090508060000154908060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060030154905084565b60006113cd611932565b8481600001818152505083816020019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508281606001818152505080600860008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000820151816000015560208201518160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060608201518160030155905050600b54915050949350505050565b80600a60006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b80600a60196101000a81548160ff02191690831515021790555050565b60086020528060005260406000206000915090508060000154908060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060030154905084565b60046020528060005260406000206000915090508060000154908060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060030154905084565b6000611657611932565b8481600001818152505083816020019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508281606001818152505080600560008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000820151816000015560208201518160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060608201518160030155905050600a60189054906101000a900460ff16915050949350505050565b60006117ad611932565b8581600001818152505084816020019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505083816040019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508281606001818152505080600160008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000820151816000015560208201518160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060608201518160030155905050600a60149054906101000a900460ff1691505095945050505050565b604051806080016040528060008152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600081525090565b60008135905061199581611cb0565b92915050565b6000813590506119aa81611cc7565b92915050565b6000813590506119bf81611cde565b92915050565b6000602082840312156119d757600080fd5b60006119e584828501611986565b91505092915050565b60008060408385031215611a0157600080fd5b6000611a0f85828601611986565b9250506020611a20858286016119b0565b9150509250929050565b600080600060608486031215611a3f57600080fd5b6000611a4d86828701611986565b9350506020611a5e868287016119b0565b9250506040611a6f86828701611986565b9150509250925092565b600080600080600060a08688031215611a9157600080fd5b6000611a9f88828901611986565b9550506020611ab0888289016119b0565b9450506040611ac188828901611986565b9350506060611ad288828901611986565b9250506080611ae3888289016119b0565b9150509295509295909350565b60008060008060808587031215611b0657600080fd5b6000611b1487828801611986565b9450506020611b25878288016119b0565b9350506040611b3687828801611986565b9250506060611b47878288016119b0565b91505092959194509250565b600060208284031215611b6557600080fd5b6000611b738482850161199b565b91505092915050565b600060208284031215611b8e57600080fd5b6000611b9c848285016119b0565b91505092915050565b611bae81611c68565b82525050565b611bbd81611c7a565b82525050565b611bcc81611ca6565b82525050565b6000602082019050611be76000830184611ba5565b92915050565b6000602082019050611c026000830184611bb4565b92915050565b6000602082019050611c1d6000830184611bc3565b92915050565b6000608082019050611c386000830187611bc3565b611c456020830186611ba5565b611c526040830185611ba5565b611c5f6060830184611bc3565b95945050505050565b6000611c7382611c86565b9050919050565b60008115159050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b611cb981611c68565b8114611cc457600080fd5b50565b611cd081611c7a565b8114611cdb57600080fd5b50565b611ce781611ca6565b8114611cf257600080fd5b5056fea264697066735822122032a3e970c3b9ef18601f746540da687b1bafb565338274208ceefc96c681682564736f6c63430008040033" + +// DeployMarketPlace deploys a new Ethereum contract, binding an instance of MarketPlace to it. +func DeployMarketPlace(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *MarketPlace, error) { + parsed, err := abi.JSON(strings.NewReader(MarketPlaceABI)) + if err != nil { + return common.Address{}, nil, nil, err + } + + address, tx, contract, err := bind.DeployContract(auth, parsed, common.FromHex(MarketPlaceBin), backend) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &MarketPlace{MarketPlaceCaller: MarketPlaceCaller{contract: contract}, MarketPlaceTransactor: MarketPlaceTransactor{contract: contract}, MarketPlaceFilterer: MarketPlaceFilterer{contract: contract}}, nil +} + +// MarketPlace is an auto generated Go binding around an Ethereum contract. +type MarketPlace struct { + MarketPlaceCaller // Read-only binding to the contract + MarketPlaceTransactor // Write-only binding to the contract + MarketPlaceFilterer // Log filterer for contract events +} + +// MarketPlaceCaller is an auto generated read-only Go binding around an Ethereum contract. +type MarketPlaceCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// MarketPlaceTransactor is an auto generated write-only Go binding around an Ethereum contract. +type MarketPlaceTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// MarketPlaceFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type MarketPlaceFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// MarketPlaceSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type MarketPlaceSession struct { + Contract *MarketPlace // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// MarketPlaceCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type MarketPlaceCallerSession struct { + Contract *MarketPlaceCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// MarketPlaceTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type MarketPlaceTransactorSession struct { + Contract *MarketPlaceTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// MarketPlaceRaw is an auto generated low-level Go binding around an Ethereum contract. +type MarketPlaceRaw struct { + Contract *MarketPlace // Generic contract binding to access the raw methods on +} + +// MarketPlaceCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type MarketPlaceCallerRaw struct { + Contract *MarketPlaceCaller // Generic read-only contract binding to access the raw methods on +} + +// MarketPlaceTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type MarketPlaceTransactorRaw struct { + Contract *MarketPlaceTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewMarketPlace creates a new instance of MarketPlace, bound to a specific deployed contract. +func NewMarketPlace(address common.Address, backend bind.ContractBackend) (*MarketPlace, error) { + contract, err := bindMarketPlace(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &MarketPlace{MarketPlaceCaller: MarketPlaceCaller{contract: contract}, MarketPlaceTransactor: MarketPlaceTransactor{contract: contract}, MarketPlaceFilterer: MarketPlaceFilterer{contract: contract}}, nil +} + +// NewMarketPlaceCaller creates a new read-only instance of MarketPlace, bound to a specific deployed contract. +func NewMarketPlaceCaller(address common.Address, caller bind.ContractCaller) (*MarketPlaceCaller, error) { + contract, err := bindMarketPlace(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &MarketPlaceCaller{contract: contract}, nil +} + +// NewMarketPlaceTransactor creates a new write-only instance of MarketPlace, bound to a specific deployed contract. +func NewMarketPlaceTransactor(address common.Address, transactor bind.ContractTransactor) (*MarketPlaceTransactor, error) { + contract, err := bindMarketPlace(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &MarketPlaceTransactor{contract: contract}, nil +} + +// NewMarketPlaceFilterer creates a new log filterer instance of MarketPlace, bound to a specific deployed contract. +func NewMarketPlaceFilterer(address common.Address, filterer bind.ContractFilterer) (*MarketPlaceFilterer, error) { + contract, err := bindMarketPlace(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &MarketPlaceFilterer{contract: contract}, nil +} + +// bindMarketPlace binds a generic wrapper to an already deployed contract. +func bindMarketPlace(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := abi.JSON(strings.NewReader(MarketPlaceABI)) + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_MarketPlace *MarketPlaceRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _MarketPlace.Contract.MarketPlaceCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_MarketPlace *MarketPlaceRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _MarketPlace.Contract.MarketPlaceTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_MarketPlace *MarketPlaceRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _MarketPlace.Contract.MarketPlaceTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_MarketPlace *MarketPlaceCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _MarketPlace.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_MarketPlace *MarketPlaceTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _MarketPlace.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_MarketPlace *MarketPlaceTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _MarketPlace.Contract.contract.Transact(opts, method, params...) +} + +// BurnZcTokenRemovingNotionalCalled is a free data retrieval call binding the contract method 0x03f5e400. +// +// Solidity: function burnZcTokenRemovingNotionalCalled(address ) view returns(uint256 maturity, address one, address two, uint256 amount) +func (_MarketPlace *MarketPlaceCaller) BurnZcTokenRemovingNotionalCalled(opts *bind.CallOpts, arg0 common.Address) (struct { + Maturity *big.Int + One common.Address + Two common.Address + Amount *big.Int +}, error) { + var out []interface{} + err := _MarketPlace.contract.Call(opts, &out, "burnZcTokenRemovingNotionalCalled", arg0) + + outstruct := new(struct { + Maturity *big.Int + One common.Address + Two common.Address + Amount *big.Int + }) + if err != nil { + return *outstruct, err + } + + outstruct.Maturity = out[0].(*big.Int) + outstruct.One = out[1].(common.Address) + outstruct.Two = out[2].(common.Address) + outstruct.Amount = out[3].(*big.Int) + + return *outstruct, err + +} + +// BurnZcTokenRemovingNotionalCalled is a free data retrieval call binding the contract method 0x03f5e400. +// +// Solidity: function burnZcTokenRemovingNotionalCalled(address ) view returns(uint256 maturity, address one, address two, uint256 amount) +func (_MarketPlace *MarketPlaceSession) BurnZcTokenRemovingNotionalCalled(arg0 common.Address) (struct { + Maturity *big.Int + One common.Address + Two common.Address + Amount *big.Int +}, error) { + return _MarketPlace.Contract.BurnZcTokenRemovingNotionalCalled(&_MarketPlace.CallOpts, arg0) +} + +// BurnZcTokenRemovingNotionalCalled is a free data retrieval call binding the contract method 0x03f5e400. +// +// Solidity: function burnZcTokenRemovingNotionalCalled(address ) view returns(uint256 maturity, address one, address two, uint256 amount) +func (_MarketPlace *MarketPlaceCallerSession) BurnZcTokenRemovingNotionalCalled(arg0 common.Address) (struct { + Maturity *big.Int + One common.Address + Two common.Address + Amount *big.Int +}, error) { + return _MarketPlace.Contract.BurnZcTokenRemovingNotionalCalled(&_MarketPlace.CallOpts, arg0) +} + +// CTokenAddressCalled is a free data retrieval call binding the contract method 0x3f73df2c. +// +// Solidity: function cTokenAddressCalled(address ) view returns(uint256) +func (_MarketPlace *MarketPlaceCaller) CTokenAddressCalled(opts *bind.CallOpts, arg0 common.Address) (*big.Int, error) { + var out []interface{} + err := _MarketPlace.contract.Call(opts, &out, "cTokenAddressCalled", arg0) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// CTokenAddressCalled is a free data retrieval call binding the contract method 0x3f73df2c. +// +// Solidity: function cTokenAddressCalled(address ) view returns(uint256) +func (_MarketPlace *MarketPlaceSession) CTokenAddressCalled(arg0 common.Address) (*big.Int, error) { + return _MarketPlace.Contract.CTokenAddressCalled(&_MarketPlace.CallOpts, arg0) +} + +// CTokenAddressCalled is a free data retrieval call binding the contract method 0x3f73df2c. +// +// Solidity: function cTokenAddressCalled(address ) view returns(uint256) +func (_MarketPlace *MarketPlaceCallerSession) CTokenAddressCalled(arg0 common.Address) (*big.Int, error) { + return _MarketPlace.Contract.CTokenAddressCalled(&_MarketPlace.CallOpts, arg0) +} + +// CustodialExitCalled is a free data retrieval call binding the contract method 0x4521d303. +// +// Solidity: function custodialExitCalled(address ) view returns(uint256 maturity, address one, address two, uint256 amount) +func (_MarketPlace *MarketPlaceCaller) CustodialExitCalled(opts *bind.CallOpts, arg0 common.Address) (struct { + Maturity *big.Int + One common.Address + Two common.Address + Amount *big.Int +}, error) { + var out []interface{} + err := _MarketPlace.contract.Call(opts, &out, "custodialExitCalled", arg0) + + outstruct := new(struct { + Maturity *big.Int + One common.Address + Two common.Address + Amount *big.Int + }) + if err != nil { + return *outstruct, err + } + + outstruct.Maturity = out[0].(*big.Int) + outstruct.One = out[1].(common.Address) + outstruct.Two = out[2].(common.Address) + outstruct.Amount = out[3].(*big.Int) + + return *outstruct, err + +} + +// CustodialExitCalled is a free data retrieval call binding the contract method 0x4521d303. +// +// Solidity: function custodialExitCalled(address ) view returns(uint256 maturity, address one, address two, uint256 amount) +func (_MarketPlace *MarketPlaceSession) CustodialExitCalled(arg0 common.Address) (struct { + Maturity *big.Int + One common.Address + Two common.Address + Amount *big.Int +}, error) { + return _MarketPlace.Contract.CustodialExitCalled(&_MarketPlace.CallOpts, arg0) +} + +// CustodialExitCalled is a free data retrieval call binding the contract method 0x4521d303. +// +// Solidity: function custodialExitCalled(address ) view returns(uint256 maturity, address one, address two, uint256 amount) +func (_MarketPlace *MarketPlaceCallerSession) CustodialExitCalled(arg0 common.Address) (struct { + Maturity *big.Int + One common.Address + Two common.Address + Amount *big.Int +}, error) { + return _MarketPlace.Contract.CustodialExitCalled(&_MarketPlace.CallOpts, arg0) +} + +// CustodialInitiateCalled is a free data retrieval call binding the contract method 0x3f25be9d. +// +// Solidity: function custodialInitiateCalled(address ) view returns(uint256 maturity, address one, address two, uint256 amount) +func (_MarketPlace *MarketPlaceCaller) CustodialInitiateCalled(opts *bind.CallOpts, arg0 common.Address) (struct { + Maturity *big.Int + One common.Address + Two common.Address + Amount *big.Int +}, error) { + var out []interface{} + err := _MarketPlace.contract.Call(opts, &out, "custodialInitiateCalled", arg0) + + outstruct := new(struct { + Maturity *big.Int + One common.Address + Two common.Address + Amount *big.Int + }) + if err != nil { + return *outstruct, err + } + + outstruct.Maturity = out[0].(*big.Int) + outstruct.One = out[1].(common.Address) + outstruct.Two = out[2].(common.Address) + outstruct.Amount = out[3].(*big.Int) + + return *outstruct, err + +} + +// CustodialInitiateCalled is a free data retrieval call binding the contract method 0x3f25be9d. +// +// Solidity: function custodialInitiateCalled(address ) view returns(uint256 maturity, address one, address two, uint256 amount) +func (_MarketPlace *MarketPlaceSession) CustodialInitiateCalled(arg0 common.Address) (struct { + Maturity *big.Int + One common.Address + Two common.Address + Amount *big.Int +}, error) { + return _MarketPlace.Contract.CustodialInitiateCalled(&_MarketPlace.CallOpts, arg0) +} + +// CustodialInitiateCalled is a free data retrieval call binding the contract method 0x3f25be9d. +// +// Solidity: function custodialInitiateCalled(address ) view returns(uint256 maturity, address one, address two, uint256 amount) +func (_MarketPlace *MarketPlaceCallerSession) CustodialInitiateCalled(arg0 common.Address) (struct { + Maturity *big.Int + One common.Address + Two common.Address + Amount *big.Int +}, error) { + return _MarketPlace.Contract.CustodialInitiateCalled(&_MarketPlace.CallOpts, arg0) +} + +// MintZcTokenAddingNotionalCalled is a free data retrieval call binding the contract method 0x89de80aa. +// +// Solidity: function mintZcTokenAddingNotionalCalled(address ) view returns(uint256 maturity, address one, address two, uint256 amount) +func (_MarketPlace *MarketPlaceCaller) MintZcTokenAddingNotionalCalled(opts *bind.CallOpts, arg0 common.Address) (struct { + Maturity *big.Int + One common.Address + Two common.Address + Amount *big.Int +}, error) { + var out []interface{} + err := _MarketPlace.contract.Call(opts, &out, "mintZcTokenAddingNotionalCalled", arg0) + + outstruct := new(struct { + Maturity *big.Int + One common.Address + Two common.Address + Amount *big.Int + }) + if err != nil { + return *outstruct, err + } + + outstruct.Maturity = out[0].(*big.Int) + outstruct.One = out[1].(common.Address) + outstruct.Two = out[2].(common.Address) + outstruct.Amount = out[3].(*big.Int) + + return *outstruct, err + +} + +// MintZcTokenAddingNotionalCalled is a free data retrieval call binding the contract method 0x89de80aa. +// +// Solidity: function mintZcTokenAddingNotionalCalled(address ) view returns(uint256 maturity, address one, address two, uint256 amount) +func (_MarketPlace *MarketPlaceSession) MintZcTokenAddingNotionalCalled(arg0 common.Address) (struct { + Maturity *big.Int + One common.Address + Two common.Address + Amount *big.Int +}, error) { + return _MarketPlace.Contract.MintZcTokenAddingNotionalCalled(&_MarketPlace.CallOpts, arg0) +} + +// MintZcTokenAddingNotionalCalled is a free data retrieval call binding the contract method 0x89de80aa. +// +// Solidity: function mintZcTokenAddingNotionalCalled(address ) view returns(uint256 maturity, address one, address two, uint256 amount) +func (_MarketPlace *MarketPlaceCallerSession) MintZcTokenAddingNotionalCalled(arg0 common.Address) (struct { + Maturity *big.Int + One common.Address + Two common.Address + Amount *big.Int +}, error) { + return _MarketPlace.Contract.MintZcTokenAddingNotionalCalled(&_MarketPlace.CallOpts, arg0) +} + +// P2pVaultExchangeCalled is a free data retrieval call binding the contract method 0xeee6e814. +// +// Solidity: function p2pVaultExchangeCalled(address ) view returns(uint256 maturity, address one, address two, uint256 amount) +func (_MarketPlace *MarketPlaceCaller) P2pVaultExchangeCalled(opts *bind.CallOpts, arg0 common.Address) (struct { + Maturity *big.Int + One common.Address + Two common.Address + Amount *big.Int +}, error) { + var out []interface{} + err := _MarketPlace.contract.Call(opts, &out, "p2pVaultExchangeCalled", arg0) + + outstruct := new(struct { + Maturity *big.Int + One common.Address + Two common.Address + Amount *big.Int + }) + if err != nil { + return *outstruct, err + } + + outstruct.Maturity = out[0].(*big.Int) + outstruct.One = out[1].(common.Address) + outstruct.Two = out[2].(common.Address) + outstruct.Amount = out[3].(*big.Int) + + return *outstruct, err + +} + +// P2pVaultExchangeCalled is a free data retrieval call binding the contract method 0xeee6e814. +// +// Solidity: function p2pVaultExchangeCalled(address ) view returns(uint256 maturity, address one, address two, uint256 amount) +func (_MarketPlace *MarketPlaceSession) P2pVaultExchangeCalled(arg0 common.Address) (struct { + Maturity *big.Int + One common.Address + Two common.Address + Amount *big.Int +}, error) { + return _MarketPlace.Contract.P2pVaultExchangeCalled(&_MarketPlace.CallOpts, arg0) +} + +// P2pVaultExchangeCalled is a free data retrieval call binding the contract method 0xeee6e814. +// +// Solidity: function p2pVaultExchangeCalled(address ) view returns(uint256 maturity, address one, address two, uint256 amount) +func (_MarketPlace *MarketPlaceCallerSession) P2pVaultExchangeCalled(arg0 common.Address) (struct { + Maturity *big.Int + One common.Address + Two common.Address + Amount *big.Int +}, error) { + return _MarketPlace.Contract.P2pVaultExchangeCalled(&_MarketPlace.CallOpts, arg0) +} + +// P2pZcTokenExchangeCalled is a free data retrieval call binding the contract method 0xc4c25726. +// +// Solidity: function p2pZcTokenExchangeCalled(address ) view returns(uint256 maturity, address one, address two, uint256 amount) +func (_MarketPlace *MarketPlaceCaller) P2pZcTokenExchangeCalled(opts *bind.CallOpts, arg0 common.Address) (struct { + Maturity *big.Int + One common.Address + Two common.Address + Amount *big.Int +}, error) { + var out []interface{} + err := _MarketPlace.contract.Call(opts, &out, "p2pZcTokenExchangeCalled", arg0) + + outstruct := new(struct { + Maturity *big.Int + One common.Address + Two common.Address + Amount *big.Int + }) + if err != nil { + return *outstruct, err + } + + outstruct.Maturity = out[0].(*big.Int) + outstruct.One = out[1].(common.Address) + outstruct.Two = out[2].(common.Address) + outstruct.Amount = out[3].(*big.Int) + + return *outstruct, err + +} + +// P2pZcTokenExchangeCalled is a free data retrieval call binding the contract method 0xc4c25726. +// +// Solidity: function p2pZcTokenExchangeCalled(address ) view returns(uint256 maturity, address one, address two, uint256 amount) +func (_MarketPlace *MarketPlaceSession) P2pZcTokenExchangeCalled(arg0 common.Address) (struct { + Maturity *big.Int + One common.Address + Two common.Address + Amount *big.Int +}, error) { + return _MarketPlace.Contract.P2pZcTokenExchangeCalled(&_MarketPlace.CallOpts, arg0) +} + +// P2pZcTokenExchangeCalled is a free data retrieval call binding the contract method 0xc4c25726. +// +// Solidity: function p2pZcTokenExchangeCalled(address ) view returns(uint256 maturity, address one, address two, uint256 amount) +func (_MarketPlace *MarketPlaceCallerSession) P2pZcTokenExchangeCalled(arg0 common.Address) (struct { + Maturity *big.Int + One common.Address + Two common.Address + Amount *big.Int +}, error) { + return _MarketPlace.Contract.P2pZcTokenExchangeCalled(&_MarketPlace.CallOpts, arg0) +} + +// RedeemVaultInterestCalled is a free data retrieval call binding the contract method 0x1cd7aed3. +// +// Solidity: function redeemVaultInterestCalled(address ) view returns(uint256 maturity, address one, address two, uint256 amount) +func (_MarketPlace *MarketPlaceCaller) RedeemVaultInterestCalled(opts *bind.CallOpts, arg0 common.Address) (struct { + Maturity *big.Int + One common.Address + Two common.Address + Amount *big.Int +}, error) { + var out []interface{} + err := _MarketPlace.contract.Call(opts, &out, "redeemVaultInterestCalled", arg0) + + outstruct := new(struct { + Maturity *big.Int + One common.Address + Two common.Address + Amount *big.Int + }) + if err != nil { + return *outstruct, err + } + + outstruct.Maturity = out[0].(*big.Int) + outstruct.One = out[1].(common.Address) + outstruct.Two = out[2].(common.Address) + outstruct.Amount = out[3].(*big.Int) + + return *outstruct, err + +} + +// RedeemVaultInterestCalled is a free data retrieval call binding the contract method 0x1cd7aed3. +// +// Solidity: function redeemVaultInterestCalled(address ) view returns(uint256 maturity, address one, address two, uint256 amount) +func (_MarketPlace *MarketPlaceSession) RedeemVaultInterestCalled(arg0 common.Address) (struct { + Maturity *big.Int + One common.Address + Two common.Address + Amount *big.Int +}, error) { + return _MarketPlace.Contract.RedeemVaultInterestCalled(&_MarketPlace.CallOpts, arg0) +} + +// RedeemVaultInterestCalled is a free data retrieval call binding the contract method 0x1cd7aed3. +// +// Solidity: function redeemVaultInterestCalled(address ) view returns(uint256 maturity, address one, address two, uint256 amount) +func (_MarketPlace *MarketPlaceCallerSession) RedeemVaultInterestCalled(arg0 common.Address) (struct { + Maturity *big.Int + One common.Address + Two common.Address + Amount *big.Int +}, error) { + return _MarketPlace.Contract.RedeemVaultInterestCalled(&_MarketPlace.CallOpts, arg0) +} + +// RedeemZcTokenCalled is a free data retrieval call binding the contract method 0xddcfbbda. +// +// Solidity: function redeemZcTokenCalled(address ) view returns(uint256 maturity, address one, address two, uint256 amount) +func (_MarketPlace *MarketPlaceCaller) RedeemZcTokenCalled(opts *bind.CallOpts, arg0 common.Address) (struct { + Maturity *big.Int + One common.Address + Two common.Address + Amount *big.Int +}, error) { + var out []interface{} + err := _MarketPlace.contract.Call(opts, &out, "redeemZcTokenCalled", arg0) + + outstruct := new(struct { + Maturity *big.Int + One common.Address + Two common.Address + Amount *big.Int + }) + if err != nil { + return *outstruct, err + } + + outstruct.Maturity = out[0].(*big.Int) + outstruct.One = out[1].(common.Address) + outstruct.Two = out[2].(common.Address) + outstruct.Amount = out[3].(*big.Int) + + return *outstruct, err + +} + +// RedeemZcTokenCalled is a free data retrieval call binding the contract method 0xddcfbbda. +// +// Solidity: function redeemZcTokenCalled(address ) view returns(uint256 maturity, address one, address two, uint256 amount) +func (_MarketPlace *MarketPlaceSession) RedeemZcTokenCalled(arg0 common.Address) (struct { + Maturity *big.Int + One common.Address + Two common.Address + Amount *big.Int +}, error) { + return _MarketPlace.Contract.RedeemZcTokenCalled(&_MarketPlace.CallOpts, arg0) +} + +// RedeemZcTokenCalled is a free data retrieval call binding the contract method 0xddcfbbda. +// +// Solidity: function redeemZcTokenCalled(address ) view returns(uint256 maturity, address one, address two, uint256 amount) +func (_MarketPlace *MarketPlaceCallerSession) RedeemZcTokenCalled(arg0 common.Address) (struct { + Maturity *big.Int + One common.Address + Two common.Address + Amount *big.Int +}, error) { + return _MarketPlace.Contract.RedeemZcTokenCalled(&_MarketPlace.CallOpts, arg0) +} + +// TransferVaultNotionalFeeCalled is a free data retrieval call binding the contract method 0x33fe997a. +// +// Solidity: function transferVaultNotionalFeeCalled(address ) view returns(uint256 maturity, address one, address two, uint256 amount) +func (_MarketPlace *MarketPlaceCaller) TransferVaultNotionalFeeCalled(opts *bind.CallOpts, arg0 common.Address) (struct { + Maturity *big.Int + One common.Address + Two common.Address + Amount *big.Int +}, error) { + var out []interface{} + err := _MarketPlace.contract.Call(opts, &out, "transferVaultNotionalFeeCalled", arg0) + + outstruct := new(struct { + Maturity *big.Int + One common.Address + Two common.Address + Amount *big.Int + }) + if err != nil { + return *outstruct, err + } + + outstruct.Maturity = out[0].(*big.Int) + outstruct.One = out[1].(common.Address) + outstruct.Two = out[2].(common.Address) + outstruct.Amount = out[3].(*big.Int) + + return *outstruct, err + +} + +// TransferVaultNotionalFeeCalled is a free data retrieval call binding the contract method 0x33fe997a. +// +// Solidity: function transferVaultNotionalFeeCalled(address ) view returns(uint256 maturity, address one, address two, uint256 amount) +func (_MarketPlace *MarketPlaceSession) TransferVaultNotionalFeeCalled(arg0 common.Address) (struct { + Maturity *big.Int + One common.Address + Two common.Address + Amount *big.Int +}, error) { + return _MarketPlace.Contract.TransferVaultNotionalFeeCalled(&_MarketPlace.CallOpts, arg0) +} + +// TransferVaultNotionalFeeCalled is a free data retrieval call binding the contract method 0x33fe997a. +// +// Solidity: function transferVaultNotionalFeeCalled(address ) view returns(uint256 maturity, address one, address two, uint256 amount) +func (_MarketPlace *MarketPlaceCallerSession) TransferVaultNotionalFeeCalled(arg0 common.Address) (struct { + Maturity *big.Int + One common.Address + Two common.Address + Amount *big.Int +}, error) { + return _MarketPlace.Contract.TransferVaultNotionalFeeCalled(&_MarketPlace.CallOpts, arg0) +} + +// BurnZcTokenRemovingNotional is a paid mutator transaction binding the contract method 0xb50a66f7. +// +// Solidity: function burnZcTokenRemovingNotional(address u, uint256 m, address t, uint256 a) returns(bool) +func (_MarketPlace *MarketPlaceTransactor) BurnZcTokenRemovingNotional(opts *bind.TransactOpts, u common.Address, m *big.Int, t common.Address, a *big.Int) (*types.Transaction, error) { + return _MarketPlace.contract.Transact(opts, "burnZcTokenRemovingNotional", u, m, t, a) +} + +// BurnZcTokenRemovingNotional is a paid mutator transaction binding the contract method 0xb50a66f7. +// +// Solidity: function burnZcTokenRemovingNotional(address u, uint256 m, address t, uint256 a) returns(bool) +func (_MarketPlace *MarketPlaceSession) BurnZcTokenRemovingNotional(u common.Address, m *big.Int, t common.Address, a *big.Int) (*types.Transaction, error) { + return _MarketPlace.Contract.BurnZcTokenRemovingNotional(&_MarketPlace.TransactOpts, u, m, t, a) +} + +// BurnZcTokenRemovingNotional is a paid mutator transaction binding the contract method 0xb50a66f7. +// +// Solidity: function burnZcTokenRemovingNotional(address u, uint256 m, address t, uint256 a) returns(bool) +func (_MarketPlace *MarketPlaceTransactorSession) BurnZcTokenRemovingNotional(u common.Address, m *big.Int, t common.Address, a *big.Int) (*types.Transaction, error) { + return _MarketPlace.Contract.BurnZcTokenRemovingNotional(&_MarketPlace.TransactOpts, u, m, t, a) +} + +// BurnZcTokenRemovingNotionalReturns is a paid mutator transaction binding the contract method 0xdc098af9. +// +// Solidity: function burnZcTokenRemovingNotionalReturns(bool b) returns() +func (_MarketPlace *MarketPlaceTransactor) BurnZcTokenRemovingNotionalReturns(opts *bind.TransactOpts, b bool) (*types.Transaction, error) { + return _MarketPlace.contract.Transact(opts, "burnZcTokenRemovingNotionalReturns", b) +} + +// BurnZcTokenRemovingNotionalReturns is a paid mutator transaction binding the contract method 0xdc098af9. +// +// Solidity: function burnZcTokenRemovingNotionalReturns(bool b) returns() +func (_MarketPlace *MarketPlaceSession) BurnZcTokenRemovingNotionalReturns(b bool) (*types.Transaction, error) { + return _MarketPlace.Contract.BurnZcTokenRemovingNotionalReturns(&_MarketPlace.TransactOpts, b) +} + +// BurnZcTokenRemovingNotionalReturns is a paid mutator transaction binding the contract method 0xdc098af9. +// +// Solidity: function burnZcTokenRemovingNotionalReturns(bool b) returns() +func (_MarketPlace *MarketPlaceTransactorSession) BurnZcTokenRemovingNotionalReturns(b bool) (*types.Transaction, error) { + return _MarketPlace.Contract.BurnZcTokenRemovingNotionalReturns(&_MarketPlace.TransactOpts, b) +} + +// CTokenAddress is a paid mutator transaction binding the contract method 0x05e1dc25. +// +// Solidity: function cTokenAddress(address u, uint256 m) returns(address) +func (_MarketPlace *MarketPlaceTransactor) CTokenAddress(opts *bind.TransactOpts, u common.Address, m *big.Int) (*types.Transaction, error) { + return _MarketPlace.contract.Transact(opts, "cTokenAddress", u, m) +} + +// CTokenAddress is a paid mutator transaction binding the contract method 0x05e1dc25. +// +// Solidity: function cTokenAddress(address u, uint256 m) returns(address) +func (_MarketPlace *MarketPlaceSession) CTokenAddress(u common.Address, m *big.Int) (*types.Transaction, error) { + return _MarketPlace.Contract.CTokenAddress(&_MarketPlace.TransactOpts, u, m) +} + +// CTokenAddress is a paid mutator transaction binding the contract method 0x05e1dc25. +// +// Solidity: function cTokenAddress(address u, uint256 m) returns(address) +func (_MarketPlace *MarketPlaceTransactorSession) CTokenAddress(u common.Address, m *big.Int) (*types.Transaction, error) { + return _MarketPlace.Contract.CTokenAddress(&_MarketPlace.TransactOpts, u, m) +} + +// CTokenAddressReturns is a paid mutator transaction binding the contract method 0xd557ee85. +// +// Solidity: function cTokenAddressReturns(address a) returns() +func (_MarketPlace *MarketPlaceTransactor) CTokenAddressReturns(opts *bind.TransactOpts, a common.Address) (*types.Transaction, error) { + return _MarketPlace.contract.Transact(opts, "cTokenAddressReturns", a) +} + +// CTokenAddressReturns is a paid mutator transaction binding the contract method 0xd557ee85. +// +// Solidity: function cTokenAddressReturns(address a) returns() +func (_MarketPlace *MarketPlaceSession) CTokenAddressReturns(a common.Address) (*types.Transaction, error) { + return _MarketPlace.Contract.CTokenAddressReturns(&_MarketPlace.TransactOpts, a) +} + +// CTokenAddressReturns is a paid mutator transaction binding the contract method 0xd557ee85. +// +// Solidity: function cTokenAddressReturns(address a) returns() +func (_MarketPlace *MarketPlaceTransactorSession) CTokenAddressReturns(a common.Address) (*types.Transaction, error) { + return _MarketPlace.Contract.CTokenAddressReturns(&_MarketPlace.TransactOpts, a) +} + +// CustodialExit is a paid mutator transaction binding the contract method 0x8c6b9b41. +// +// Solidity: function custodialExit(address u, uint256 m, address o, address t, uint256 a) returns(bool) +func (_MarketPlace *MarketPlaceTransactor) CustodialExit(opts *bind.TransactOpts, u common.Address, m *big.Int, o common.Address, t common.Address, a *big.Int) (*types.Transaction, error) { + return _MarketPlace.contract.Transact(opts, "custodialExit", u, m, o, t, a) +} + +// CustodialExit is a paid mutator transaction binding the contract method 0x8c6b9b41. +// +// Solidity: function custodialExit(address u, uint256 m, address o, address t, uint256 a) returns(bool) +func (_MarketPlace *MarketPlaceSession) CustodialExit(u common.Address, m *big.Int, o common.Address, t common.Address, a *big.Int) (*types.Transaction, error) { + return _MarketPlace.Contract.CustodialExit(&_MarketPlace.TransactOpts, u, m, o, t, a) +} + +// CustodialExit is a paid mutator transaction binding the contract method 0x8c6b9b41. +// +// Solidity: function custodialExit(address u, uint256 m, address o, address t, uint256 a) returns(bool) +func (_MarketPlace *MarketPlaceTransactorSession) CustodialExit(u common.Address, m *big.Int, o common.Address, t common.Address, a *big.Int) (*types.Transaction, error) { + return _MarketPlace.Contract.CustodialExit(&_MarketPlace.TransactOpts, u, m, o, t, a) +} + +// CustodialExitReturns is a paid mutator transaction binding the contract method 0x1cd9be91. +// +// Solidity: function custodialExitReturns(bool b) returns() +func (_MarketPlace *MarketPlaceTransactor) CustodialExitReturns(opts *bind.TransactOpts, b bool) (*types.Transaction, error) { + return _MarketPlace.contract.Transact(opts, "custodialExitReturns", b) +} + +// CustodialExitReturns is a paid mutator transaction binding the contract method 0x1cd9be91. +// +// Solidity: function custodialExitReturns(bool b) returns() +func (_MarketPlace *MarketPlaceSession) CustodialExitReturns(b bool) (*types.Transaction, error) { + return _MarketPlace.Contract.CustodialExitReturns(&_MarketPlace.TransactOpts, b) +} + +// CustodialExitReturns is a paid mutator transaction binding the contract method 0x1cd9be91. +// +// Solidity: function custodialExitReturns(bool b) returns() +func (_MarketPlace *MarketPlaceTransactorSession) CustodialExitReturns(b bool) (*types.Transaction, error) { + return _MarketPlace.Contract.CustodialExitReturns(&_MarketPlace.TransactOpts, b) +} + +// CustodialInitiate is a paid mutator transaction binding the contract method 0xf8e51bcb. +// +// Solidity: function custodialInitiate(address u, uint256 m, address o, address t, uint256 a) returns(bool) +func (_MarketPlace *MarketPlaceTransactor) CustodialInitiate(opts *bind.TransactOpts, u common.Address, m *big.Int, o common.Address, t common.Address, a *big.Int) (*types.Transaction, error) { + return _MarketPlace.contract.Transact(opts, "custodialInitiate", u, m, o, t, a) +} + +// CustodialInitiate is a paid mutator transaction binding the contract method 0xf8e51bcb. +// +// Solidity: function custodialInitiate(address u, uint256 m, address o, address t, uint256 a) returns(bool) +func (_MarketPlace *MarketPlaceSession) CustodialInitiate(u common.Address, m *big.Int, o common.Address, t common.Address, a *big.Int) (*types.Transaction, error) { + return _MarketPlace.Contract.CustodialInitiate(&_MarketPlace.TransactOpts, u, m, o, t, a) +} + +// CustodialInitiate is a paid mutator transaction binding the contract method 0xf8e51bcb. +// +// Solidity: function custodialInitiate(address u, uint256 m, address o, address t, uint256 a) returns(bool) +func (_MarketPlace *MarketPlaceTransactorSession) CustodialInitiate(u common.Address, m *big.Int, o common.Address, t common.Address, a *big.Int) (*types.Transaction, error) { + return _MarketPlace.Contract.CustodialInitiate(&_MarketPlace.TransactOpts, u, m, o, t, a) +} + +// CustodialInitiateReturns is a paid mutator transaction binding the contract method 0x2634de19. +// +// Solidity: function custodialInitiateReturns(bool b) returns() +func (_MarketPlace *MarketPlaceTransactor) CustodialInitiateReturns(opts *bind.TransactOpts, b bool) (*types.Transaction, error) { + return _MarketPlace.contract.Transact(opts, "custodialInitiateReturns", b) +} + +// CustodialInitiateReturns is a paid mutator transaction binding the contract method 0x2634de19. +// +// Solidity: function custodialInitiateReturns(bool b) returns() +func (_MarketPlace *MarketPlaceSession) CustodialInitiateReturns(b bool) (*types.Transaction, error) { + return _MarketPlace.Contract.CustodialInitiateReturns(&_MarketPlace.TransactOpts, b) +} + +// CustodialInitiateReturns is a paid mutator transaction binding the contract method 0x2634de19. +// +// Solidity: function custodialInitiateReturns(bool b) returns() +func (_MarketPlace *MarketPlaceTransactorSession) CustodialInitiateReturns(b bool) (*types.Transaction, error) { + return _MarketPlace.Contract.CustodialInitiateReturns(&_MarketPlace.TransactOpts, b) +} + +// MintZcTokenAddingNotional is a paid mutator transaction binding the contract method 0xef267f2c. +// +// Solidity: function mintZcTokenAddingNotional(address u, uint256 m, address t, uint256 a) returns(bool) +func (_MarketPlace *MarketPlaceTransactor) MintZcTokenAddingNotional(opts *bind.TransactOpts, u common.Address, m *big.Int, t common.Address, a *big.Int) (*types.Transaction, error) { + return _MarketPlace.contract.Transact(opts, "mintZcTokenAddingNotional", u, m, t, a) +} + +// MintZcTokenAddingNotional is a paid mutator transaction binding the contract method 0xef267f2c. +// +// Solidity: function mintZcTokenAddingNotional(address u, uint256 m, address t, uint256 a) returns(bool) +func (_MarketPlace *MarketPlaceSession) MintZcTokenAddingNotional(u common.Address, m *big.Int, t common.Address, a *big.Int) (*types.Transaction, error) { + return _MarketPlace.Contract.MintZcTokenAddingNotional(&_MarketPlace.TransactOpts, u, m, t, a) +} + +// MintZcTokenAddingNotional is a paid mutator transaction binding the contract method 0xef267f2c. +// +// Solidity: function mintZcTokenAddingNotional(address u, uint256 m, address t, uint256 a) returns(bool) +func (_MarketPlace *MarketPlaceTransactorSession) MintZcTokenAddingNotional(u common.Address, m *big.Int, t common.Address, a *big.Int) (*types.Transaction, error) { + return _MarketPlace.Contract.MintZcTokenAddingNotional(&_MarketPlace.TransactOpts, u, m, t, a) +} + +// MintZcTokenAddingNotionalReturns is a paid mutator transaction binding the contract method 0x4bc81e09. +// +// Solidity: function mintZcTokenAddingNotionalReturns(bool b) returns() +func (_MarketPlace *MarketPlaceTransactor) MintZcTokenAddingNotionalReturns(opts *bind.TransactOpts, b bool) (*types.Transaction, error) { + return _MarketPlace.contract.Transact(opts, "mintZcTokenAddingNotionalReturns", b) +} + +// MintZcTokenAddingNotionalReturns is a paid mutator transaction binding the contract method 0x4bc81e09. +// +// Solidity: function mintZcTokenAddingNotionalReturns(bool b) returns() +func (_MarketPlace *MarketPlaceSession) MintZcTokenAddingNotionalReturns(b bool) (*types.Transaction, error) { + return _MarketPlace.Contract.MintZcTokenAddingNotionalReturns(&_MarketPlace.TransactOpts, b) +} + +// MintZcTokenAddingNotionalReturns is a paid mutator transaction binding the contract method 0x4bc81e09. +// +// Solidity: function mintZcTokenAddingNotionalReturns(bool b) returns() +func (_MarketPlace *MarketPlaceTransactorSession) MintZcTokenAddingNotionalReturns(b bool) (*types.Transaction, error) { + return _MarketPlace.Contract.MintZcTokenAddingNotionalReturns(&_MarketPlace.TransactOpts, b) +} + +// P2pVaultExchange is a paid mutator transaction binding the contract method 0xbddbfbe4. +// +// Solidity: function p2pVaultExchange(address u, uint256 m, address o, address t, uint256 a) returns(bool) +func (_MarketPlace *MarketPlaceTransactor) P2pVaultExchange(opts *bind.TransactOpts, u common.Address, m *big.Int, o common.Address, t common.Address, a *big.Int) (*types.Transaction, error) { + return _MarketPlace.contract.Transact(opts, "p2pVaultExchange", u, m, o, t, a) +} + +// P2pVaultExchange is a paid mutator transaction binding the contract method 0xbddbfbe4. +// +// Solidity: function p2pVaultExchange(address u, uint256 m, address o, address t, uint256 a) returns(bool) +func (_MarketPlace *MarketPlaceSession) P2pVaultExchange(u common.Address, m *big.Int, o common.Address, t common.Address, a *big.Int) (*types.Transaction, error) { + return _MarketPlace.Contract.P2pVaultExchange(&_MarketPlace.TransactOpts, u, m, o, t, a) +} + +// P2pVaultExchange is a paid mutator transaction binding the contract method 0xbddbfbe4. +// +// Solidity: function p2pVaultExchange(address u, uint256 m, address o, address t, uint256 a) returns(bool) +func (_MarketPlace *MarketPlaceTransactorSession) P2pVaultExchange(u common.Address, m *big.Int, o common.Address, t common.Address, a *big.Int) (*types.Transaction, error) { + return _MarketPlace.Contract.P2pVaultExchange(&_MarketPlace.TransactOpts, u, m, o, t, a) +} + +// P2pVaultExchangeReturns is a paid mutator transaction binding the contract method 0x7d04cd15. +// +// Solidity: function p2pVaultExchangeReturns(bool b) returns() +func (_MarketPlace *MarketPlaceTransactor) P2pVaultExchangeReturns(opts *bind.TransactOpts, b bool) (*types.Transaction, error) { + return _MarketPlace.contract.Transact(opts, "p2pVaultExchangeReturns", b) +} + +// P2pVaultExchangeReturns is a paid mutator transaction binding the contract method 0x7d04cd15. +// +// Solidity: function p2pVaultExchangeReturns(bool b) returns() +func (_MarketPlace *MarketPlaceSession) P2pVaultExchangeReturns(b bool) (*types.Transaction, error) { + return _MarketPlace.Contract.P2pVaultExchangeReturns(&_MarketPlace.TransactOpts, b) +} + +// P2pVaultExchangeReturns is a paid mutator transaction binding the contract method 0x7d04cd15. +// +// Solidity: function p2pVaultExchangeReturns(bool b) returns() +func (_MarketPlace *MarketPlaceTransactorSession) P2pVaultExchangeReturns(b bool) (*types.Transaction, error) { + return _MarketPlace.Contract.P2pVaultExchangeReturns(&_MarketPlace.TransactOpts, b) +} + +// P2pZcTokenExchange is a paid mutator transaction binding the contract method 0x65a963aa. +// +// Solidity: function p2pZcTokenExchange(address u, uint256 m, address o, address t, uint256 a) returns(bool) +func (_MarketPlace *MarketPlaceTransactor) P2pZcTokenExchange(opts *bind.TransactOpts, u common.Address, m *big.Int, o common.Address, t common.Address, a *big.Int) (*types.Transaction, error) { + return _MarketPlace.contract.Transact(opts, "p2pZcTokenExchange", u, m, o, t, a) +} + +// P2pZcTokenExchange is a paid mutator transaction binding the contract method 0x65a963aa. +// +// Solidity: function p2pZcTokenExchange(address u, uint256 m, address o, address t, uint256 a) returns(bool) +func (_MarketPlace *MarketPlaceSession) P2pZcTokenExchange(u common.Address, m *big.Int, o common.Address, t common.Address, a *big.Int) (*types.Transaction, error) { + return _MarketPlace.Contract.P2pZcTokenExchange(&_MarketPlace.TransactOpts, u, m, o, t, a) +} + +// P2pZcTokenExchange is a paid mutator transaction binding the contract method 0x65a963aa. +// +// Solidity: function p2pZcTokenExchange(address u, uint256 m, address o, address t, uint256 a) returns(bool) +func (_MarketPlace *MarketPlaceTransactorSession) P2pZcTokenExchange(u common.Address, m *big.Int, o common.Address, t common.Address, a *big.Int) (*types.Transaction, error) { + return _MarketPlace.Contract.P2pZcTokenExchange(&_MarketPlace.TransactOpts, u, m, o, t, a) +} + +// P2pZcTokenExchangeReturns is a paid mutator transaction binding the contract method 0xbeaff41e. +// +// Solidity: function p2pZcTokenExchangeReturns(bool b) returns() +func (_MarketPlace *MarketPlaceTransactor) P2pZcTokenExchangeReturns(opts *bind.TransactOpts, b bool) (*types.Transaction, error) { + return _MarketPlace.contract.Transact(opts, "p2pZcTokenExchangeReturns", b) +} + +// P2pZcTokenExchangeReturns is a paid mutator transaction binding the contract method 0xbeaff41e. +// +// Solidity: function p2pZcTokenExchangeReturns(bool b) returns() +func (_MarketPlace *MarketPlaceSession) P2pZcTokenExchangeReturns(b bool) (*types.Transaction, error) { + return _MarketPlace.Contract.P2pZcTokenExchangeReturns(&_MarketPlace.TransactOpts, b) +} + +// P2pZcTokenExchangeReturns is a paid mutator transaction binding the contract method 0xbeaff41e. +// +// Solidity: function p2pZcTokenExchangeReturns(bool b) returns() +func (_MarketPlace *MarketPlaceTransactorSession) P2pZcTokenExchangeReturns(b bool) (*types.Transaction, error) { + return _MarketPlace.Contract.P2pZcTokenExchangeReturns(&_MarketPlace.TransactOpts, b) +} + +// RedeemVaultInterest is a paid mutator transaction binding the contract method 0xa11f4856. +// +// Solidity: function redeemVaultInterest(address u, uint256 m, address t) returns(uint256) +func (_MarketPlace *MarketPlaceTransactor) RedeemVaultInterest(opts *bind.TransactOpts, u common.Address, m *big.Int, t common.Address) (*types.Transaction, error) { + return _MarketPlace.contract.Transact(opts, "redeemVaultInterest", u, m, t) +} + +// RedeemVaultInterest is a paid mutator transaction binding the contract method 0xa11f4856. +// +// Solidity: function redeemVaultInterest(address u, uint256 m, address t) returns(uint256) +func (_MarketPlace *MarketPlaceSession) RedeemVaultInterest(u common.Address, m *big.Int, t common.Address) (*types.Transaction, error) { + return _MarketPlace.Contract.RedeemVaultInterest(&_MarketPlace.TransactOpts, u, m, t) +} + +// RedeemVaultInterest is a paid mutator transaction binding the contract method 0xa11f4856. +// +// Solidity: function redeemVaultInterest(address u, uint256 m, address t) returns(uint256) +func (_MarketPlace *MarketPlaceTransactorSession) RedeemVaultInterest(u common.Address, m *big.Int, t common.Address) (*types.Transaction, error) { + return _MarketPlace.Contract.RedeemVaultInterest(&_MarketPlace.TransactOpts, u, m, t) +} + +// RedeemVaultInterestReturns is a paid mutator transaction binding the contract method 0x295b25f2. +// +// Solidity: function redeemVaultInterestReturns(uint256 a) returns() +func (_MarketPlace *MarketPlaceTransactor) RedeemVaultInterestReturns(opts *bind.TransactOpts, a *big.Int) (*types.Transaction, error) { + return _MarketPlace.contract.Transact(opts, "redeemVaultInterestReturns", a) +} + +// RedeemVaultInterestReturns is a paid mutator transaction binding the contract method 0x295b25f2. +// +// Solidity: function redeemVaultInterestReturns(uint256 a) returns() +func (_MarketPlace *MarketPlaceSession) RedeemVaultInterestReturns(a *big.Int) (*types.Transaction, error) { + return _MarketPlace.Contract.RedeemVaultInterestReturns(&_MarketPlace.TransactOpts, a) +} + +// RedeemVaultInterestReturns is a paid mutator transaction binding the contract method 0x295b25f2. +// +// Solidity: function redeemVaultInterestReturns(uint256 a) returns() +func (_MarketPlace *MarketPlaceTransactorSession) RedeemVaultInterestReturns(a *big.Int) (*types.Transaction, error) { + return _MarketPlace.Contract.RedeemVaultInterestReturns(&_MarketPlace.TransactOpts, a) +} + +// RedeemZcToken is a paid mutator transaction binding the contract method 0xc5ee114d. +// +// Solidity: function redeemZcToken(address u, uint256 m, address t, uint256 a) returns(uint256) +func (_MarketPlace *MarketPlaceTransactor) RedeemZcToken(opts *bind.TransactOpts, u common.Address, m *big.Int, t common.Address, a *big.Int) (*types.Transaction, error) { + return _MarketPlace.contract.Transact(opts, "redeemZcToken", u, m, t, a) +} + +// RedeemZcToken is a paid mutator transaction binding the contract method 0xc5ee114d. +// +// Solidity: function redeemZcToken(address u, uint256 m, address t, uint256 a) returns(uint256) +func (_MarketPlace *MarketPlaceSession) RedeemZcToken(u common.Address, m *big.Int, t common.Address, a *big.Int) (*types.Transaction, error) { + return _MarketPlace.Contract.RedeemZcToken(&_MarketPlace.TransactOpts, u, m, t, a) +} + +// RedeemZcToken is a paid mutator transaction binding the contract method 0xc5ee114d. +// +// Solidity: function redeemZcToken(address u, uint256 m, address t, uint256 a) returns(uint256) +func (_MarketPlace *MarketPlaceTransactorSession) RedeemZcToken(u common.Address, m *big.Int, t common.Address, a *big.Int) (*types.Transaction, error) { + return _MarketPlace.Contract.RedeemZcToken(&_MarketPlace.TransactOpts, u, m, t, a) +} + +// RedeemZcTokenReturns is a paid mutator transaction binding the contract method 0x6ac91033. +// +// Solidity: function redeemZcTokenReturns(uint256 a) returns() +func (_MarketPlace *MarketPlaceTransactor) RedeemZcTokenReturns(opts *bind.TransactOpts, a *big.Int) (*types.Transaction, error) { + return _MarketPlace.contract.Transact(opts, "redeemZcTokenReturns", a) +} + +// RedeemZcTokenReturns is a paid mutator transaction binding the contract method 0x6ac91033. +// +// Solidity: function redeemZcTokenReturns(uint256 a) returns() +func (_MarketPlace *MarketPlaceSession) RedeemZcTokenReturns(a *big.Int) (*types.Transaction, error) { + return _MarketPlace.Contract.RedeemZcTokenReturns(&_MarketPlace.TransactOpts, a) +} + +// RedeemZcTokenReturns is a paid mutator transaction binding the contract method 0x6ac91033. +// +// Solidity: function redeemZcTokenReturns(uint256 a) returns() +func (_MarketPlace *MarketPlaceTransactorSession) RedeemZcTokenReturns(a *big.Int) (*types.Transaction, error) { + return _MarketPlace.Contract.RedeemZcTokenReturns(&_MarketPlace.TransactOpts, a) +} + +// TransferVaultNotionalFee is a paid mutator transaction binding the contract method 0x3cf9a4e3. +// +// Solidity: function transferVaultNotionalFee(address u, uint256 m, address f, uint256 a) returns(bool) +func (_MarketPlace *MarketPlaceTransactor) TransferVaultNotionalFee(opts *bind.TransactOpts, u common.Address, m *big.Int, f common.Address, a *big.Int) (*types.Transaction, error) { + return _MarketPlace.contract.Transact(opts, "transferVaultNotionalFee", u, m, f, a) +} + +// TransferVaultNotionalFee is a paid mutator transaction binding the contract method 0x3cf9a4e3. +// +// Solidity: function transferVaultNotionalFee(address u, uint256 m, address f, uint256 a) returns(bool) +func (_MarketPlace *MarketPlaceSession) TransferVaultNotionalFee(u common.Address, m *big.Int, f common.Address, a *big.Int) (*types.Transaction, error) { + return _MarketPlace.Contract.TransferVaultNotionalFee(&_MarketPlace.TransactOpts, u, m, f, a) +} + +// TransferVaultNotionalFee is a paid mutator transaction binding the contract method 0x3cf9a4e3. +// +// Solidity: function transferVaultNotionalFee(address u, uint256 m, address f, uint256 a) returns(bool) +func (_MarketPlace *MarketPlaceTransactorSession) TransferVaultNotionalFee(u common.Address, m *big.Int, f common.Address, a *big.Int) (*types.Transaction, error) { + return _MarketPlace.Contract.TransferVaultNotionalFee(&_MarketPlace.TransactOpts, u, m, f, a) +} + +// TransferVaultNotionalFeeReturns is a paid mutator transaction binding the contract method 0x04aa1dfd. +// +// Solidity: function transferVaultNotionalFeeReturns(bool b) returns() +func (_MarketPlace *MarketPlaceTransactor) TransferVaultNotionalFeeReturns(opts *bind.TransactOpts, b bool) (*types.Transaction, error) { + return _MarketPlace.contract.Transact(opts, "transferVaultNotionalFeeReturns", b) +} + +// TransferVaultNotionalFeeReturns is a paid mutator transaction binding the contract method 0x04aa1dfd. +// +// Solidity: function transferVaultNotionalFeeReturns(bool b) returns() +func (_MarketPlace *MarketPlaceSession) TransferVaultNotionalFeeReturns(b bool) (*types.Transaction, error) { + return _MarketPlace.Contract.TransferVaultNotionalFeeReturns(&_MarketPlace.TransactOpts, b) +} + +// TransferVaultNotionalFeeReturns is a paid mutator transaction binding the contract method 0x04aa1dfd. +// +// Solidity: function transferVaultNotionalFeeReturns(bool b) returns() +func (_MarketPlace *MarketPlaceTransactorSession) TransferVaultNotionalFeeReturns(b bool) (*types.Transaction, error) { + return _MarketPlace.Contract.TransferVaultNotionalFeeReturns(&_MarketPlace.TransactOpts, b) +} diff --git a/gost/test/mocks/vaulttracker.go b/gost/test/mocks/vaulttracker.go new file mode 100644 index 0000000..aab8346 --- /dev/null +++ b/gost/test/mocks/vaulttracker.go @@ -0,0 +1,734 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package mocks + +import ( + "math/big" + "strings" + + ethereum "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/event" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription +) + +// VaultTrackerABI is the input ABI used to generate the binding from. +const VaultTrackerABI = "[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"m\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"c\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"s\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"o\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"a\",\"type\":\"uint256\"}],\"name\":\"addNotional\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"addNotionalCalled\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"b\",\"type\":\"bool\"}],\"name\":\"addNotionalReturns\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"cTokenAddr\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"matureVault\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"b\",\"type\":\"bool\"}],\"name\":\"matureVaultReturns\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"maturity\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"n\",\"type\":\"uint256\"}],\"name\":\"maturityReturns\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"o\",\"type\":\"address\"}],\"name\":\"redeemInterest\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"redeemInterestCalled\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"a\",\"type\":\"uint256\"}],\"name\":\"redeemInterestReturns\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"o\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"a\",\"type\":\"uint256\"}],\"name\":\"removeNotional\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"removeNotionalCalled\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"b\",\"type\":\"bool\"}],\"name\":\"removeNotionalReturns\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"swivel\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"f\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"a\",\"type\":\"uint256\"}],\"name\":\"transferNotionalFee\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"transferNotionalFeeCalled\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"b\",\"type\":\"bool\"}],\"name\":\"transferNotionalFeeReturns\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"f\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"t\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"a\",\"type\":\"uint256\"}],\"name\":\"transferNotionalFrom\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"transferNotionalFromCalled\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"b\",\"type\":\"bool\"}],\"name\":\"transferNotionalFromReturns\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]" + +// VaultTrackerBin is the compiled bytecode used for deploying new contracts. +var VaultTrackerBin = "0x608060405234801561001057600080fd5b5060405161082238038061082283398101604081905261002f91610082565b600792909255600480546001600160a01b039283166001600160a01b031991821617909155600580549290931691161790556100bd565b80516001600160a01b038116811461007d57600080fd5b919050565b600080600060608486031215610096578283fd5b835192506100a660208501610066565b91506100b460408501610066565b90509250925092565b610756806100cc6000396000f3fe608060405234801561001057600080fd5b50600436106101775760003560e01c806382cac89c116100d8578063b7dd34831161008c578063d6cb2c0d11610066578063d6cb2c0d1461057c578063da3de9e91461058f578063e590c362146105ce57600080fd5b8063b7dd3483146104f5578063bbce238614610515578063d0b9d0321461053557600080fd5b8063a701da69116100bd578063a701da6914610453578063b326258d1461049b578063b4c4a4c8146104e257600080fd5b806382cac89c146103ef578063a01cfffb1461040f57600080fd5b80633dfa1f411161012f5780635dfe12ac116101145780635dfe12ac14610359578063613a28d11461039f5780636b868d51146103e457600080fd5b80633dfa1f41146102f25780635c70b7c11461031257600080fd5b8063177946731161016057806317794673146101f457806319caf46c14610291578063204f83f9146102ea57600080fd5b8063012b264a1461017c5780630aa93b9b146101c6575b600080fd5b60055461019c9073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b6101e66101d4366004610663565b60016020526000908152604090205481565b6040519081526020016101bd565b610281610202366004610684565b60408051808201825273ffffffffffffffffffffffffffffffffffffffff93841681526020808201938452948416600090815260029095529320925183547fffffffffffffffffffffffff0000000000000000000000000000000000000000169216919091178255516001909101556009546301000000900460ff1690565b60405190151581526020016101bd565b6101e661029f366004610663565b600680547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9290921691909117905560085490565b6007546101e6565b6101e6610300366004610663565b60006020819052908152604090205481565b6103576103203660046106e8565b60098054911515610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff909216919091179055565b005b6103576103673660046106e8565b6009805491151562010000027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff909216919091179055565b6102816103ad3660046106bf565b73ffffffffffffffffffffffffffffffffffffffff9190911660009081526001602052604090205560095462010000900460ff1690565b60095460ff16610281565b60065461019c9073ffffffffffffffffffffffffffffffffffffffff1681565b61028161041d3660046106bf565b73ffffffffffffffffffffffffffffffffffffffff91909116600090815260208190526040902055600954610100900460ff1690565b6103576104613660046106e8565b60098054911515640100000000027fffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffff909216919091179055565b6102816104a93660046106bf565b73ffffffffffffffffffffffffffffffffffffffff91909116600090815260036020526040902055600954640100000000900460ff1690565b6103576104f0366004610708565b600755565b60045461019c9073ffffffffffffffffffffffffffffffffffffffff1681565b6101e6610523366004610663565b60036020526000908152604090205481565b6103576105433660046106e8565b600980549115156301000000027fffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffff909216919091179055565b61035761058a366004610708565b600855565b61035761059d3660046106e8565b600980547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055565b61060e6105dc366004610663565b6002602052600090815260409020805460019091015473ffffffffffffffffffffffffffffffffffffffff9091169082565b6040805173ffffffffffffffffffffffffffffffffffffffff90931683526020830191909152016101bd565b803573ffffffffffffffffffffffffffffffffffffffff8116811461065e57600080fd5b919050565b600060208284031215610674578081fd5b61067d8261063a565b9392505050565b600080600060608486031215610698578182fd5b6106a18461063a565b92506106af6020850161063a565b9150604084013590509250925092565b600080604083850312156106d1578182fd5b6106da8361063a565b946020939093013593505050565b6000602082840312156106f9578081fd5b8135801515811461067d578182fd5b600060208284031215610719578081fd5b503591905056fea26469706673582212202ce12b1980bd5f82baa5e2ebd47a5978b9f4251b48a4b88ed7b08f2685a21f8e64736f6c63430008040033" + +// DeployVaultTracker deploys a new Ethereum contract, binding an instance of VaultTracker to it. +func DeployVaultTracker(auth *bind.TransactOpts, backend bind.ContractBackend, m *big.Int, c common.Address, s common.Address) (common.Address, *types.Transaction, *VaultTracker, error) { + parsed, err := abi.JSON(strings.NewReader(VaultTrackerABI)) + if err != nil { + return common.Address{}, nil, nil, err + } + + address, tx, contract, err := bind.DeployContract(auth, parsed, common.FromHex(VaultTrackerBin), backend, m, c, s) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &VaultTracker{VaultTrackerCaller: VaultTrackerCaller{contract: contract}, VaultTrackerTransactor: VaultTrackerTransactor{contract: contract}, VaultTrackerFilterer: VaultTrackerFilterer{contract: contract}}, nil +} + +// VaultTracker is an auto generated Go binding around an Ethereum contract. +type VaultTracker struct { + VaultTrackerCaller // Read-only binding to the contract + VaultTrackerTransactor // Write-only binding to the contract + VaultTrackerFilterer // Log filterer for contract events +} + +// VaultTrackerCaller is an auto generated read-only Go binding around an Ethereum contract. +type VaultTrackerCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// VaultTrackerTransactor is an auto generated write-only Go binding around an Ethereum contract. +type VaultTrackerTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// VaultTrackerFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type VaultTrackerFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// VaultTrackerSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type VaultTrackerSession struct { + Contract *VaultTracker // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// VaultTrackerCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type VaultTrackerCallerSession struct { + Contract *VaultTrackerCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// VaultTrackerTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type VaultTrackerTransactorSession struct { + Contract *VaultTrackerTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// VaultTrackerRaw is an auto generated low-level Go binding around an Ethereum contract. +type VaultTrackerRaw struct { + Contract *VaultTracker // Generic contract binding to access the raw methods on +} + +// VaultTrackerCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type VaultTrackerCallerRaw struct { + Contract *VaultTrackerCaller // Generic read-only contract binding to access the raw methods on +} + +// VaultTrackerTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type VaultTrackerTransactorRaw struct { + Contract *VaultTrackerTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewVaultTracker creates a new instance of VaultTracker, bound to a specific deployed contract. +func NewVaultTracker(address common.Address, backend bind.ContractBackend) (*VaultTracker, error) { + contract, err := bindVaultTracker(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &VaultTracker{VaultTrackerCaller: VaultTrackerCaller{contract: contract}, VaultTrackerTransactor: VaultTrackerTransactor{contract: contract}, VaultTrackerFilterer: VaultTrackerFilterer{contract: contract}}, nil +} + +// NewVaultTrackerCaller creates a new read-only instance of VaultTracker, bound to a specific deployed contract. +func NewVaultTrackerCaller(address common.Address, caller bind.ContractCaller) (*VaultTrackerCaller, error) { + contract, err := bindVaultTracker(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &VaultTrackerCaller{contract: contract}, nil +} + +// NewVaultTrackerTransactor creates a new write-only instance of VaultTracker, bound to a specific deployed contract. +func NewVaultTrackerTransactor(address common.Address, transactor bind.ContractTransactor) (*VaultTrackerTransactor, error) { + contract, err := bindVaultTracker(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &VaultTrackerTransactor{contract: contract}, nil +} + +// NewVaultTrackerFilterer creates a new log filterer instance of VaultTracker, bound to a specific deployed contract. +func NewVaultTrackerFilterer(address common.Address, filterer bind.ContractFilterer) (*VaultTrackerFilterer, error) { + contract, err := bindVaultTracker(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &VaultTrackerFilterer{contract: contract}, nil +} + +// bindVaultTracker binds a generic wrapper to an already deployed contract. +func bindVaultTracker(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := abi.JSON(strings.NewReader(VaultTrackerABI)) + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_VaultTracker *VaultTrackerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _VaultTracker.Contract.VaultTrackerCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_VaultTracker *VaultTrackerRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _VaultTracker.Contract.VaultTrackerTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_VaultTracker *VaultTrackerRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _VaultTracker.Contract.VaultTrackerTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_VaultTracker *VaultTrackerCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _VaultTracker.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_VaultTracker *VaultTrackerTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _VaultTracker.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_VaultTracker *VaultTrackerTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _VaultTracker.Contract.contract.Transact(opts, method, params...) +} + +// AddNotionalCalled is a free data retrieval call binding the contract method 0x3dfa1f41. +// +// Solidity: function addNotionalCalled(address ) view returns(uint256) +func (_VaultTracker *VaultTrackerCaller) AddNotionalCalled(opts *bind.CallOpts, arg0 common.Address) (*big.Int, error) { + var out []interface{} + err := _VaultTracker.contract.Call(opts, &out, "addNotionalCalled", arg0) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// AddNotionalCalled is a free data retrieval call binding the contract method 0x3dfa1f41. +// +// Solidity: function addNotionalCalled(address ) view returns(uint256) +func (_VaultTracker *VaultTrackerSession) AddNotionalCalled(arg0 common.Address) (*big.Int, error) { + return _VaultTracker.Contract.AddNotionalCalled(&_VaultTracker.CallOpts, arg0) +} + +// AddNotionalCalled is a free data retrieval call binding the contract method 0x3dfa1f41. +// +// Solidity: function addNotionalCalled(address ) view returns(uint256) +func (_VaultTracker *VaultTrackerCallerSession) AddNotionalCalled(arg0 common.Address) (*big.Int, error) { + return _VaultTracker.Contract.AddNotionalCalled(&_VaultTracker.CallOpts, arg0) +} + +// CTokenAddr is a free data retrieval call binding the contract method 0xb7dd3483. +// +// Solidity: function cTokenAddr() view returns(address) +func (_VaultTracker *VaultTrackerCaller) CTokenAddr(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _VaultTracker.contract.Call(opts, &out, "cTokenAddr") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// CTokenAddr is a free data retrieval call binding the contract method 0xb7dd3483. +// +// Solidity: function cTokenAddr() view returns(address) +func (_VaultTracker *VaultTrackerSession) CTokenAddr() (common.Address, error) { + return _VaultTracker.Contract.CTokenAddr(&_VaultTracker.CallOpts) +} + +// CTokenAddr is a free data retrieval call binding the contract method 0xb7dd3483. +// +// Solidity: function cTokenAddr() view returns(address) +func (_VaultTracker *VaultTrackerCallerSession) CTokenAddr() (common.Address, error) { + return _VaultTracker.Contract.CTokenAddr(&_VaultTracker.CallOpts) +} + +// MatureVault is a free data retrieval call binding the contract method 0x6b868d51. +// +// Solidity: function matureVault() view returns(bool) +func (_VaultTracker *VaultTrackerCaller) MatureVault(opts *bind.CallOpts) (bool, error) { + var out []interface{} + err := _VaultTracker.contract.Call(opts, &out, "matureVault") + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// MatureVault is a free data retrieval call binding the contract method 0x6b868d51. +// +// Solidity: function matureVault() view returns(bool) +func (_VaultTracker *VaultTrackerSession) MatureVault() (bool, error) { + return _VaultTracker.Contract.MatureVault(&_VaultTracker.CallOpts) +} + +// MatureVault is a free data retrieval call binding the contract method 0x6b868d51. +// +// Solidity: function matureVault() view returns(bool) +func (_VaultTracker *VaultTrackerCallerSession) MatureVault() (bool, error) { + return _VaultTracker.Contract.MatureVault(&_VaultTracker.CallOpts) +} + +// Maturity is a free data retrieval call binding the contract method 0x204f83f9. +// +// Solidity: function maturity() view returns(uint256) +func (_VaultTracker *VaultTrackerCaller) Maturity(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _VaultTracker.contract.Call(opts, &out, "maturity") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// Maturity is a free data retrieval call binding the contract method 0x204f83f9. +// +// Solidity: function maturity() view returns(uint256) +func (_VaultTracker *VaultTrackerSession) Maturity() (*big.Int, error) { + return _VaultTracker.Contract.Maturity(&_VaultTracker.CallOpts) +} + +// Maturity is a free data retrieval call binding the contract method 0x204f83f9. +// +// Solidity: function maturity() view returns(uint256) +func (_VaultTracker *VaultTrackerCallerSession) Maturity() (*big.Int, error) { + return _VaultTracker.Contract.Maturity(&_VaultTracker.CallOpts) +} + +// RedeemInterestCalled is a free data retrieval call binding the contract method 0x82cac89c. +// +// Solidity: function redeemInterestCalled() view returns(address) +func (_VaultTracker *VaultTrackerCaller) RedeemInterestCalled(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _VaultTracker.contract.Call(opts, &out, "redeemInterestCalled") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// RedeemInterestCalled is a free data retrieval call binding the contract method 0x82cac89c. +// +// Solidity: function redeemInterestCalled() view returns(address) +func (_VaultTracker *VaultTrackerSession) RedeemInterestCalled() (common.Address, error) { + return _VaultTracker.Contract.RedeemInterestCalled(&_VaultTracker.CallOpts) +} + +// RedeemInterestCalled is a free data retrieval call binding the contract method 0x82cac89c. +// +// Solidity: function redeemInterestCalled() view returns(address) +func (_VaultTracker *VaultTrackerCallerSession) RedeemInterestCalled() (common.Address, error) { + return _VaultTracker.Contract.RedeemInterestCalled(&_VaultTracker.CallOpts) +} + +// RemoveNotionalCalled is a free data retrieval call binding the contract method 0x0aa93b9b. +// +// Solidity: function removeNotionalCalled(address ) view returns(uint256) +func (_VaultTracker *VaultTrackerCaller) RemoveNotionalCalled(opts *bind.CallOpts, arg0 common.Address) (*big.Int, error) { + var out []interface{} + err := _VaultTracker.contract.Call(opts, &out, "removeNotionalCalled", arg0) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// RemoveNotionalCalled is a free data retrieval call binding the contract method 0x0aa93b9b. +// +// Solidity: function removeNotionalCalled(address ) view returns(uint256) +func (_VaultTracker *VaultTrackerSession) RemoveNotionalCalled(arg0 common.Address) (*big.Int, error) { + return _VaultTracker.Contract.RemoveNotionalCalled(&_VaultTracker.CallOpts, arg0) +} + +// RemoveNotionalCalled is a free data retrieval call binding the contract method 0x0aa93b9b. +// +// Solidity: function removeNotionalCalled(address ) view returns(uint256) +func (_VaultTracker *VaultTrackerCallerSession) RemoveNotionalCalled(arg0 common.Address) (*big.Int, error) { + return _VaultTracker.Contract.RemoveNotionalCalled(&_VaultTracker.CallOpts, arg0) +} + +// Swivel is a free data retrieval call binding the contract method 0x012b264a. +// +// Solidity: function swivel() view returns(address) +func (_VaultTracker *VaultTrackerCaller) Swivel(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _VaultTracker.contract.Call(opts, &out, "swivel") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// Swivel is a free data retrieval call binding the contract method 0x012b264a. +// +// Solidity: function swivel() view returns(address) +func (_VaultTracker *VaultTrackerSession) Swivel() (common.Address, error) { + return _VaultTracker.Contract.Swivel(&_VaultTracker.CallOpts) +} + +// Swivel is a free data retrieval call binding the contract method 0x012b264a. +// +// Solidity: function swivel() view returns(address) +func (_VaultTracker *VaultTrackerCallerSession) Swivel() (common.Address, error) { + return _VaultTracker.Contract.Swivel(&_VaultTracker.CallOpts) +} + +// TransferNotionalFeeCalled is a free data retrieval call binding the contract method 0xbbce2386. +// +// Solidity: function transferNotionalFeeCalled(address ) view returns(uint256) +func (_VaultTracker *VaultTrackerCaller) TransferNotionalFeeCalled(opts *bind.CallOpts, arg0 common.Address) (*big.Int, error) { + var out []interface{} + err := _VaultTracker.contract.Call(opts, &out, "transferNotionalFeeCalled", arg0) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// TransferNotionalFeeCalled is a free data retrieval call binding the contract method 0xbbce2386. +// +// Solidity: function transferNotionalFeeCalled(address ) view returns(uint256) +func (_VaultTracker *VaultTrackerSession) TransferNotionalFeeCalled(arg0 common.Address) (*big.Int, error) { + return _VaultTracker.Contract.TransferNotionalFeeCalled(&_VaultTracker.CallOpts, arg0) +} + +// TransferNotionalFeeCalled is a free data retrieval call binding the contract method 0xbbce2386. +// +// Solidity: function transferNotionalFeeCalled(address ) view returns(uint256) +func (_VaultTracker *VaultTrackerCallerSession) TransferNotionalFeeCalled(arg0 common.Address) (*big.Int, error) { + return _VaultTracker.Contract.TransferNotionalFeeCalled(&_VaultTracker.CallOpts, arg0) +} + +// TransferNotionalFromCalled is a free data retrieval call binding the contract method 0xe590c362. +// +// Solidity: function transferNotionalFromCalled(address ) view returns(address to, uint256 amount) +func (_VaultTracker *VaultTrackerCaller) TransferNotionalFromCalled(opts *bind.CallOpts, arg0 common.Address) (struct { + To common.Address + Amount *big.Int +}, error) { + var out []interface{} + err := _VaultTracker.contract.Call(opts, &out, "transferNotionalFromCalled", arg0) + + outstruct := new(struct { + To common.Address + Amount *big.Int + }) + if err != nil { + return *outstruct, err + } + + outstruct.To = out[0].(common.Address) + outstruct.Amount = out[1].(*big.Int) + + return *outstruct, err + +} + +// TransferNotionalFromCalled is a free data retrieval call binding the contract method 0xe590c362. +// +// Solidity: function transferNotionalFromCalled(address ) view returns(address to, uint256 amount) +func (_VaultTracker *VaultTrackerSession) TransferNotionalFromCalled(arg0 common.Address) (struct { + To common.Address + Amount *big.Int +}, error) { + return _VaultTracker.Contract.TransferNotionalFromCalled(&_VaultTracker.CallOpts, arg0) +} + +// TransferNotionalFromCalled is a free data retrieval call binding the contract method 0xe590c362. +// +// Solidity: function transferNotionalFromCalled(address ) view returns(address to, uint256 amount) +func (_VaultTracker *VaultTrackerCallerSession) TransferNotionalFromCalled(arg0 common.Address) (struct { + To common.Address + Amount *big.Int +}, error) { + return _VaultTracker.Contract.TransferNotionalFromCalled(&_VaultTracker.CallOpts, arg0) +} + +// AddNotional is a paid mutator transaction binding the contract method 0xa01cfffb. +// +// Solidity: function addNotional(address o, uint256 a) returns(bool) +func (_VaultTracker *VaultTrackerTransactor) AddNotional(opts *bind.TransactOpts, o common.Address, a *big.Int) (*types.Transaction, error) { + return _VaultTracker.contract.Transact(opts, "addNotional", o, a) +} + +// AddNotional is a paid mutator transaction binding the contract method 0xa01cfffb. +// +// Solidity: function addNotional(address o, uint256 a) returns(bool) +func (_VaultTracker *VaultTrackerSession) AddNotional(o common.Address, a *big.Int) (*types.Transaction, error) { + return _VaultTracker.Contract.AddNotional(&_VaultTracker.TransactOpts, o, a) +} + +// AddNotional is a paid mutator transaction binding the contract method 0xa01cfffb. +// +// Solidity: function addNotional(address o, uint256 a) returns(bool) +func (_VaultTracker *VaultTrackerTransactorSession) AddNotional(o common.Address, a *big.Int) (*types.Transaction, error) { + return _VaultTracker.Contract.AddNotional(&_VaultTracker.TransactOpts, o, a) +} + +// AddNotionalReturns is a paid mutator transaction binding the contract method 0x5c70b7c1. +// +// Solidity: function addNotionalReturns(bool b) returns() +func (_VaultTracker *VaultTrackerTransactor) AddNotionalReturns(opts *bind.TransactOpts, b bool) (*types.Transaction, error) { + return _VaultTracker.contract.Transact(opts, "addNotionalReturns", b) +} + +// AddNotionalReturns is a paid mutator transaction binding the contract method 0x5c70b7c1. +// +// Solidity: function addNotionalReturns(bool b) returns() +func (_VaultTracker *VaultTrackerSession) AddNotionalReturns(b bool) (*types.Transaction, error) { + return _VaultTracker.Contract.AddNotionalReturns(&_VaultTracker.TransactOpts, b) +} + +// AddNotionalReturns is a paid mutator transaction binding the contract method 0x5c70b7c1. +// +// Solidity: function addNotionalReturns(bool b) returns() +func (_VaultTracker *VaultTrackerTransactorSession) AddNotionalReturns(b bool) (*types.Transaction, error) { + return _VaultTracker.Contract.AddNotionalReturns(&_VaultTracker.TransactOpts, b) +} + +// MatureVaultReturns is a paid mutator transaction binding the contract method 0xda3de9e9. +// +// Solidity: function matureVaultReturns(bool b) returns() +func (_VaultTracker *VaultTrackerTransactor) MatureVaultReturns(opts *bind.TransactOpts, b bool) (*types.Transaction, error) { + return _VaultTracker.contract.Transact(opts, "matureVaultReturns", b) +} + +// MatureVaultReturns is a paid mutator transaction binding the contract method 0xda3de9e9. +// +// Solidity: function matureVaultReturns(bool b) returns() +func (_VaultTracker *VaultTrackerSession) MatureVaultReturns(b bool) (*types.Transaction, error) { + return _VaultTracker.Contract.MatureVaultReturns(&_VaultTracker.TransactOpts, b) +} + +// MatureVaultReturns is a paid mutator transaction binding the contract method 0xda3de9e9. +// +// Solidity: function matureVaultReturns(bool b) returns() +func (_VaultTracker *VaultTrackerTransactorSession) MatureVaultReturns(b bool) (*types.Transaction, error) { + return _VaultTracker.Contract.MatureVaultReturns(&_VaultTracker.TransactOpts, b) +} + +// MaturityReturns is a paid mutator transaction binding the contract method 0xb4c4a4c8. +// +// Solidity: function maturityReturns(uint256 n) returns() +func (_VaultTracker *VaultTrackerTransactor) MaturityReturns(opts *bind.TransactOpts, n *big.Int) (*types.Transaction, error) { + return _VaultTracker.contract.Transact(opts, "maturityReturns", n) +} + +// MaturityReturns is a paid mutator transaction binding the contract method 0xb4c4a4c8. +// +// Solidity: function maturityReturns(uint256 n) returns() +func (_VaultTracker *VaultTrackerSession) MaturityReturns(n *big.Int) (*types.Transaction, error) { + return _VaultTracker.Contract.MaturityReturns(&_VaultTracker.TransactOpts, n) +} + +// MaturityReturns is a paid mutator transaction binding the contract method 0xb4c4a4c8. +// +// Solidity: function maturityReturns(uint256 n) returns() +func (_VaultTracker *VaultTrackerTransactorSession) MaturityReturns(n *big.Int) (*types.Transaction, error) { + return _VaultTracker.Contract.MaturityReturns(&_VaultTracker.TransactOpts, n) +} + +// RedeemInterest is a paid mutator transaction binding the contract method 0x19caf46c. +// +// Solidity: function redeemInterest(address o) returns(uint256) +func (_VaultTracker *VaultTrackerTransactor) RedeemInterest(opts *bind.TransactOpts, o common.Address) (*types.Transaction, error) { + return _VaultTracker.contract.Transact(opts, "redeemInterest", o) +} + +// RedeemInterest is a paid mutator transaction binding the contract method 0x19caf46c. +// +// Solidity: function redeemInterest(address o) returns(uint256) +func (_VaultTracker *VaultTrackerSession) RedeemInterest(o common.Address) (*types.Transaction, error) { + return _VaultTracker.Contract.RedeemInterest(&_VaultTracker.TransactOpts, o) +} + +// RedeemInterest is a paid mutator transaction binding the contract method 0x19caf46c. +// +// Solidity: function redeemInterest(address o) returns(uint256) +func (_VaultTracker *VaultTrackerTransactorSession) RedeemInterest(o common.Address) (*types.Transaction, error) { + return _VaultTracker.Contract.RedeemInterest(&_VaultTracker.TransactOpts, o) +} + +// RedeemInterestReturns is a paid mutator transaction binding the contract method 0xd6cb2c0d. +// +// Solidity: function redeemInterestReturns(uint256 a) returns() +func (_VaultTracker *VaultTrackerTransactor) RedeemInterestReturns(opts *bind.TransactOpts, a *big.Int) (*types.Transaction, error) { + return _VaultTracker.contract.Transact(opts, "redeemInterestReturns", a) +} + +// RedeemInterestReturns is a paid mutator transaction binding the contract method 0xd6cb2c0d. +// +// Solidity: function redeemInterestReturns(uint256 a) returns() +func (_VaultTracker *VaultTrackerSession) RedeemInterestReturns(a *big.Int) (*types.Transaction, error) { + return _VaultTracker.Contract.RedeemInterestReturns(&_VaultTracker.TransactOpts, a) +} + +// RedeemInterestReturns is a paid mutator transaction binding the contract method 0xd6cb2c0d. +// +// Solidity: function redeemInterestReturns(uint256 a) returns() +func (_VaultTracker *VaultTrackerTransactorSession) RedeemInterestReturns(a *big.Int) (*types.Transaction, error) { + return _VaultTracker.Contract.RedeemInterestReturns(&_VaultTracker.TransactOpts, a) +} + +// RemoveNotional is a paid mutator transaction binding the contract method 0x613a28d1. +// +// Solidity: function removeNotional(address o, uint256 a) returns(bool) +func (_VaultTracker *VaultTrackerTransactor) RemoveNotional(opts *bind.TransactOpts, o common.Address, a *big.Int) (*types.Transaction, error) { + return _VaultTracker.contract.Transact(opts, "removeNotional", o, a) +} + +// RemoveNotional is a paid mutator transaction binding the contract method 0x613a28d1. +// +// Solidity: function removeNotional(address o, uint256 a) returns(bool) +func (_VaultTracker *VaultTrackerSession) RemoveNotional(o common.Address, a *big.Int) (*types.Transaction, error) { + return _VaultTracker.Contract.RemoveNotional(&_VaultTracker.TransactOpts, o, a) +} + +// RemoveNotional is a paid mutator transaction binding the contract method 0x613a28d1. +// +// Solidity: function removeNotional(address o, uint256 a) returns(bool) +func (_VaultTracker *VaultTrackerTransactorSession) RemoveNotional(o common.Address, a *big.Int) (*types.Transaction, error) { + return _VaultTracker.Contract.RemoveNotional(&_VaultTracker.TransactOpts, o, a) +} + +// RemoveNotionalReturns is a paid mutator transaction binding the contract method 0x5dfe12ac. +// +// Solidity: function removeNotionalReturns(bool b) returns() +func (_VaultTracker *VaultTrackerTransactor) RemoveNotionalReturns(opts *bind.TransactOpts, b bool) (*types.Transaction, error) { + return _VaultTracker.contract.Transact(opts, "removeNotionalReturns", b) +} + +// RemoveNotionalReturns is a paid mutator transaction binding the contract method 0x5dfe12ac. +// +// Solidity: function removeNotionalReturns(bool b) returns() +func (_VaultTracker *VaultTrackerSession) RemoveNotionalReturns(b bool) (*types.Transaction, error) { + return _VaultTracker.Contract.RemoveNotionalReturns(&_VaultTracker.TransactOpts, b) +} + +// RemoveNotionalReturns is a paid mutator transaction binding the contract method 0x5dfe12ac. +// +// Solidity: function removeNotionalReturns(bool b) returns() +func (_VaultTracker *VaultTrackerTransactorSession) RemoveNotionalReturns(b bool) (*types.Transaction, error) { + return _VaultTracker.Contract.RemoveNotionalReturns(&_VaultTracker.TransactOpts, b) +} + +// TransferNotionalFee is a paid mutator transaction binding the contract method 0xb326258d. +// +// Solidity: function transferNotionalFee(address f, uint256 a) returns(bool) +func (_VaultTracker *VaultTrackerTransactor) TransferNotionalFee(opts *bind.TransactOpts, f common.Address, a *big.Int) (*types.Transaction, error) { + return _VaultTracker.contract.Transact(opts, "transferNotionalFee", f, a) +} + +// TransferNotionalFee is a paid mutator transaction binding the contract method 0xb326258d. +// +// Solidity: function transferNotionalFee(address f, uint256 a) returns(bool) +func (_VaultTracker *VaultTrackerSession) TransferNotionalFee(f common.Address, a *big.Int) (*types.Transaction, error) { + return _VaultTracker.Contract.TransferNotionalFee(&_VaultTracker.TransactOpts, f, a) +} + +// TransferNotionalFee is a paid mutator transaction binding the contract method 0xb326258d. +// +// Solidity: function transferNotionalFee(address f, uint256 a) returns(bool) +func (_VaultTracker *VaultTrackerTransactorSession) TransferNotionalFee(f common.Address, a *big.Int) (*types.Transaction, error) { + return _VaultTracker.Contract.TransferNotionalFee(&_VaultTracker.TransactOpts, f, a) +} + +// TransferNotionalFeeReturns is a paid mutator transaction binding the contract method 0xa701da69. +// +// Solidity: function transferNotionalFeeReturns(bool b) returns() +func (_VaultTracker *VaultTrackerTransactor) TransferNotionalFeeReturns(opts *bind.TransactOpts, b bool) (*types.Transaction, error) { + return _VaultTracker.contract.Transact(opts, "transferNotionalFeeReturns", b) +} + +// TransferNotionalFeeReturns is a paid mutator transaction binding the contract method 0xa701da69. +// +// Solidity: function transferNotionalFeeReturns(bool b) returns() +func (_VaultTracker *VaultTrackerSession) TransferNotionalFeeReturns(b bool) (*types.Transaction, error) { + return _VaultTracker.Contract.TransferNotionalFeeReturns(&_VaultTracker.TransactOpts, b) +} + +// TransferNotionalFeeReturns is a paid mutator transaction binding the contract method 0xa701da69. +// +// Solidity: function transferNotionalFeeReturns(bool b) returns() +func (_VaultTracker *VaultTrackerTransactorSession) TransferNotionalFeeReturns(b bool) (*types.Transaction, error) { + return _VaultTracker.Contract.TransferNotionalFeeReturns(&_VaultTracker.TransactOpts, b) +} + +// TransferNotionalFrom is a paid mutator transaction binding the contract method 0x17794673. +// +// Solidity: function transferNotionalFrom(address f, address t, uint256 a) returns(bool) +func (_VaultTracker *VaultTrackerTransactor) TransferNotionalFrom(opts *bind.TransactOpts, f common.Address, t common.Address, a *big.Int) (*types.Transaction, error) { + return _VaultTracker.contract.Transact(opts, "transferNotionalFrom", f, t, a) +} + +// TransferNotionalFrom is a paid mutator transaction binding the contract method 0x17794673. +// +// Solidity: function transferNotionalFrom(address f, address t, uint256 a) returns(bool) +func (_VaultTracker *VaultTrackerSession) TransferNotionalFrom(f common.Address, t common.Address, a *big.Int) (*types.Transaction, error) { + return _VaultTracker.Contract.TransferNotionalFrom(&_VaultTracker.TransactOpts, f, t, a) +} + +// TransferNotionalFrom is a paid mutator transaction binding the contract method 0x17794673. +// +// Solidity: function transferNotionalFrom(address f, address t, uint256 a) returns(bool) +func (_VaultTracker *VaultTrackerTransactorSession) TransferNotionalFrom(f common.Address, t common.Address, a *big.Int) (*types.Transaction, error) { + return _VaultTracker.Contract.TransferNotionalFrom(&_VaultTracker.TransactOpts, f, t, a) +} + +// TransferNotionalFromReturns is a paid mutator transaction binding the contract method 0xd0b9d032. +// +// Solidity: function transferNotionalFromReturns(bool b) returns() +func (_VaultTracker *VaultTrackerTransactor) TransferNotionalFromReturns(opts *bind.TransactOpts, b bool) (*types.Transaction, error) { + return _VaultTracker.contract.Transact(opts, "transferNotionalFromReturns", b) +} + +// TransferNotionalFromReturns is a paid mutator transaction binding the contract method 0xd0b9d032. +// +// Solidity: function transferNotionalFromReturns(bool b) returns() +func (_VaultTracker *VaultTrackerSession) TransferNotionalFromReturns(b bool) (*types.Transaction, error) { + return _VaultTracker.Contract.TransferNotionalFromReturns(&_VaultTracker.TransactOpts, b) +} + +// TransferNotionalFromReturns is a paid mutator transaction binding the contract method 0xd0b9d032. +// +// Solidity: function transferNotionalFromReturns(bool b) returns() +func (_VaultTracker *VaultTrackerTransactorSession) TransferNotionalFromReturns(b bool) (*types.Transaction, error) { + return _VaultTracker.Contract.TransferNotionalFromReturns(&_VaultTracker.TransactOpts, b) +} diff --git a/gost/test/mocks/zctoken.go b/gost/test/mocks/zctoken.go new file mode 100644 index 0000000..e95e21d --- /dev/null +++ b/gost/test/mocks/zctoken.go @@ -0,0 +1,619 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package mocks + +import ( + "math/big" + "strings" + + ethereum "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/event" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription +) + +// ZcTokenABI is the input ABI used to generate the binding from. +const ZcTokenABI = "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"u\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"m\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"n\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"s\",\"type\":\"string\"},{\"internalType\":\"uint8\",\"name\":\"d\",\"type\":\"uint8\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"f\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"a\",\"type\":\"uint256\"}],\"name\":\"burn\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"burnCalled\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"b\",\"type\":\"bool\"}],\"name\":\"burnReturns\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"decimals\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"maturity\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"n\",\"type\":\"uint256\"}],\"name\":\"maturityReturns\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"f\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"a\",\"type\":\"uint256\"}],\"name\":\"mint\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"mintCalled\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"b\",\"type\":\"bool\"}],\"name\":\"mintReturns\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"symbol\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"f\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"t\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"a\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"transferFromCalled\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"b\",\"type\":\"bool\"}],\"name\":\"transferFromReturns\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"underlying\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"u\",\"type\":\"address\"}],\"name\":\"underlyingReturns\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]" + +// ZcTokenBin is the compiled bytecode used for deploying new contracts. +var ZcTokenBin = "0x60806040523480156200001157600080fd5b5060405162000a2a38038062000a2a8339810160408190526200003491620001fd565b60058054610100600160a81b0319166101006001600160a01b03881602179055600684905582516200006e906003906020860190620000a4565b50815162000084906004906020850190620000a4565b506005805460ff191660ff9290921691909117905550620002fb92505050565b828054620000b290620002a8565b90600052602060002090601f016020900481019282620000d6576000855562000121565b82601f10620000f157805160ff191683800117855562000121565b8280016001018555821562000121579182015b828111156200012157825182559160200191906001019062000104565b506200012f92915062000133565b5090565b5b808211156200012f576000815560010162000134565b600082601f8301126200015b578081fd5b81516001600160401b0380821115620001785762000178620002e5565b604051601f8301601f19908116603f01168101908282118183101715620001a357620001a3620002e5565b81604052838152602092508683858801011115620001bf578485fd5b8491505b83821015620001e25785820183015181830184015290820190620001c3565b83821115620001f357848385830101525b9695505050505050565b600080600080600060a0868803121562000215578081fd5b85516001600160a01b03811681146200022c578182fd5b6020870151604088015191965094506001600160401b038082111562000250578283fd5b6200025e89838a016200014a565b9450606088015191508082111562000274578283fd5b5062000283888289016200014a565b925050608086015160ff811681146200029a578182fd5b809150509295509295909350565b600181811c90821680620002bd57607f821691505b60208210811415620002df57634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052604160045260246000fd5b61071f806200030b6000396000f3fe608060405234801561001057600080fd5b50600436106101005760003560e01c80639dc29fac11610097578063e541efa211610066578063e541efa214610378578063e7ba6774146103e4578063ee4db5701461043e578063fdfe5f4d1461045e57600080fd5b80639dc29fac146102c7578063b4c4a4c814610306578063b9bb928c14610319578063bba0ad391461035857600080fd5b806340c10f19116100d357806340c10f19146101f05780636521b96a146102345780636f307dc31461027c57806395d89b41146102bf57600080fd5b806306fdde0314610105578063204f83f91461012357806323b872dd14610135578063313ce567146101d1575b600080fd5b61010d6104a3565b60405161011a9190610624565b60405180910390f35b6006545b60405190815260200161011a565b6101c1610143366004610588565b60408051808201825273ffffffffffffffffffffffffffffffffffffffff93841681526020808201938452948416600090815260029095529320925183547fffffffffffffffffffffffff00000000000000000000000000000000000000001692169190911782555160019091015560075462010000900460ff1690565b604051901515815260200161011a565b6005546101de9060ff1681565b60405160ff909116815260200161011a565b6101c16101fe3660046105c3565b73ffffffffffffffffffffffffffffffffffffffff91909116600090815260016020526040902055600754610100900460ff1690565b61027a6102423660046105ec565b6007805491151562010000027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff909216919091179055565b005b600554610100900473ffffffffffffffffffffffffffffffffffffffff1660405173ffffffffffffffffffffffffffffffffffffffff909116815260200161011a565b61010d610531565b6101c16102d53660046105c3565b73ffffffffffffffffffffffffffffffffffffffff9190911660009081526020819052604090205560075460ff1690565b61027a61031436600461060c565b600655565b61027a6103273660046105ec565b600780547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055565b610127610366366004610567565b60006020819052908152604090205481565b6103b8610386366004610567565b6002602052600090815260409020805460019091015473ffffffffffffffffffffffffffffffffffffffff9091169082565b6040805173ffffffffffffffffffffffffffffffffffffffff909316835260208301919091520161011a565b61027a6103f2366004610567565b6005805473ffffffffffffffffffffffffffffffffffffffff909216610100027fffffffffffffffffffffff0000000000000000000000000000000000000000ff909216919091179055565b61012761044c366004610567565b60016020526000908152604090205481565b61027a61046c3660046105ec565b60078054911515610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff909216919091179055565b600380546104b090610695565b80601f01602080910402602001604051908101604052809291908181526020018280546104dc90610695565b80156105295780601f106104fe57610100808354040283529160200191610529565b820191906000526020600020905b81548152906001019060200180831161050c57829003601f168201915b505050505081565b600480546104b090610695565b803573ffffffffffffffffffffffffffffffffffffffff8116811461056257600080fd5b919050565b600060208284031215610578578081fd5b6105818261053e565b9392505050565b60008060006060848603121561059c578182fd5b6105a58461053e565b92506105b36020850161053e565b9150604084013590509250925092565b600080604083850312156105d5578182fd5b6105de8361053e565b946020939093013593505050565b6000602082840312156105fd578081fd5b81358015158114610581578182fd5b60006020828403121561061d578081fd5b5035919050565b6000602080835283518082850152825b8181101561065057858101830151858201604001528201610634565b818111156106615783604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016929092016040019392505050565b600181811c908216806106a957607f821691505b602082108114156106e3577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b5091905056fea2646970667358221220eb8a5eef9e13a196e22e78e58517b46946db88220c910292ae27c5fcd5a37c2964736f6c63430008040033" + +// DeployZcToken deploys a new Ethereum contract, binding an instance of ZcToken to it. +func DeployZcToken(auth *bind.TransactOpts, backend bind.ContractBackend, u common.Address, m *big.Int, n string, s string, d uint8) (common.Address, *types.Transaction, *ZcToken, error) { + parsed, err := abi.JSON(strings.NewReader(ZcTokenABI)) + if err != nil { + return common.Address{}, nil, nil, err + } + + address, tx, contract, err := bind.DeployContract(auth, parsed, common.FromHex(ZcTokenBin), backend, u, m, n, s, d) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &ZcToken{ZcTokenCaller: ZcTokenCaller{contract: contract}, ZcTokenTransactor: ZcTokenTransactor{contract: contract}, ZcTokenFilterer: ZcTokenFilterer{contract: contract}}, nil +} + +// ZcToken is an auto generated Go binding around an Ethereum contract. +type ZcToken struct { + ZcTokenCaller // Read-only binding to the contract + ZcTokenTransactor // Write-only binding to the contract + ZcTokenFilterer // Log filterer for contract events +} + +// ZcTokenCaller is an auto generated read-only Go binding around an Ethereum contract. +type ZcTokenCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// ZcTokenTransactor is an auto generated write-only Go binding around an Ethereum contract. +type ZcTokenTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// ZcTokenFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type ZcTokenFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// ZcTokenSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type ZcTokenSession struct { + Contract *ZcToken // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// ZcTokenCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type ZcTokenCallerSession struct { + Contract *ZcTokenCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// ZcTokenTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type ZcTokenTransactorSession struct { + Contract *ZcTokenTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// ZcTokenRaw is an auto generated low-level Go binding around an Ethereum contract. +type ZcTokenRaw struct { + Contract *ZcToken // Generic contract binding to access the raw methods on +} + +// ZcTokenCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type ZcTokenCallerRaw struct { + Contract *ZcTokenCaller // Generic read-only contract binding to access the raw methods on +} + +// ZcTokenTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type ZcTokenTransactorRaw struct { + Contract *ZcTokenTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewZcToken creates a new instance of ZcToken, bound to a specific deployed contract. +func NewZcToken(address common.Address, backend bind.ContractBackend) (*ZcToken, error) { + contract, err := bindZcToken(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &ZcToken{ZcTokenCaller: ZcTokenCaller{contract: contract}, ZcTokenTransactor: ZcTokenTransactor{contract: contract}, ZcTokenFilterer: ZcTokenFilterer{contract: contract}}, nil +} + +// NewZcTokenCaller creates a new read-only instance of ZcToken, bound to a specific deployed contract. +func NewZcTokenCaller(address common.Address, caller bind.ContractCaller) (*ZcTokenCaller, error) { + contract, err := bindZcToken(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &ZcTokenCaller{contract: contract}, nil +} + +// NewZcTokenTransactor creates a new write-only instance of ZcToken, bound to a specific deployed contract. +func NewZcTokenTransactor(address common.Address, transactor bind.ContractTransactor) (*ZcTokenTransactor, error) { + contract, err := bindZcToken(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &ZcTokenTransactor{contract: contract}, nil +} + +// NewZcTokenFilterer creates a new log filterer instance of ZcToken, bound to a specific deployed contract. +func NewZcTokenFilterer(address common.Address, filterer bind.ContractFilterer) (*ZcTokenFilterer, error) { + contract, err := bindZcToken(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &ZcTokenFilterer{contract: contract}, nil +} + +// bindZcToken binds a generic wrapper to an already deployed contract. +func bindZcToken(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := abi.JSON(strings.NewReader(ZcTokenABI)) + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_ZcToken *ZcTokenRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _ZcToken.Contract.ZcTokenCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_ZcToken *ZcTokenRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _ZcToken.Contract.ZcTokenTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_ZcToken *ZcTokenRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _ZcToken.Contract.ZcTokenTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_ZcToken *ZcTokenCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _ZcToken.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_ZcToken *ZcTokenTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _ZcToken.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_ZcToken *ZcTokenTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _ZcToken.Contract.contract.Transact(opts, method, params...) +} + +// BurnCalled is a free data retrieval call binding the contract method 0xbba0ad39. +// +// Solidity: function burnCalled(address ) view returns(uint256) +func (_ZcToken *ZcTokenCaller) BurnCalled(opts *bind.CallOpts, arg0 common.Address) (*big.Int, error) { + var out []interface{} + err := _ZcToken.contract.Call(opts, &out, "burnCalled", arg0) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// BurnCalled is a free data retrieval call binding the contract method 0xbba0ad39. +// +// Solidity: function burnCalled(address ) view returns(uint256) +func (_ZcToken *ZcTokenSession) BurnCalled(arg0 common.Address) (*big.Int, error) { + return _ZcToken.Contract.BurnCalled(&_ZcToken.CallOpts, arg0) +} + +// BurnCalled is a free data retrieval call binding the contract method 0xbba0ad39. +// +// Solidity: function burnCalled(address ) view returns(uint256) +func (_ZcToken *ZcTokenCallerSession) BurnCalled(arg0 common.Address) (*big.Int, error) { + return _ZcToken.Contract.BurnCalled(&_ZcToken.CallOpts, arg0) +} + +// Decimals is a free data retrieval call binding the contract method 0x313ce567. +// +// Solidity: function decimals() view returns(uint8) +func (_ZcToken *ZcTokenCaller) Decimals(opts *bind.CallOpts) (uint8, error) { + var out []interface{} + err := _ZcToken.contract.Call(opts, &out, "decimals") + + if err != nil { + return *new(uint8), err + } + + out0 := *abi.ConvertType(out[0], new(uint8)).(*uint8) + + return out0, err + +} + +// Decimals is a free data retrieval call binding the contract method 0x313ce567. +// +// Solidity: function decimals() view returns(uint8) +func (_ZcToken *ZcTokenSession) Decimals() (uint8, error) { + return _ZcToken.Contract.Decimals(&_ZcToken.CallOpts) +} + +// Decimals is a free data retrieval call binding the contract method 0x313ce567. +// +// Solidity: function decimals() view returns(uint8) +func (_ZcToken *ZcTokenCallerSession) Decimals() (uint8, error) { + return _ZcToken.Contract.Decimals(&_ZcToken.CallOpts) +} + +// Maturity is a free data retrieval call binding the contract method 0x204f83f9. +// +// Solidity: function maturity() view returns(uint256) +func (_ZcToken *ZcTokenCaller) Maturity(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _ZcToken.contract.Call(opts, &out, "maturity") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// Maturity is a free data retrieval call binding the contract method 0x204f83f9. +// +// Solidity: function maturity() view returns(uint256) +func (_ZcToken *ZcTokenSession) Maturity() (*big.Int, error) { + return _ZcToken.Contract.Maturity(&_ZcToken.CallOpts) +} + +// Maturity is a free data retrieval call binding the contract method 0x204f83f9. +// +// Solidity: function maturity() view returns(uint256) +func (_ZcToken *ZcTokenCallerSession) Maturity() (*big.Int, error) { + return _ZcToken.Contract.Maturity(&_ZcToken.CallOpts) +} + +// MintCalled is a free data retrieval call binding the contract method 0xee4db570. +// +// Solidity: function mintCalled(address ) view returns(uint256) +func (_ZcToken *ZcTokenCaller) MintCalled(opts *bind.CallOpts, arg0 common.Address) (*big.Int, error) { + var out []interface{} + err := _ZcToken.contract.Call(opts, &out, "mintCalled", arg0) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// MintCalled is a free data retrieval call binding the contract method 0xee4db570. +// +// Solidity: function mintCalled(address ) view returns(uint256) +func (_ZcToken *ZcTokenSession) MintCalled(arg0 common.Address) (*big.Int, error) { + return _ZcToken.Contract.MintCalled(&_ZcToken.CallOpts, arg0) +} + +// MintCalled is a free data retrieval call binding the contract method 0xee4db570. +// +// Solidity: function mintCalled(address ) view returns(uint256) +func (_ZcToken *ZcTokenCallerSession) MintCalled(arg0 common.Address) (*big.Int, error) { + return _ZcToken.Contract.MintCalled(&_ZcToken.CallOpts, arg0) +} + +// Name is a free data retrieval call binding the contract method 0x06fdde03. +// +// Solidity: function name() view returns(string) +func (_ZcToken *ZcTokenCaller) Name(opts *bind.CallOpts) (string, error) { + var out []interface{} + err := _ZcToken.contract.Call(opts, &out, "name") + + if err != nil { + return *new(string), err + } + + out0 := *abi.ConvertType(out[0], new(string)).(*string) + + return out0, err + +} + +// Name is a free data retrieval call binding the contract method 0x06fdde03. +// +// Solidity: function name() view returns(string) +func (_ZcToken *ZcTokenSession) Name() (string, error) { + return _ZcToken.Contract.Name(&_ZcToken.CallOpts) +} + +// Name is a free data retrieval call binding the contract method 0x06fdde03. +// +// Solidity: function name() view returns(string) +func (_ZcToken *ZcTokenCallerSession) Name() (string, error) { + return _ZcToken.Contract.Name(&_ZcToken.CallOpts) +} + +// Symbol is a free data retrieval call binding the contract method 0x95d89b41. +// +// Solidity: function symbol() view returns(string) +func (_ZcToken *ZcTokenCaller) Symbol(opts *bind.CallOpts) (string, error) { + var out []interface{} + err := _ZcToken.contract.Call(opts, &out, "symbol") + + if err != nil { + return *new(string), err + } + + out0 := *abi.ConvertType(out[0], new(string)).(*string) + + return out0, err + +} + +// Symbol is a free data retrieval call binding the contract method 0x95d89b41. +// +// Solidity: function symbol() view returns(string) +func (_ZcToken *ZcTokenSession) Symbol() (string, error) { + return _ZcToken.Contract.Symbol(&_ZcToken.CallOpts) +} + +// Symbol is a free data retrieval call binding the contract method 0x95d89b41. +// +// Solidity: function symbol() view returns(string) +func (_ZcToken *ZcTokenCallerSession) Symbol() (string, error) { + return _ZcToken.Contract.Symbol(&_ZcToken.CallOpts) +} + +// TransferFromCalled is a free data retrieval call binding the contract method 0xe541efa2. +// +// Solidity: function transferFromCalled(address ) view returns(address to, uint256 amount) +func (_ZcToken *ZcTokenCaller) TransferFromCalled(opts *bind.CallOpts, arg0 common.Address) (struct { + To common.Address + Amount *big.Int +}, error) { + var out []interface{} + err := _ZcToken.contract.Call(opts, &out, "transferFromCalled", arg0) + + outstruct := new(struct { + To common.Address + Amount *big.Int + }) + if err != nil { + return *outstruct, err + } + + outstruct.To = out[0].(common.Address) + outstruct.Amount = out[1].(*big.Int) + + return *outstruct, err + +} + +// TransferFromCalled is a free data retrieval call binding the contract method 0xe541efa2. +// +// Solidity: function transferFromCalled(address ) view returns(address to, uint256 amount) +func (_ZcToken *ZcTokenSession) TransferFromCalled(arg0 common.Address) (struct { + To common.Address + Amount *big.Int +}, error) { + return _ZcToken.Contract.TransferFromCalled(&_ZcToken.CallOpts, arg0) +} + +// TransferFromCalled is a free data retrieval call binding the contract method 0xe541efa2. +// +// Solidity: function transferFromCalled(address ) view returns(address to, uint256 amount) +func (_ZcToken *ZcTokenCallerSession) TransferFromCalled(arg0 common.Address) (struct { + To common.Address + Amount *big.Int +}, error) { + return _ZcToken.Contract.TransferFromCalled(&_ZcToken.CallOpts, arg0) +} + +// Underlying is a free data retrieval call binding the contract method 0x6f307dc3. +// +// Solidity: function underlying() view returns(address) +func (_ZcToken *ZcTokenCaller) Underlying(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _ZcToken.contract.Call(opts, &out, "underlying") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// Underlying is a free data retrieval call binding the contract method 0x6f307dc3. +// +// Solidity: function underlying() view returns(address) +func (_ZcToken *ZcTokenSession) Underlying() (common.Address, error) { + return _ZcToken.Contract.Underlying(&_ZcToken.CallOpts) +} + +// Underlying is a free data retrieval call binding the contract method 0x6f307dc3. +// +// Solidity: function underlying() view returns(address) +func (_ZcToken *ZcTokenCallerSession) Underlying() (common.Address, error) { + return _ZcToken.Contract.Underlying(&_ZcToken.CallOpts) +} + +// Burn is a paid mutator transaction binding the contract method 0x9dc29fac. +// +// Solidity: function burn(address f, uint256 a) returns(bool) +func (_ZcToken *ZcTokenTransactor) Burn(opts *bind.TransactOpts, f common.Address, a *big.Int) (*types.Transaction, error) { + return _ZcToken.contract.Transact(opts, "burn", f, a) +} + +// Burn is a paid mutator transaction binding the contract method 0x9dc29fac. +// +// Solidity: function burn(address f, uint256 a) returns(bool) +func (_ZcToken *ZcTokenSession) Burn(f common.Address, a *big.Int) (*types.Transaction, error) { + return _ZcToken.Contract.Burn(&_ZcToken.TransactOpts, f, a) +} + +// Burn is a paid mutator transaction binding the contract method 0x9dc29fac. +// +// Solidity: function burn(address f, uint256 a) returns(bool) +func (_ZcToken *ZcTokenTransactorSession) Burn(f common.Address, a *big.Int) (*types.Transaction, error) { + return _ZcToken.Contract.Burn(&_ZcToken.TransactOpts, f, a) +} + +// BurnReturns is a paid mutator transaction binding the contract method 0xb9bb928c. +// +// Solidity: function burnReturns(bool b) returns() +func (_ZcToken *ZcTokenTransactor) BurnReturns(opts *bind.TransactOpts, b bool) (*types.Transaction, error) { + return _ZcToken.contract.Transact(opts, "burnReturns", b) +} + +// BurnReturns is a paid mutator transaction binding the contract method 0xb9bb928c. +// +// Solidity: function burnReturns(bool b) returns() +func (_ZcToken *ZcTokenSession) BurnReturns(b bool) (*types.Transaction, error) { + return _ZcToken.Contract.BurnReturns(&_ZcToken.TransactOpts, b) +} + +// BurnReturns is a paid mutator transaction binding the contract method 0xb9bb928c. +// +// Solidity: function burnReturns(bool b) returns() +func (_ZcToken *ZcTokenTransactorSession) BurnReturns(b bool) (*types.Transaction, error) { + return _ZcToken.Contract.BurnReturns(&_ZcToken.TransactOpts, b) +} + +// MaturityReturns is a paid mutator transaction binding the contract method 0xb4c4a4c8. +// +// Solidity: function maturityReturns(uint256 n) returns() +func (_ZcToken *ZcTokenTransactor) MaturityReturns(opts *bind.TransactOpts, n *big.Int) (*types.Transaction, error) { + return _ZcToken.contract.Transact(opts, "maturityReturns", n) +} + +// MaturityReturns is a paid mutator transaction binding the contract method 0xb4c4a4c8. +// +// Solidity: function maturityReturns(uint256 n) returns() +func (_ZcToken *ZcTokenSession) MaturityReturns(n *big.Int) (*types.Transaction, error) { + return _ZcToken.Contract.MaturityReturns(&_ZcToken.TransactOpts, n) +} + +// MaturityReturns is a paid mutator transaction binding the contract method 0xb4c4a4c8. +// +// Solidity: function maturityReturns(uint256 n) returns() +func (_ZcToken *ZcTokenTransactorSession) MaturityReturns(n *big.Int) (*types.Transaction, error) { + return _ZcToken.Contract.MaturityReturns(&_ZcToken.TransactOpts, n) +} + +// Mint is a paid mutator transaction binding the contract method 0x40c10f19. +// +// Solidity: function mint(address f, uint256 a) returns(bool) +func (_ZcToken *ZcTokenTransactor) Mint(opts *bind.TransactOpts, f common.Address, a *big.Int) (*types.Transaction, error) { + return _ZcToken.contract.Transact(opts, "mint", f, a) +} + +// Mint is a paid mutator transaction binding the contract method 0x40c10f19. +// +// Solidity: function mint(address f, uint256 a) returns(bool) +func (_ZcToken *ZcTokenSession) Mint(f common.Address, a *big.Int) (*types.Transaction, error) { + return _ZcToken.Contract.Mint(&_ZcToken.TransactOpts, f, a) +} + +// Mint is a paid mutator transaction binding the contract method 0x40c10f19. +// +// Solidity: function mint(address f, uint256 a) returns(bool) +func (_ZcToken *ZcTokenTransactorSession) Mint(f common.Address, a *big.Int) (*types.Transaction, error) { + return _ZcToken.Contract.Mint(&_ZcToken.TransactOpts, f, a) +} + +// MintReturns is a paid mutator transaction binding the contract method 0xfdfe5f4d. +// +// Solidity: function mintReturns(bool b) returns() +func (_ZcToken *ZcTokenTransactor) MintReturns(opts *bind.TransactOpts, b bool) (*types.Transaction, error) { + return _ZcToken.contract.Transact(opts, "mintReturns", b) +} + +// MintReturns is a paid mutator transaction binding the contract method 0xfdfe5f4d. +// +// Solidity: function mintReturns(bool b) returns() +func (_ZcToken *ZcTokenSession) MintReturns(b bool) (*types.Transaction, error) { + return _ZcToken.Contract.MintReturns(&_ZcToken.TransactOpts, b) +} + +// MintReturns is a paid mutator transaction binding the contract method 0xfdfe5f4d. +// +// Solidity: function mintReturns(bool b) returns() +func (_ZcToken *ZcTokenTransactorSession) MintReturns(b bool) (*types.Transaction, error) { + return _ZcToken.Contract.MintReturns(&_ZcToken.TransactOpts, b) +} + +// TransferFrom is a paid mutator transaction binding the contract method 0x23b872dd. +// +// Solidity: function transferFrom(address f, address t, uint256 a) returns(bool) +func (_ZcToken *ZcTokenTransactor) TransferFrom(opts *bind.TransactOpts, f common.Address, t common.Address, a *big.Int) (*types.Transaction, error) { + return _ZcToken.contract.Transact(opts, "transferFrom", f, t, a) +} + +// TransferFrom is a paid mutator transaction binding the contract method 0x23b872dd. +// +// Solidity: function transferFrom(address f, address t, uint256 a) returns(bool) +func (_ZcToken *ZcTokenSession) TransferFrom(f common.Address, t common.Address, a *big.Int) (*types.Transaction, error) { + return _ZcToken.Contract.TransferFrom(&_ZcToken.TransactOpts, f, t, a) +} + +// TransferFrom is a paid mutator transaction binding the contract method 0x23b872dd. +// +// Solidity: function transferFrom(address f, address t, uint256 a) returns(bool) +func (_ZcToken *ZcTokenTransactorSession) TransferFrom(f common.Address, t common.Address, a *big.Int) (*types.Transaction, error) { + return _ZcToken.Contract.TransferFrom(&_ZcToken.TransactOpts, f, t, a) +} + +// TransferFromReturns is a paid mutator transaction binding the contract method 0x6521b96a. +// +// Solidity: function transferFromReturns(bool b) returns() +func (_ZcToken *ZcTokenTransactor) TransferFromReturns(opts *bind.TransactOpts, b bool) (*types.Transaction, error) { + return _ZcToken.contract.Transact(opts, "transferFromReturns", b) +} + +// TransferFromReturns is a paid mutator transaction binding the contract method 0x6521b96a. +// +// Solidity: function transferFromReturns(bool b) returns() +func (_ZcToken *ZcTokenSession) TransferFromReturns(b bool) (*types.Transaction, error) { + return _ZcToken.Contract.TransferFromReturns(&_ZcToken.TransactOpts, b) +} + +// TransferFromReturns is a paid mutator transaction binding the contract method 0x6521b96a. +// +// Solidity: function transferFromReturns(bool b) returns() +func (_ZcToken *ZcTokenTransactorSession) TransferFromReturns(b bool) (*types.Transaction, error) { + return _ZcToken.Contract.TransferFromReturns(&_ZcToken.TransactOpts, b) +} + +// UnderlyingReturns is a paid mutator transaction binding the contract method 0xe7ba6774. +// +// Solidity: function underlyingReturns(address u) returns() +func (_ZcToken *ZcTokenTransactor) UnderlyingReturns(opts *bind.TransactOpts, u common.Address) (*types.Transaction, error) { + return _ZcToken.contract.Transact(opts, "underlyingReturns", u) +} + +// UnderlyingReturns is a paid mutator transaction binding the contract method 0xe7ba6774. +// +// Solidity: function underlyingReturns(address u) returns() +func (_ZcToken *ZcTokenSession) UnderlyingReturns(u common.Address) (*types.Transaction, error) { + return _ZcToken.Contract.UnderlyingReturns(&_ZcToken.TransactOpts, u) +} + +// UnderlyingReturns is a paid mutator transaction binding the contract method 0xe7ba6774. +// +// Solidity: function underlyingReturns(address u) returns() +func (_ZcToken *ZcTokenTransactorSession) UnderlyingReturns(u common.Address) (*types.Transaction, error) { + return _ZcToken.Contract.UnderlyingReturns(&_ZcToken.TransactOpts, u) +} diff --git a/gost/test/swivel/Abstracts.sol b/gost/test/swivel/Abstracts.sol new file mode 100644 index 0000000..1bd2f21 --- /dev/null +++ b/gost/test/swivel/Abstracts.sol @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: UNLICENSED + +pragma solidity 0.8.4; + +abstract contract Erc20 { + function approve(address, uint256) virtual external returns (bool); + function transfer(address, uint256) virtual external returns (bool); + function balanceOf(address) virtual external returns (uint256); + function transferFrom(address, address, uint256) virtual public returns (bool); +} + +abstract contract CErc20 is Erc20 { + function mint(uint256) virtual external returns (uint256); + function redeem(uint256) virtual external returns (uint256); + function redeemUnderlying(uint256) virtual external returns (uint256); + function exchangeRateCurrent() virtual external returns (uint256); +} + +abstract contract MarketPlace { + // adds notional and mints zctokens + function mintZcTokenAddingNotional(address, uint256, address, uint256) virtual external returns (bool); + // removes notional and burns zctokens + function burnZcTokenRemovingNotional(address, uint256, address, uint256) virtual external returns (bool); + // returns the amount of underlying principal to send + function redeemZcToken(address, uint256, address, uint256) virtual external returns (uint256); + // returns the amount of underlying interest to send + function redeemVaultInterest(address, uint256, address) virtual external returns (uint256); + // returns the cToken address for a given market + function cTokenAddress(address, uint256) virtual external returns (address); + // EVFZE FF EZFVE call this which would then burn zctoken and remove notional + function custodialExit(address, uint256, address, address, uint256) virtual external returns (bool); + // IVFZI && IZFVI call this which would then mint zctoken and add notional + function custodialInitiate(address, uint256, address, address, uint256) virtual external returns (bool); + // IZFZE && EZFZI call this, tranferring zctoken from one party to another + function p2pZcTokenExchange(address, uint256, address, address, uint256) virtual external returns (bool); + // IVFVE && EVFVI call this, removing notional from one party and adding to the other + function p2pVaultExchange(address, uint256, address, address, uint256) virtual external returns (bool); + // IVFZI && IVFVE call this which then transfers notional from msg.sender (taker) to swivel + function transferVaultNotionalFee(address, uint256, address, uint256) virtual external returns (bool); +} diff --git a/gost/test/swivel/CErc20.abi b/gost/test/swivel/CErc20.abi new file mode 100644 index 0000000..03e1ca1 --- /dev/null +++ b/gost/test/swivel/CErc20.abi @@ -0,0 +1 @@ +[{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"exchangeRateCurrent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"mint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"redeem","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"redeemUnderlying","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file diff --git a/gost/test/swivel/CErc20.bin b/gost/test/swivel/CErc20.bin new file mode 100644 index 0000000..e69de29 diff --git a/gost/test/swivel/Erc20.abi b/gost/test/swivel/Erc20.abi new file mode 100644 index 0000000..88abe05 --- /dev/null +++ b/gost/test/swivel/Erc20.abi @@ -0,0 +1 @@ +[{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file diff --git a/gost/test/swivel/Erc20.bin b/gost/test/swivel/Erc20.bin new file mode 100644 index 0000000..e69de29 diff --git a/gost/test/swivel/Hash.abi b/gost/test/swivel/Hash.abi new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/gost/test/swivel/Hash.abi @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/gost/test/swivel/Hash.bin b/gost/test/swivel/Hash.bin new file mode 100644 index 0000000..cad2ae0 --- /dev/null +++ b/gost/test/swivel/Hash.bin @@ -0,0 +1 @@ +60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea264697066735822122054cd7351b54950151a8593f59ef863373f17bba93179111e3b59a9f319776b0f64736f6c63430008040033 \ No newline at end of file diff --git a/gost/test/swivel/Hash.sol b/gost/test/swivel/Hash.sol new file mode 100644 index 0000000..9cfefb2 --- /dev/null +++ b/gost/test/swivel/Hash.sol @@ -0,0 +1,107 @@ +// SPDX-License-Identifier: UNLICENSED + +pragma solidity 0.8.4; + +/** + @notice Encapsulation of the logic to produce EIP712 hashed domain and messages. + Also to produce / verify hashed and signed Orders. + See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-712.md + See/attribute https://github.com/0xProject/0x-monorepo/blob/development/contracts/utils/contracts/src/LibEIP712.sol +*/ + +library Hash { + /// @dev struct represents the attributes of an offchain Swivel.Order + struct Order { + bytes32 key; + address maker; + address underlying; + bool vault; + bool exit; + uint256 principal; + uint256 premium; + uint256 maturity; + uint256 expiry; + } + + // EIP712 Domain Separator typeHash + // keccak256(abi.encodePacked( + // 'EIP712Domain(', + // 'string name,', + // 'string version,', + // 'uint256 chainId,', + // 'address verifyingContract', + // ')' + // )); + bytes32 constant internal DOMAIN_TYPEHASH = 0x8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f; + + // EIP712 typeHash of an Order + // keccak256(abi.encodePacked( + // 'Order(', + // 'bytes32 key,', + // 'address maker,', + // 'address underlying,', + // 'bool vault,', + // 'bool exit,', + // 'uint256 principal,', + // 'uint256 premium,', + // 'uint256 maturity,', + // 'uint256 expiry', + // ')' + // )); + bytes32 constant internal ORDER_TYPEHASH = 0x7ddd38ab5ed1c16b61ca90eeb9579e29da1ba821cf42d8cdef8f30a31a6a4146; + + /// @param n EIP712 domain name + /// @param version EIP712 semantic version string + /// @param i Chain ID + /// @param verifier address of the verifying contract + function domain(string memory n, string memory version, uint256 i, address verifier) internal pure returns (bytes32) { + bytes32 hash; + + assembly { + let nameHash := keccak256(add(n, 32), mload(n)) + let versionHash := keccak256(add(version, 32), mload(version)) + let pointer := mload(64) + mstore(pointer, DOMAIN_TYPEHASH) + mstore(add(pointer, 32), nameHash) + mstore(add(pointer, 64), versionHash) + mstore(add(pointer, 96), i) + mstore(add(pointer, 128), verifier) + hash := keccak256(pointer, 160) + } + + return hash; + } + + /// @param d Type hash of the domain separator (see Hash.domain) + /// @param h EIP712 hash struct (order for example) + function message(bytes32 d, bytes32 h) internal pure returns (bytes32) { + bytes32 hash; + + assembly { + let pointer := mload(64) + mstore(pointer, 0x1901000000000000000000000000000000000000000000000000000000000000) + mstore(add(pointer, 2), d) + mstore(add(pointer, 34), h) + hash := keccak256(pointer, 66) + } + + return hash; + } + + /// @param o A Swivel Order + function order(Order calldata o) internal pure returns (bytes32) { + // TODO assembly + return keccak256(abi.encode( + ORDER_TYPEHASH, + o.key, + o.maker, + o.underlying, + o.vault, + o.exit, + o.principal, + o.premium, + o.maturity, + o.expiry + )); + } +} diff --git a/gost/test/swivel/MarketPlace.abi b/gost/test/swivel/MarketPlace.abi new file mode 100644 index 0000000..6cc9d61 --- /dev/null +++ b/gost/test/swivel/MarketPlace.abi @@ -0,0 +1 @@ +[{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"burnZcTokenRemovingNotional","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"cTokenAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"custodialExit","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"custodialInitiate","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"mintZcTokenAddingNotional","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"p2pVaultExchange","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"p2pZcTokenExchange","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"}],"name":"redeemVaultInterest","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"redeemZcToken","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"transferVaultNotionalFee","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file diff --git a/gost/test/swivel/MarketPlace.bin b/gost/test/swivel/MarketPlace.bin new file mode 100644 index 0000000..e69de29 diff --git a/gost/test/swivel/Sig.abi b/gost/test/swivel/Sig.abi new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/gost/test/swivel/Sig.abi @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/gost/test/swivel/Sig.bin b/gost/test/swivel/Sig.bin new file mode 100644 index 0000000..945f351 --- /dev/null +++ b/gost/test/swivel/Sig.bin @@ -0,0 +1 @@ +60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220d93f66bcb0b1e22a51c317c540712f6842cb2afd7aed60c29f6c1703f45fd41764736f6c63430008040033 \ No newline at end of file diff --git a/gost/test/swivel/Sig.sol b/gost/test/swivel/Sig.sol new file mode 100644 index 0000000..c80008f --- /dev/null +++ b/gost/test/swivel/Sig.sol @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: UNLICENSED + +pragma solidity 0.8.4; + +library Sig { + /// @dev ECDSA V,R and S components encapsulated here as we may not always be able to accept a bytes signature + struct Components { + uint8 v; + bytes32 r; + bytes32 s; + } + + /// @param h Hashed data which was originally signed + /// @param c signature struct containing V,R and S + /// @return The recovered address + function recover(bytes32 h, Components calldata c) internal pure returns (address) { + // EIP-2 and malleable signatures... + // see https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/cryptography/ECDSA.sol + require(uint256(c.s) <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0, 'invalid signature "s" value'); + require(c.v == 27 || c.v == 28, 'invalid signature "v" value'); + + return ecrecover(h, c.v, c.r, c.s); + } + + /// @param h Hashed data which was originally signed + /// @param sig Valid ECDSA signature + /// @dev splitAndRecover should only be used if it is known that the resulting + /// verifying bit (V) will be 27 || 28. Otherwise use recover, possibly calling split first. + /// @return The recovered address + function splitAndRecover(bytes32 h, bytes memory sig) internal pure returns (address) { + (uint8 v, bytes32 r, bytes32 s) = split(sig); + + return ecrecover(h, v, r, s); + } + + /// @param sig Valid ECDSA signature + /// @return v The verification bit + /// @return r First 32 bytes + /// @return s Next 32 bytes + function split(bytes memory sig) internal pure returns (uint8, bytes32, bytes32) { + require(sig.length == 65, 'invalid signature length'); // TODO standardize error messages + + bytes32 r; + bytes32 s; + uint8 v; + + assembly { + r := mload(add(sig, 32)) + s := mload(add(sig, 64)) + v := byte(0, mload(add(sig, 96))) + } + + return (v, r, s); + } +} diff --git a/gost/test/swivel/Swivel.abi b/gost/test/swivel/Swivel.abi new file mode 100644 index 0000000..d834fdd --- /dev/null +++ b/gost/test/swivel/Swivel.abi @@ -0,0 +1 @@ +[{"inputs":[{"internalType":"address","name":"m","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"key","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"hash","type":"bytes32"}],"name":"Cancel","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"key","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"hash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"maker","type":"address"},{"indexed":false,"internalType":"bool","name":"vault","type":"bool"},{"indexed":false,"internalType":"bool","name":"exit","type":"bool"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"filled","type":"uint256"}],"name":"Exit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"key","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"hash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"maker","type":"address"},{"indexed":false,"internalType":"bool","name":"vault","type":"bool"},{"indexed":false,"internalType":"bool","name":"exit","type":"bool"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"filled","type":"uint256"}],"name":"Initiate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"hold","type":"uint256"}],"name":"WithdrawalScheduled","type":"event"},{"inputs":[],"name":"HOLD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"NAME","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"VERSION","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"admin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"e","type":"address"}],"name":"blockWithdrawal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"key","type":"bytes32"},{"internalType":"address","name":"maker","type":"address"},{"internalType":"address","name":"underlying","type":"address"},{"internalType":"bool","name":"vault","type":"bool"},{"internalType":"bool","name":"exit","type":"bool"},{"internalType":"uint256","name":"principal","type":"uint256"},{"internalType":"uint256","name":"premium","type":"uint256"},{"internalType":"uint256","name":"maturity","type":"uint256"},{"internalType":"uint256","name":"expiry","type":"uint256"}],"internalType":"struct Hash.Order","name":"o","type":"tuple"},{"components":[{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct Sig.Components","name":"c","type":"tuple"}],"name":"cancel","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"cancelled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"u","type":"address"},{"internalType":"uint256","name":"m","type":"uint256"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"combineTokens","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"domain","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"key","type":"bytes32"},{"internalType":"address","name":"maker","type":"address"},{"internalType":"address","name":"underlying","type":"address"},{"internalType":"bool","name":"vault","type":"bool"},{"internalType":"bool","name":"exit","type":"bool"},{"internalType":"uint256","name":"principal","type":"uint256"},{"internalType":"uint256","name":"premium","type":"uint256"},{"internalType":"uint256","name":"maturity","type":"uint256"},{"internalType":"uint256","name":"expiry","type":"uint256"}],"internalType":"struct Hash.Order[]","name":"o","type":"tuple[]"},{"internalType":"uint256[]","name":"a","type":"uint256[]"},{"components":[{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct Sig.Components[]","name":"c","type":"tuple[]"}],"name":"exit","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"fenominator","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"filled","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"key","type":"bytes32"},{"internalType":"address","name":"maker","type":"address"},{"internalType":"address","name":"underlying","type":"address"},{"internalType":"bool","name":"vault","type":"bool"},{"internalType":"bool","name":"exit","type":"bool"},{"internalType":"uint256","name":"principal","type":"uint256"},{"internalType":"uint256","name":"premium","type":"uint256"},{"internalType":"uint256","name":"maturity","type":"uint256"},{"internalType":"uint256","name":"expiry","type":"uint256"}],"internalType":"struct Hash.Order[]","name":"o","type":"tuple[]"},{"internalType":"uint256[]","name":"a","type":"uint256[]"},{"components":[{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct Sig.Components[]","name":"c","type":"tuple[]"}],"name":"initiate","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"marketPlace","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"u","type":"address"},{"internalType":"uint256","name":"m","type":"uint256"}],"name":"redeemVaultInterest","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"u","type":"address"},{"internalType":"uint256","name":"m","type":"uint256"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"redeemZcToken","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"e","type":"address"}],"name":"scheduleWithdrawal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"t","type":"uint16"},{"internalType":"uint16","name":"d","type":"uint16"}],"name":"setFee","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"u","type":"address"},{"internalType":"uint256","name":"m","type":"uint256"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"splitUnderlying","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"e","type":"address"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"withdrawals","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}] \ No newline at end of file diff --git a/gost/test/swivel/Swivel.bin b/gost/test/swivel/Swivel.bin new file mode 100644 index 0000000..36d8502 --- /dev/null +++ b/gost/test/swivel/Swivel.bin @@ -0,0 +1 @@ +60e06040523480156200001157600080fd5b50604051620054a7380380620054a7833981016040819052620000349162000206565b3360601b60c052604080518082018252600e81526d53776976656c2046696e616e636560901b602080830191909152825180840190935260058352640322e302e360dc1b838201526200009592904690309062001caa620000e8821b17901c565b6080908152606082811b6001600160601b03191660a05260408051928301815260c880845261025860208501526101909184019190915290820152620000e09060039060046200013f565b505062000236565b8351602094850120835193850193909320604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f815295860194909452928401929092526060830152608082015260a0902090565b82805482825590600052602060002090600f01601090048101928215620001dd5791602002820160005b83821115620001ab57835183826101000a81548161ffff021916908361ffff160217905550926020019260020160208160010104928301926001030262000169565b8015620001db5782816101000a81549061ffff0219169055600201602081600101049283019260010302620001ab565b505b50620001eb929150620001ef565b5090565b5b80821115620001eb5760008155600101620001f0565b60006020828403121562000218578081fd5b81516001600160a01b03811681146200022f578182fd5b9392505050565b60805160a05160601c60c05160601c6151bd620002ea600039600081816103a601528181610e1b01528181610f9a015281816114b7015281816115900152611bc601526000818161020d01528181610466015281816107d301528181610b8801528181611198015281816121a101528181612659015281816128f601528181612f5f0152818161362901528181613dfd015281816143cf01526147cd0152600081816103620152611dec01526151bd6000f3fe608060405234801561001057600080fd5b50600436106101775760003560e01c806392ae3764116100d8578063c2fb26a61161008c578063f851a44011610066578063f851a440146103a1578063f8eaad35146103c8578063ffa1ad74146103db57600080fd5b8063c2fb26a61461035d578063d0886f9714610384578063d2144f581461038e57600080fd5b8063a102e384116100bd578063a102e384146102ee578063a3f4df7e14610301578063aba287011461034a57600080fd5b806392ae3764146102c857806399b64de1146102db57600080fd5b806333c810e91161012f57806340d37cdf1161011457806340d37cdf1461028057806351cff8d9146102935780637a9262a2146102a857600080fd5b806333c810e9146102475780633e1608b41461026d57600080fd5b8063288cdc9111610160578063288cdc91146101b75780632ac12622146101e55780632e25d2a61461020857600080fd5b80630908ff2d1461017c578063154e0f2e146101a4575b600080fd5b61018f61018a366004614e03565b610417565b60405190151581526020015b60405180910390f35b61018f6101b2366004614e03565b610784565b6101d76101c5366004614f31565b60016020526000908152604090205481565b60405190815260200161019b565b61018f6101f3366004614f31565b60006020819052908152604090205460ff1681565b61022f7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b03909116815260200161019b565b61025a610255366004614f31565b610a0b565b60405161ffff909116815260200161019b565b61018f61027b366004614f49565b610a43565b61018f61028e366004614dd8565b610b40565b6102a66102a1366004614da0565b610e19565b005b6101d76102b6366004614da0565b60026020526000908152604090205481565b61018f6102d6366004614e03565b6110b4565b61018f6102e9366004614faa565b6114b3565b6102a66102fc366004614da0565b61158e565b61033d6040518060400160405280600e81526020017f53776976656c2046696e616e636500000000000000000000000000000000000081525081565b60405161019b9190615015565b61018f610358366004614e37565b611622565b6101d77f000000000000000000000000000000000000000000000000000000000000000081565b6101d76203f48081565b61018f61039c366004614e37565b6118fa565b61022f7f000000000000000000000000000000000000000000000000000000000000000081565b6102a66103d6366004614da0565b611bc4565b61033d6040518060400160405280600581526020017f322e302e3000000000000000000000000000000000000000000000000000000081525081565b6040517fb50a66f70000000000000000000000000000000000000000000000000000000081526001600160a01b03848116600483015260248201849052336044830152606482018390526000917f00000000000000000000000000000000000000000000000000000000000000009182169063b50a66f790608401602060405180830381600087803b1580156104ac57600080fd5b505af11580156104c0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104e49190614f15565b61055b5760405162461bcd60e51b815260206004820152602560248201527f6275726e205a63546f6b656e2072656d6f76696e67204e6f74696f6e616c206660448201527f61696c656400000000000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b6040517f05e1dc250000000000000000000000000000000000000000000000000000000081526001600160a01b03868116600483015260248201869052600091908316906305e1dc2590604401602060405180830381600087803b1580156105c257600080fd5b505af11580156105d6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105fa9190614dbc565b6040517f852a12e3000000000000000000000000000000000000000000000000000000008152600481018690529091506001600160a01b0382169063852a12e390602401602060405180830381600087803b15801561065857600080fd5b505af115801561066c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106909190614fdc565b156106dd5760405162461bcd60e51b815260206004820152601960248201527f636f6d706f756e6420726564656d7074696f6e206572726f72000000000000006044820152606401610552565b6040517fa9059cbb000000000000000000000000000000000000000000000000000000008152336004820152602481018590526001600160a01b0387169063a9059cbb906044015b602060405180830381600087803b15801561073f57600080fd5b505af1158015610753573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107779190614f15565b5060019695505050505050565b6040517fc5ee114d0000000000000000000000000000000000000000000000000000000081526001600160a01b03848116600483015260248201849052336044830152606482018390526000917f00000000000000000000000000000000000000000000000000000000000000009183919083169063c5ee114d90608401602060405180830381600087803b15801561081c57600080fd5b505af1158015610830573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108549190614fdc565b6040517f05e1dc250000000000000000000000000000000000000000000000000000000081526001600160a01b03888116600483015260248201889052919250908316906305e1dc2590604401602060405180830381600087803b1580156108bb57600080fd5b505af11580156108cf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108f39190614dbc565b6001600160a01b031663852a12e3826040518263ffffffff1660e01b815260040161092091815260200190565b602060405180830381600087803b15801561093a57600080fd5b505af115801561094e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109729190614fdc565b156109bf5760405162461bcd60e51b815260206004820152601a60248201527f636f6d706f756e6420726564656d7074696f6e206661696c65640000000000006044820152606401610552565b6040517fa9059cbb000000000000000000000000000000000000000000000000000000008152336004820152602481018290526001600160a01b0387169063a9059cbb90604401610725565b60038181548110610a1b57600080fd5b9060005260206000209060109182820401919006600202915054906101000a900461ffff1681565b600080610a508484611d01565b9050610a626040850160208601614da0565b6001600160a01b0316336001600160a01b031614610ac25760405162461bcd60e51b815260206004820152601460248201527f73656e646572206d757374206265206d616b65720000000000000000000000006044820152606401610552565b6000818152602081905260409081902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055518435907f9e5d8891dc1b047de610617bc9bc2d8ccffebbc3d63363431a546831245858a690610b2e9084815260200190565b60405180910390a25060019392505050565b6040517fa11f48560000000000000000000000000000000000000000000000000000000081526001600160a01b038381166004830152602482018390523360448301526000917f00000000000000000000000000000000000000000000000000000000000000009183919083169063a11f485690606401602060405180830381600087803b158015610bd157600080fd5b505af1158015610be5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c099190614fdc565b6040517f05e1dc250000000000000000000000000000000000000000000000000000000081526001600160a01b03878116600483015260248201879052919250908316906305e1dc2590604401602060405180830381600087803b158015610c7057600080fd5b505af1158015610c84573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ca89190614dbc565b6001600160a01b031663852a12e3826040518263ffffffff1660e01b8152600401610cd591815260200190565b602060405180830381600087803b158015610cef57600080fd5b505af1158015610d03573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d279190614fdc565b15610d745760405162461bcd60e51b815260206004820152601a60248201527f636f6d706f756e6420726564656d7074696f6e206661696c65640000000000006044820152606401610552565b6040517fa9059cbb000000000000000000000000000000000000000000000000000000008152336004820152602481018290526001600160a01b0386169063a9059cbb90604401602060405180830381600087803b158015610dd557600080fd5b505af1158015610de9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e0d9190614f15565b50600195945050505050565b7f0000000000000000000000000000000000000000000000000000000000000000336001600160a01b03821614610e925760405162461bcd60e51b815260206004820152601460248201527f73656e646572206d7573742062652061646d696e0000000000000000000000006044820152606401610552565b6001600160a01b03821660009081526002602052604090205480610ef85760405162461bcd60e51b815260206004820152601760248201527f6e6f207769746864726177616c207363686564756c65640000000000000000006044820152606401610552565b80421015610f485760405162461bcd60e51b815260206004820152601860248201527f7769746864726177616c207374696c6c206f6e20686f6c6400000000000000006044820152606401610552565b6001600160a01b03831660008181526002602052604080822091909155517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015284919063a9059cbb907f00000000000000000000000000000000000000000000000000000000000000009083906370a0823190602401602060405180830381600087803b158015610fdf57600080fd5b505af1158015610ff3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110179190614fdc565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381600087803b15801561107557600080fd5b505af1158015611089573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110ad9190614f15565b5050505050565b6040517f23b872dd0000000000000000000000000000000000000000000000000000000081523360048201523060248201526044810182905260009084906001600160a01b038216906323b872dd90606401602060405180830381600087803b15801561112057600080fd5b505af1158015611134573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111589190614f15565b506040517f05e1dc250000000000000000000000000000000000000000000000000000000081526001600160a01b038681166004830152602482018690527f0000000000000000000000000000000000000000000000000000000000000000916000918316906305e1dc2590604401602060405180830381600087803b1580156111e157600080fd5b505af11580156111f5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112199190614dbc565b6040517f095ea7b30000000000000000000000000000000000000000000000000000000081526001600160a01b038083166004830152602482018890529192509084169063095ea7b390604401602060405180830381600087803b15801561128057600080fd5b505af1158015611294573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112b89190614f15565b506040517fa0712d68000000000000000000000000000000000000000000000000000000008152600481018690526001600160a01b0382169063a0712d6890602401602060405180830381600087803b15801561131457600080fd5b505af1158015611328573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061134c9190614fdc565b156113995760405162461bcd60e51b815260206004820152601560248201527f6d696e74696e672043546f6b656e204661696c656400000000000000000000006044820152606401610552565b6040517fef267f2c0000000000000000000000000000000000000000000000000000000081526001600160a01b038881166004830152602482018890523360448301526064820187905283169063ef267f2c90608401602060405180830381600087803b15801561140957600080fd5b505af115801561141d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114419190614f15565b6107775760405162461bcd60e51b815260206004820152602360248201527f6d696e74205a63546f6b656e20616464696e67204e6f74696f6e616c2066616960448201527f6c656400000000000000000000000000000000000000000000000000000000006064820152608401610552565b60007f0000000000000000000000000000000000000000000000000000000000000000336001600160a01b0382161461152e5760405162461bcd60e51b815260206004820152601460248201527f73656e646572206d7573742062652061646d696e0000000000000000000000006044820152606401610552565b8260038561ffff168154811061155457634e487b7160e01b600052603260045260246000fd5b90600052602060002090601091828204019190066002026101000a81548161ffff021916908361ffff160217905550600191505092915050565b7f0000000000000000000000000000000000000000000000000000000000000000336001600160a01b038216146116075760405162461bcd60e51b815260206004820152601460248201527f73656e646572206d7573742062652061646d696e0000000000000000000000006044820152606401610552565b506001600160a01b0316600090815260026020526040812055565b6000805b868110156118ec5787878281811061164e57634e487b7160e01b600052603260045260246000fd5b9050610120020160800160208101906116679190614ef9565b6117a55787878281811061168b57634e487b7160e01b600052603260045260246000fd5b9050610120020160600160208101906116a49190614ef9565b611729576117248888838181106116cb57634e487b7160e01b600052603260045260246000fd5b905061012002018787848181106116f257634e487b7160e01b600052603260045260246000fd5b9050602002013586868581811061171957634e487b7160e01b600052603260045260246000fd5b905060600201611e9b565b6118da565b61172488888381811061174c57634e487b7160e01b600052603260045260246000fd5b9050610120020187878481811061177357634e487b7160e01b600052603260045260246000fd5b9050602002013586868581811061179a57634e487b7160e01b600052603260045260246000fd5b90506060020161237d565b8787828181106117c557634e487b7160e01b600052603260045260246000fd5b9050610120020160600160208101906117de9190614ef9565b61185e5761172488888381811061180557634e487b7160e01b600052603260045260246000fd5b9050610120020187878481811061182c57634e487b7160e01b600052603260045260246000fd5b9050602002013586868581811061185357634e487b7160e01b600052603260045260246000fd5b9050606002016127a0565b6118da88888381811061188157634e487b7160e01b600052603260045260246000fd5b905061012002018787848181106118a857634e487b7160e01b600052603260045260246000fd5b905060200201358686858181106118cf57634e487b7160e01b600052603260045260246000fd5b905060600201612e08565b806118e481615112565b915050611626565b506001979650505050505050565b6000805b868110156118ec5787878281811061192657634e487b7160e01b600052603260045260246000fd5b90506101200201608001602081019061193f9190614ef9565b611a7d5787878281811061196357634e487b7160e01b600052603260045260246000fd5b90506101200201606001602081019061197c9190614ef9565b611a01576119fc8888838181106119a357634e487b7160e01b600052603260045260246000fd5b905061012002018787848181106119ca57634e487b7160e01b600052603260045260246000fd5b905060200201358686858181106119f157634e487b7160e01b600052603260045260246000fd5b905060600201613340565b611bb2565b6119fc888883818110611a2457634e487b7160e01b600052603260045260246000fd5b90506101200201878784818110611a4b57634e487b7160e01b600052603260045260246000fd5b90506020020135868685818110611a7257634e487b7160e01b600052603260045260246000fd5b905060600201613b19565b878782818110611a9d57634e487b7160e01b600052603260045260246000fd5b905061012002016060016020810190611ab69190614ef9565b611b36576119fc888883818110611add57634e487b7160e01b600052603260045260246000fd5b90506101200201878784818110611b0457634e487b7160e01b600052603260045260246000fd5b90506020020135868685818110611b2b57634e487b7160e01b600052603260045260246000fd5b90506060020161418c565b611bb2888883818110611b5957634e487b7160e01b600052603260045260246000fd5b90506101200201878784818110611b8057634e487b7160e01b600052603260045260246000fd5b90506020020135868685818110611ba757634e487b7160e01b600052603260045260246000fd5b9050606002016145a7565b80611bbc81615112565b9150506118fe565b7f0000000000000000000000000000000000000000000000000000000000000000336001600160a01b03821614611c3d5760405162461bcd60e51b815260206004820152601460248201527f73656e646572206d7573742062652061646d696e0000000000000000000000006044820152606401610552565b6000611c4c6203f48042615086565b6001600160a01b0384166000818152600260205260409081902083905551919250907fd9cf0116e5bb6fbe3d257dc8d1ee7ae76c303efeae77f1e93024d2cb218bedd390611c9d9084815260200190565b60405180910390a2505050565b8351602094850120835193850193909320604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f815295860194909452928401929092526060830152608082015260a0902090565b600080611d0d84614a7b565b60008181526020819052604090205490915060ff1615611d6f5760405162461bcd60e51b815260206004820152600f60248201527f6f726465722063616e63656c6c656400000000000000000000000000000000006044820152606401610552565b428461010001351015611dc45760405162461bcd60e51b815260206004820152600d60248201527f6f726465722065787069726564000000000000000000000000000000000000006044820152606401610552565b6040517f190100000000000000000000000000000000000000000000000000000000000081527f000000000000000000000000000000000000000000000000000000000000000060028201526022810182905260429020611e259084614b79565b6001600160a01b0316611e3e6040860160208701614da0565b6001600160a01b031614611e945760405162461bcd60e51b815260206004820152601160248201527f696e76616c6964207369676e61747572650000000000000000000000000000006044820152606401610552565b9392505050565b6000611ea78483611d01565b600081815260016020526040902054909150611ec79060c08601356150fb565b831115611f165760405162461bcd60e51b815260206004820152601f60248201527f74616b657220616d6f756e74203e20617661696c61626c6520766f6c756d65006044820152606401610552565b60008181526001602052604081208054859290611f34908490615086565b9091555060009050670de0b6b3a764000060a086013560c0870135611f5987846150be565b611f63919061509e565b611f6d91906150be565b611f77919061509e565b90506000670de0b6b3a76400006003600181548110611fa657634e487b7160e01b600052603260045260246000fd5b60009182526020909120601082040154600f9091166002026101000a900461ffff16611fda84670de0b6b3a76400006150be565b611fe4919061509e565b611fee919061509e565b905060006120026060880160408901614da0565b90506001600160a01b0381166323b872dd61202360408a0160208b01614da0565b338561202f8b896150fb565b61203991906150fb565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b1681526001600160a01b0393841660048201529290911660248301526044820152606401602060405180830381600087803b1580156120a057600080fd5b505af11580156120b4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120d89190614f15565b506001600160a01b0381166323b872dd6120f860408a0160208b01614da0565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b03909116600482015230602482015260448101859052606401602060405180830381600087803b15801561215e57600080fd5b505af1158015612172573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121969190614f15565b506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166365a963aa6121d660608a0160408b01614da0565b60e08a0135336121ec60408d0160208e01614da0565b60405160e086901b7fffffffff000000000000000000000000000000000000000000000000000000001681526001600160a01b0394851660048201526024810193909352908316604483015290911660648201526084810186905260a401602060405180830381600087803b15801561226457600080fd5b505af1158015612278573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061229c9190614f15565b6122e85760405162461bcd60e51b815260206004820152601760248201527f7a63546f6b656e2065786368616e6765206661696c65640000000000000000006044820152606401610552565b336122f96040890160208a01614da0565b6001600160a01b031688357f51cad9177cf46d59109ae978bb3cf5ffed2bb3d53fb3682fa56fbd92667128348761233660808d0160608e01614ef9565b61234660a08e0160808f01614ef9565b604080519384529115156020840152151590820152606081018b90526080810188905260a00160405180910390a450505050505050565b60006123898483611d01565b6000818152600160205260409020549091506123a99060a08601356150fb565b8311156123f85760405162461bcd60e51b815260206004820152601f60248201527f74616b657220616d6f756e74203e20617661696c61626c6520766f6c756d65006044820152606401610552565b60008181526001602052604081208054859290612416908490615086565b9091555060009050670de0b6b3a764000060c086013560a087013561243b87846150be565b612445919061509e565b61244f91906150be565b612459919061509e565b90506000670de0b6b3a76400006003808154811061248757634e487b7160e01b600052603260045260246000fd5b60009182526020909120601082040154600f9091166002026101000a900461ffff166124bb84670de0b6b3a76400006150be565b6124c5919061509e565b6124cf919061509e565b905060006124e36060880160408901614da0565b90506001600160a01b0381166323b872dd61250460408a0160208b01614da0565b3361250f86886150fb565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b1681526001600160a01b0393841660048201529290911660248301526044820152606401602060405180830381600087803b15801561257657600080fd5b505af115801561258a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125ae9190614f15565b506040517f23b872dd000000000000000000000000000000000000000000000000000000008152336004820152306024820152604481018390526001600160a01b038216906323b872dd90606401602060405180830381600087803b15801561261657600080fd5b505af115801561262a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061264e9190614f15565b506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663bddbfbe461268e60608a0160408b01614da0565b60e08a0135336126a460408d0160208e01614da0565b60405160e086901b7fffffffff000000000000000000000000000000000000000000000000000000001681526001600160a01b0394851660048201526024810193909352908316604483015290911660648201526084810189905260a401602060405180830381600087803b15801561271c57600080fd5b505af1158015612730573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127549190614f15565b6122e85760405162461bcd60e51b815260206004820152601560248201527f7661756c742065786368616e6765206661696c656400000000000000000000006044820152606401610552565b60006127ac8483611d01565b6000818152600160205260409020549091506127cc9060a08601356150fb565b83111561281b5760405162461bcd60e51b815260206004820152601f60248201527f74616b657220616d6f756e74203e20617661696c61626c6520766f6c756d65006044820152606401610552565b60008181526001602052604081208054859290612839908490615086565b9091555060009050670de0b6b3a764000060c086013560a087013561285e87846150be565b612868919061509e565b61287291906150be565b61287c919061509e565b90506000670de0b6b3a7640000600380815481106128aa57634e487b7160e01b600052603260045260246000fd5b60009182526020909120601082040154600f9091166002026101000a900461ffff166128de84670de0b6b3a76400006150be565b6128e8919061509e565b6128f2919061509e565b90507f000000000000000000000000000000000000000000000000000000000000000060006001600160a01b0382166305e1dc2561293660608b0160408c01614da0565b60405160e083811b7fffffffff000000000000000000000000000000000000000000000000000000001682526001600160a01b03929092166004820152908b01356024820152604401602060405180830381600087803b15801561299957600080fd5b505af11580156129ad573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129d19190614dbc565b6040517f852a12e3000000000000000000000000000000000000000000000000000000008152600481018990529091506001600160a01b0382169063852a12e390602401602060405180830381600087803b158015612a2f57600080fd5b505af1158015612a43573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a679190614fdc565b15612ab45760405162461bcd60e51b815260206004820152601960248201527f636f6d706f756e6420726564656d7074696f6e206572726f72000000000000006044820152606401610552565b6000612ac660608a0160408b01614da0565b90506001600160a01b03811663a9059cbb612ae760408c0160208d01614da0565b612af1888c6150fb565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381600087803b158015612b4f57600080fd5b505af1158015612b63573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b879190614f15565b506001600160a01b03811663a9059cbb33612ba287896150fb565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381600087803b158015612c0057600080fd5b505af1158015612c14573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c389190614f15565b506001600160a01b038316638c6b9b41612c5860608c0160408d01614da0565b60e08c0135612c6d60408e0160208f01614da0565b60405160e085901b7fffffffff000000000000000000000000000000000000000000000000000000001681526001600160a01b03938416600482015260248101929092529091166044820152336064820152608481018b905260a4015b602060405180830381600087803b158015612ce457600080fd5b505af1158015612cf8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d1c9190614f15565b612d685760405162461bcd60e51b815260206004820152601560248201527f637573746f6469616c2065786974206661696c656400000000000000000000006044820152606401610552565b33612d7960408b0160208c01614da0565b6001600160a01b03168a600001357f51cad9177cf46d59109ae978bb3cf5ffed2bb3d53fb3682fa56fbd9266712834898d6060016020810190612dbc9190614ef9565b8e6080016020810190612dcf9190614ef9565b604080519384529115156020840152151590820152606081018d9052608081018a905260a00160405180910390a4505050505050505050565b6000612e148483611d01565b600081815260016020526040902054909150612e349060c08601356150fb565b831115612e835760405162461bcd60e51b815260206004820152601f60248201527f74616b657220616d6f756e74203e20617661696c61626c6520766f6c756d65006044820152606401610552565b60008181526001602052604081208054859290612ea1908490615086565b9091555060009050670de0b6b3a764000060a086013560c0870135612ec687846150be565b612ed0919061509e565b612eda91906150be565b612ee4919061509e565b90506000670de0b6b3a76400006003600181548110612f1357634e487b7160e01b600052603260045260246000fd5b60009182526020909120601082040154600f9091166002026101000a900461ffff16612f4784670de0b6b3a76400006150be565b612f51919061509e565b612f5b919061509e565b90507f000000000000000000000000000000000000000000000000000000000000000060006001600160a01b0382166305e1dc25612f9f60608b0160408c01614da0565b60405160e083811b7fffffffff000000000000000000000000000000000000000000000000000000001682526001600160a01b03929092166004820152908b01356024820152604401602060405180830381600087803b15801561300257600080fd5b505af1158015613016573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061303a9190614dbc565b6040517f852a12e3000000000000000000000000000000000000000000000000000000008152600481018690529091506001600160a01b0382169063852a12e390602401602060405180830381600087803b15801561309857600080fd5b505af11580156130ac573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130d09190614fdc565b1561311d5760405162461bcd60e51b815260206004820152601960248201527f636f6d706f756e6420726564656d7074696f6e206572726f72000000000000006044820152606401610552565b600061312f60608a0160408b01614da0565b90506001600160a01b03811663a9059cbb338661314c8c8a6150fb565b61315691906150fb565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381600087803b1580156131b457600080fd5b505af11580156131c8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131ec9190614f15565b506001600160a01b03811663a9059cbb61320c60408c0160208d01614da0565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602481018b9052604401602060405180830381600087803b15801561326c57600080fd5b505af1158015613280573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132a49190614f15565b506001600160a01b038316638c6b9b416132c460608c0160408d01614da0565b8b60e00135338d60200160208101906132dd9190614da0565b60405160e086901b7fffffffff000000000000000000000000000000000000000000000000000000001681526001600160a01b0394851660048201526024810193909352908316604483015290911660648201526084810188905260a401612cca565b600061334c8483611d01565b60008181526001602052604090205490915061336c9060c08601356150fb565b8311156133bb5760405162461bcd60e51b815260206004820152601f60248201527f74616b657220616d6f756e74203e20617661696c61626c6520766f6c756d65006044820152606401610552565b600081815260016020526040812080548592906133d9908490615086565b9091555060009050670de0b6b3a764000060a086013560c08701356133fe87846150be565b613408919061509e565b61341291906150be565b61341c919061509e565b90506000670de0b6b3a7640000600360028154811061344b57634e487b7160e01b600052603260045260246000fd5b60009182526020909120601082040154600f9091166002026101000a900461ffff1661347f84670de0b6b3a76400006150be565b613489919061509e565b613493919061509e565b905060006134a76060880160408901614da0565b90506001600160a01b0381166323b872dd336134c960408b0160208c01614da0565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b1681526001600160a01b0392831660048201529116602482015260448101899052606401602060405180830381600087803b15801561353057600080fd5b505af1158015613544573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135689190614f15565b506001600160a01b0381166323b872dd61358860408a0160208b01614da0565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b03909116600482015230602482015260448101869052606401602060405180830381600087803b1580156135ee57600080fd5b505af1158015613602573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136269190614f15565b507f000000000000000000000000000000000000000000000000000000000000000060006001600160a01b0382166305e1dc2561366960608c0160408d01614da0565b60405160e083811b7fffffffff000000000000000000000000000000000000000000000000000000001682526001600160a01b03929092166004820152908c01356024820152604401602060405180830381600087803b1580156136cc57600080fd5b505af11580156136e0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137049190614dbc565b6040517f095ea7b30000000000000000000000000000000000000000000000000000000081526001600160a01b038083166004830152602482018890529192509084169063095ea7b390604401602060405180830381600087803b15801561376b57600080fd5b505af115801561377f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137a39190614f15565b506040517fa0712d68000000000000000000000000000000000000000000000000000000008152600481018690526001600160a01b0382169063a0712d6890602401602060405180830381600087803b1580156137ff57600080fd5b505af1158015613813573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138379190614fdc565b156138845760405162461bcd60e51b815260206004820152601560248201527f6d696e74696e672043546f6b656e206661696c656400000000000000000000006044820152606401610552565b6001600160a01b03821663f8e51bcb6138a360608c0160408d01614da0565b60e08c01356138b860408e0160208f01614da0565b60405160e085901b7fffffffff000000000000000000000000000000000000000000000000000000001681526001600160a01b039384166004820152602481019290925290911660448201523360648201526084810188905260a401602060405180830381600087803b15801561392e57600080fd5b505af1158015613942573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139669190614f15565b6139b25760405162461bcd60e51b815260206004820152601960248201527f637573746f6469616c20696e697469617465206661696c6564000000000000006044820152606401610552565b6001600160a01b038216633cf9a4e36139d160608c0160408d01614da0565b60405160e083811b7fffffffff000000000000000000000000000000000000000000000000000000001682526001600160a01b03929092166004820152908c0135602482015233604482015260648101879052608401602060405180830381600087803b158015613a4157600080fd5b505af1158015613a55573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a799190614f15565b613ac55760405162461bcd60e51b815260206004820152601c60248201527f6e6f74696f6e616c20666565207472616e73666572206661696c6564000000006044820152606401610552565b33613ad660408b0160208c01614da0565b6001600160a01b03168a600001357f32bc401d77ffde781b234d480866e0c360e724770a30ea3299309f9171e400ef898d6060016020810190612dbc9190614ef9565b6000613b258483611d01565b600081815260016020526040902054909150613b459060a08601356150fb565b831115613b945760405162461bcd60e51b815260206004820152601f60248201527f74616b657220616d6f756e74203e20617661696c61626c6520766f6c756d65006044820152606401610552565b60008181526001602052604081208054859290613bb2908490615086565b9091555060009050670de0b6b3a764000060c086013560a0870135613bd787846150be565b613be1919061509e565b613beb91906150be565b613bf5919061509e565b90506000670de0b6b3a76400006003600081548110613c2457634e487b7160e01b600052603260045260246000fd5b60009182526020909120601082040154600f9091166002026101000a900461ffff16613c5884670de0b6b3a76400006150be565b613c62919061509e565b613c6c919061509e565b90506000613c806060880160408901614da0565b90506001600160a01b0381166323b872dd613ca160408a0160208b01614da0565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b03909116600482015233602482015260448101869052606401602060405180830381600087803b158015613d0757600080fd5b505af1158015613d1b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613d3f9190614f15565b506001600160a01b0381166323b872dd3330613d5b868b615086565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b1681526001600160a01b0393841660048201529290911660248301526044820152606401602060405180830381600087803b158015613dc257600080fd5b505af1158015613dd6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613dfa9190614f15565b507f000000000000000000000000000000000000000000000000000000000000000060006001600160a01b0382166305e1dc25613e3d60608c0160408d01614da0565b60405160e083811b7fffffffff000000000000000000000000000000000000000000000000000000001682526001600160a01b03929092166004820152908c01356024820152604401602060405180830381600087803b158015613ea057600080fd5b505af1158015613eb4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ed89190614dbc565b6040517f095ea7b30000000000000000000000000000000000000000000000000000000081526001600160a01b038083166004830152602482018b90529192509084169063095ea7b390604401602060405180830381600087803b158015613f3f57600080fd5b505af1158015613f53573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f779190614f15565b506040517fa0712d68000000000000000000000000000000000000000000000000000000008152600481018990526001600160a01b0382169063a0712d6890602401602060405180830381600087803b158015613fd357600080fd5b505af1158015613fe7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061400b9190614fdc565b156140585760405162461bcd60e51b815260206004820152601560248201527f6d696e74696e672043546f6b656e204661696c656400000000000000000000006044820152606401610552565b6001600160a01b03821663f8e51bcb61407760608c0160408d01614da0565b8b60e00135338d60200160208101906140909190614da0565b60405160e086901b7fffffffff000000000000000000000000000000000000000000000000000000001681526001600160a01b039485166004820152602481019390935290831660448301529091166064820152608481018b905260a401602060405180830381600087803b15801561410857600080fd5b505af115801561411c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141409190614f15565b613ac55760405162461bcd60e51b815260206004820152601960248201527f637573746f6469616c20696e697469617465206661696c6564000000000000006044820152606401610552565b60006141988483611d01565b6000818152600160205260409020549091506141b89060a08601356150fb565b8311156142075760405162461bcd60e51b815260206004820152601f60248201527f74616b657220616d6f756e74203e20617661696c61626c6520766f6c756d65006044820152606401610552565b60008181526001602052604081208054859290614225908490615086565b9091555060009050670de0b6b3a764000060c086013560a087013561424a87846150be565b614254919061509e565b61425e91906150be565b614268919061509e565b90506000670de0b6b3a7640000600360008154811061429757634e487b7160e01b600052603260045260246000fd5b60009182526020909120601082040154600f9091166002026101000a900461ffff166142cb84670de0b6b3a76400006150be565b6142d5919061509e565b6142df919061509e565b90506142f16060870160408801614da0565b6001600160a01b03166323b872dd3361431060408a0160208b01614da0565b8461431b878b6150fb565b6143259190615086565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b1681526001600160a01b0393841660048201529290911660248301526044820152606401602060405180830381600087803b15801561438c57600080fd5b505af11580156143a0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906143c49190614f15565b506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166365a963aa6144046060890160408a01614da0565b60e089013561441960408b0160208c01614da0565b60405160e085901b7fffffffff000000000000000000000000000000000000000000000000000000001681526001600160a01b039384166004820152602481019290925290911660448201523360648201526084810188905260a401602060405180830381600087803b15801561448f57600080fd5b505af11580156144a3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906144c79190614f15565b6145135760405162461bcd60e51b815260206004820152601760248201527f7a63546f6b656e2065786368616e6765206661696c65640000000000000000006044820152606401610552565b336145246040880160208901614da0565b6001600160a01b031687357f32bc401d77ffde781b234d480866e0c360e724770a30ea3299309f9171e400ef8661456160808c0160608d01614ef9565b61457160a08d0160808e01614ef9565b604080519384529115156020840152151590820152606081018a90526080810187905260a00160405180910390a4505050505050565b60006145b38483611d01565b6000818152600160205260409020549091506145d39060c08601356150fb565b8311156146225760405162461bcd60e51b815260206004820152601f60248201527f74616b657220616d6f756e74203e20617661696c61626c6520766f6c756d65006044820152606401610552565b60008181526001602052604081208054859290614640908490615086565b9091555060009050670de0b6b3a764000060a086013560c087013561466587846150be565b61466f919061509e565b61467991906150be565b614683919061509e565b90506000670de0b6b3a764000060036002815481106146b257634e487b7160e01b600052603260045260246000fd5b60009182526020909120601082040154600f9091166002026101000a900461ffff166146e684670de0b6b3a76400006150be565b6146f0919061509e565b6146fa919061509e565b905061470c6060870160408801614da0565b6001600160a01b03166323b872dd3361472b60408a0160208b01614da0565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b1681526001600160a01b0392831660048201529116602482015260448101889052606401602060405180830381600087803b15801561479257600080fd5b505af11580156147a6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906147ca9190614f15565b507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03811663bddbfbe461480b60608a0160408b01614da0565b60e08a013561482060408c0160208d01614da0565b60405160e085901b7fffffffff000000000000000000000000000000000000000000000000000000001681526001600160a01b039384166004820152602481019290925290911660448201523360648201526084810186905260a401602060405180830381600087803b15801561489657600080fd5b505af11580156148aa573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906148ce9190614f15565b61491a5760405162461bcd60e51b815260206004820152601560248201527f7661756c742065786368616e6765206661696c656400000000000000000000006044820152606401610552565b6001600160a01b038116633cf9a4e361493960608a0160408b01614da0565b60405160e083811b7fffffffff000000000000000000000000000000000000000000000000000000001682526001600160a01b03929092166004820152908a0135602482015233604482015260648101859052608401602060405180830381600087803b1580156149a957600080fd5b505af11580156149bd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906149e19190614f15565b614a2d5760405162461bcd60e51b815260206004820152601c60248201527f6e6f74696f6e616c20666565207472616e73666572206661696c6564000000006044820152606401610552565b33614a3e6040890160208a01614da0565b6001600160a01b031688357f32bc401d77ffde781b234d480866e0c360e724770a30ea3299309f9171e400ef8761233660808d0160608e01614ef9565b60007f7ddd38ab5ed1c16b61ca90eeb9579e29da1ba821cf42d8cdef8f30a31a6a41468235614ab06040850160208601614da0565b614ac06060860160408701614da0565b614ad06080870160608801614ef9565b614ae060a0880160808901614ef9565b8760a001358860c001358960e001358a6101000135604051602001614b5c9a99989796959493929190998a5260208a01989098526001600160a01b0396871660408a01529490951660608801529115156080870152151560a086015260c085015260e08401919091526101008301526101208201526101400190565b604051602081830303815290604052805190602001209050919050565b60007f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a060408301351115614bef5760405162461bcd60e51b815260206004820152601b60248201527f696e76616c6964207369676e6174757265202273222076616c756500000000006044820152606401610552565b614bfc6020830183614ff4565b60ff16601b1480614c1c5750614c156020830183614ff4565b60ff16601c145b614c685760405162461bcd60e51b815260206004820152601b60248201527f696e76616c6964207369676e6174757265202276222076616c756500000000006044820152606401610552565b600183614c786020850185614ff4565b604080516000815260208181018084529490945260ff9092168282015291850135606082015290840135608082015260a0016020604051602081039080840390855afa158015614ccc573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00151949350505050565b60008083601f840112614d0d578182fd5b50813567ffffffffffffffff811115614d24578182fd5b602083019150836020606083028501011115614d3f57600080fd5b9250929050565b60008083601f840112614d57578182fd5b50813567ffffffffffffffff811115614d6e578182fd5b6020830191508360208260051b8501011115614d3f57600080fd5b803561ffff81168114614d9b57600080fd5b919050565b600060208284031215614db1578081fd5b8135611e9481615161565b600060208284031215614dcd578081fd5b8151611e9481615161565b60008060408385031215614dea578081fd5b8235614df581615161565b946020939093013593505050565b600080600060608486031215614e17578081fd5b8335614e2281615161565b95602085013595506040909401359392505050565b60008060008060008060608789031215614e4f578182fd5b863567ffffffffffffffff80821115614e66578384fd5b818901915089601f830112614e79578384fd5b813581811115614e87578485fd5b8a602061012083028501011115614e9c578485fd5b602092830198509650908801359080821115614eb6578384fd5b614ec28a838b01614d46565b90965094506040890135915080821115614eda578384fd5b50614ee789828a01614cfc565b979a9699509497509295939492505050565b600060208284031215614f0a578081fd5b8135611e9481615179565b600060208284031215614f26578081fd5b8151611e9481615179565b600060208284031215614f42578081fd5b5035919050565b600080828403610180811215614f5d578283fd5b61012080821215614f6c578384fd5b84935060607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee083011215614f9e578283fd5b92959390920193505050565b60008060408385031215614fbc578182fd5b614fc583614d89565b9150614fd360208401614d89565b90509250929050565b600060208284031215614fed578081fd5b5051919050565b600060208284031215615005578081fd5b813560ff81168114611e94578182fd5b6000602080835283518082850152825b8181101561504157858101830151858201604001528201615025565b818111156150525783604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016929092016040019392505050565b600082198211156150995761509961514b565b500190565b6000826150b957634e487b7160e01b81526012600452602481fd5b500490565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156150f6576150f661514b565b500290565b60008282101561510d5761510d61514b565b500390565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8214156151445761514461514b565b5060010190565b634e487b7160e01b600052601160045260246000fd5b6001600160a01b038116811461517657600080fd5b50565b801515811461517657600080fdfea26469706673582212204350d7df97aa463f28be506e125a157aad36ae11c989b1194f02096b4a5bf28f64736f6c63430008040033 \ No newline at end of file diff --git a/gost/test/swivel/Swivel.sol b/gost/test/swivel/Swivel.sol new file mode 100644 index 0000000..d810c32 --- /dev/null +++ b/gost/test/swivel/Swivel.sol @@ -0,0 +1,490 @@ +// SPDX-License-Identifier: UNLICENSED + +pragma solidity 0.8.4; + +import './Abstracts.sol'; +import './Hash.sol'; +import './Sig.sol'; + +contract Swivel { + /// @dev maps the key of an order to a boolean indicating if an order was cancelled + mapping (bytes32 => bool) public cancelled; + /// @dev maps the key of an order to an amount representing its taken volume + mapping (bytes32 => uint256) public filled; + /// @dev maps a token address to a point in time, a hold, after which a withdrawal can be made + mapping (address => uint256) public withdrawals; + + string constant public NAME = 'Swivel Finance'; + string constant public VERSION = '2.0.0'; + uint256 constant public HOLD = 259200; // obvs could be a smaller uint but packing? + bytes32 public immutable domain; + address public immutable marketPlace; + address public immutable admin; + /// @dev holds the fee demoninators for [zcTokenInitiate, zcTokenExit, vaultInitiate, vaultExit] + uint16[] public fenominator; + + /// @notice Emitted on order cancellation + event Cancel (bytes32 indexed key, bytes32 hash); + /// @notice Emitted on any initiate* + /// @dev filled is 'principalFilled' when (vault:false, exit:false) && (vault:true, exit:true) + /// @dev filled is 'premiumFilled' when (vault:true, exit:false) && (vault:false, exit:true) + event Initiate(bytes32 indexed key, bytes32 hash, address indexed maker, bool vault, bool exit, address indexed sender, uint256 amount, uint256 filled); + /// @notice Emitted on any exit* + /// @dev filled is 'principalFilled' when (vault:false, exit:false) && (vault:true, exit:true) + /// @dev filled is 'premiumFilled' when (vault:true, exit:false) && (vault:false, exit:true) + event Exit(bytes32 indexed key, bytes32 hash, address indexed maker, bool vault, bool exit, address indexed sender, uint256 amount, uint256 filled); + /// @notice Emitted on token withdrawal scheduling + /// @dev token is the address of the token scheduled for withdrawal + /// @dev withdrawalTime is the timestamp at which the queued withdrawal will be possible + event WithdrawalScheduled (address indexed token, uint256 hold); + + /// @param m deployed MarketPlace contract address + constructor(address m) { + admin = msg.sender; + domain = Hash.domain(NAME, VERSION, block.chainid, address(this)); + marketPlace = m; + fenominator = [200, 600, 400, 200]; + } + + // ********* INITIATING ************* + + /// @notice Allows a user to initiate a position + /// @param o Array of offline Swivel.Orders + /// @param a Array of order volume (principal) amounts relative to passed orders + /// @param c Array of Components from valid ECDSA signatures + function initiate(Hash.Order[] calldata o, uint256[] calldata a, Sig.Components[] calldata c) external returns (bool) { + // for each order filled, routes the order to the right interaction depending on its params + for (uint256 i=0; i < o.length; i++) { + // If the order filled is NOT an exit + if (!o[i].exit) { + // if the order filled does NOT involve a vault (nTokens) + if (!o[i].vault) { + // then the user has called `initiate` against a zcToken initiate and msg.sender is initiating a vault (purchasing nTokens, payingPremium) + initiateVaultFillingZcTokenInitiate(o[i], a[i], c[i]); + } else { + // then the user has called `initiate` against a vault initiate and msg.sender is initiating a zcToken position (splitting and selling nTokens, receivingPremium) + initiateZcTokenFillingVaultInitiate(o[i], a[i], c[i]); + } + } else { + if (!o[i].vault) { + // then the user has called `initiate` against a zcToken exit and msg.sender is initiating a zcToken position (splitting and selling nTokens, receivingPremium) + initiateZcTokenFillingZcTokenExit(o[i], a[i], c[i]); + } else { + // then the user has called `initiate` against a vault exit (selling nTokens) and msg.sender is initiating a vault (purchasing nTokens, payingPremium) + initiateVaultFillingVaultExit(o[i], a[i], c[i]); + } + } + } + + return true; + } + + /// @notice Allows a user to initiate a Vault by filling an offline zcToken initiate order + /// @dev This method should pass (underlying, maturity, maker, sender, principalFilled) to MarketPlace.custodialInitiate + /// @param o Order being filled + /// @param a Amount of volume (premium) being filled by the taker's exit + /// @param c Components of a valid ECDSA signature + function initiateVaultFillingZcTokenInitiate(Hash.Order calldata o, uint256 a, Sig.Components calldata c) internal { + // checks order signature, order cancellation and order expiry + bytes32 hash = validOrderHash(o, c); + + // checks the taker amount passed to amount available in the order + require(a <= (o.premium - filled[hash]), 'taker amount > available volume'); + + // adds the taker amount to the order's filled amount + filled[hash] += a; + + // calculate principal filled and fee + uint256 principalFilled = (((a * 1e18) / o.premium) * o.principal) / 1e18; + uint256 fee = ((principalFilled * 1e18) / fenominator[2]) / 1e18; + + // transfer underlying tokens + Erc20 uToken = Erc20(o.underlying); + uToken.transferFrom(msg.sender, o.maker, a); + uToken.transferFrom(o.maker, address(this), principalFilled); + + // deposit underlying to Compound and mint cTokens + MarketPlace mPlace = MarketPlace(marketPlace); + address cTokenAddr = mPlace.cTokenAddress(o.underlying, o.maturity); + uToken.approve(cTokenAddr, principalFilled); + require(CErc20(cTokenAddr).mint(principalFilled) == 0, 'minting CToken failed'); + + // mint zcTokens + nTokens and allocate appropriately in marketplace + require(mPlace.custodialInitiate(o.underlying, o.maturity, o.maker, msg.sender, principalFilled), 'custodial initiate failed'); + + // transfer fee in vault notional to swivel (from msg.sender) + require(mPlace.transferVaultNotionalFee(o.underlying, o.maturity, msg.sender, fee), "notional fee transfer failed"); + + emit Initiate(o.key, hash, o.maker, o.vault, o.exit, msg.sender, a, principalFilled); + } + + /// @notice Allows a user to initiate a zcToken by filling an offline vault initiate order + /// @dev This method should pass (underlying, maturity, sender, maker, a) to MarketPlace.custodialInitiate + /// @param o Order being filled + /// @param o Amount of volume (principal) being filled by the taker's exit + /// @param c Components of a valid ECDSA signature + function initiateZcTokenFillingVaultInitiate(Hash.Order calldata o, uint256 a, Sig.Components calldata c) internal { + bytes32 hash = validOrderHash(o, c); + + require((a <= o.principal - filled[hash]), 'taker amount > available volume'); + + filled[hash] += a; + + uint256 premiumFilled = (((a * 1e18) / o.principal) * o.premium) / 1e18; + uint256 fee = ((premiumFilled * 1e18) / fenominator[0]) / 1e18; + + Erc20 uToken = Erc20(o.underlying); + uToken.transferFrom(o.maker, msg.sender, premiumFilled); + // transfer principal + fee in underlying to swivel (from sender) + uToken.transferFrom(msg.sender, address(this), (a + fee)); + + // deposit underlying to Compound and mint cTokens + MarketPlace mPlace = MarketPlace(marketPlace); + address cTokenAddr = mPlace.cTokenAddress(o.underlying, o.maturity); + uToken.approve(cTokenAddr, a); + require(CErc20(cTokenAddr).mint(a) == 0, 'minting CToken Failed'); + + // mint zcTokens + nTokens and allocate appropriately in marketplace + require(mPlace.custodialInitiate(o.underlying, o.maturity, msg.sender, o.maker, a), 'custodial initiate failed'); + + emit Initiate(o.key, hash, o.maker, o.vault, o.exit, msg.sender, a, premiumFilled); + } + + /// @notice Allows a user to initiate zcToken? by filling an offline zcToken exit order + /// @dev This method should pass (underlying, maturity, maker, sender, a) to MarketPlace.p2pZcTokenExchange + /// @param o Order being filled + /// @param a Amount of volume (principal) being filled by the taker's exit + /// @param c Components of a valid ECDSA signature + function initiateZcTokenFillingZcTokenExit(Hash.Order calldata o, uint256 a, Sig.Components calldata c) internal { + bytes32 hash = validOrderHash(o, c); + + require(a <= ((o.principal - filled[hash])), 'taker amount > available volume'); + + filled[hash] += a; + + uint256 premiumFilled = (((a * 1e18) / o.principal) * o.premium) / 1e18; + uint256 fee = ((premiumFilled * 1e18) / fenominator[0]) / 1e18; + + // transfer underlying tokens - the premium paid + fee in underlying to swivel (from sender) + Erc20(o.underlying).transferFrom(msg.sender, o.maker, ((a - premiumFilled) + fee)); + // transfer zcTokens between users in marketplace + require(MarketPlace(marketPlace).p2pZcTokenExchange(o.underlying, o.maturity, o.maker, msg.sender, a), 'zcToken exchange failed'); + + emit Initiate(o.key, hash, o.maker, o.vault, o.exit, msg.sender, a, premiumFilled); + } + + /// @notice Allows a user to initiate a Vault by filling an offline vault exit order + /// @dev This method should pass (underlying, maturity, maker, sender, principalFilled) to MarketPlace.p2pVaultExchange + /// @param o Order being filled + /// @param a Amount of volume (interest) being filled by the taker's exit + /// @param c Components of a valid ECDSA signature + function initiateVaultFillingVaultExit(Hash.Order calldata o, uint256 a, Sig.Components calldata c) internal { + bytes32 hash = validOrderHash(o, c); + + require(a <= (o.premium - filled[hash]), 'taker amount > available volume'); + + filled[hash] += a; + + uint256 principalFilled = (((a * 1e18) / o.premium) * o.principal) / 1e18; + uint256 fee = ((principalFilled * 1e18) / fenominator[2]) / 1e18; + + Erc20(o.underlying).transferFrom(msg.sender, o.maker, a); + + MarketPlace mPlace = MarketPlace(marketPlace); + // transfer vault.notional (nTokens) between users in marketplace + require(mPlace.p2pVaultExchange(o.underlying, o.maturity, o.maker, msg.sender, principalFilled), 'vault exchange failed'); + + // transfer fee (in nTokens) to swivel + require(mPlace.transferVaultNotionalFee(o.underlying, o.maturity, msg.sender, fee), "notional fee transfer failed"); + + emit Initiate(o.key, hash, o.maker, o.vault, o.exit, msg.sender, a, principalFilled); + } + + // ********* EXITING *************** + + /// @notice Allows a user to exit (sell) a currently held position to the marketplace. + /// @param o Array of offline Swivel.Orders + /// @param a Array of order volume (principal) amounts relative to passed orders + /// @param c Components of a valid ECDSA signature + function exit(Hash.Order[] calldata o, uint256[] calldata a, Sig.Components[] calldata c) external returns (bool) { + // for each order filled, routes the order to the right interaction depending on its params + for (uint256 i=0; i < o.length; i++) { + // if the order is NOT an exit + if (!o[i].exit) { + // if the order filled does NOT involve a vault (nTokens) + if (!o[i].vault) { + // then the user has called `exit` against a zcToken initiate and msg.sender is exiting zcTokens (buying nTokens + redeeming, payingPremium) + exitZcTokenFillingZcTokenInitiate(o[i], a[i], c[i]); + } else { + // then the user has called `exit` against a vault initiate and msg.sender is exiting nTokens (selling nTokens, receivingPremium) + exitVaultFillingVaultInitiate(o[i], a[i], c[i]); + } + } else { + if (!o[i].vault) { + // then the user has called `exit` against a zcToken exit and msg.sender is exiting nTokens (selling nTokens, receivingPremium) + exitVaultFillingZcTokenExit(o[i], a[i], c[i]); + } else { + // then the user has called `exit` against a vault exit and msg.sender is exiting zcTokens (buying nTokens + redeeming, payingPremium) + exitZcTokenFillingVaultExit(o[i], a[i], c[i]); + } + } + } + + return true; + } + + /// @notice Allows a user to exit their zcTokens by filling an offline zcToken initiate order + /// @dev This method should pass (underlying, maturity, sender, maker, principalFilled) to MarketPlace.p2pZcTokenExchange + /// @param o Order being filled + /// @param a Amount of volume (interest) being filled by the taker's exit + /// @param c Components of a valid ECDSA signature + function exitZcTokenFillingZcTokenInitiate(Hash.Order calldata o, uint256 a, Sig.Components calldata c) internal { + bytes32 hash = validOrderHash(o, c); + + require(a <= (o.premium - filled[hash]), 'taker amount > available volume'); + + filled[hash] += a; + + uint256 principalFilled = (((a * 1e18) / o.premium) * o.principal) / 1e18; + uint256 fee = ((principalFilled * 1e18) / fenominator[1]) / 1e18; + + Erc20 uToken = Erc20(o.underlying); + // transfer underlying from initiating party to exiting party, minus the price the exit party pays for the exit (premium), and the fee. + uToken.transferFrom(o.maker, msg.sender, principalFilled - a - fee); + // transfer fee in underlying to swivel + uToken.transferFrom(o.maker, address(this), fee); + + // transfer zcTokens from msg.sender to o.maker + require(MarketPlace(marketPlace).p2pZcTokenExchange(o.underlying, o.maturity, msg.sender, o.maker, principalFilled), 'zcToken exchange failed'); + + emit Exit(o.key, hash, o.maker, o.vault, o.exit, msg.sender, a, principalFilled); + } + + /// @notice Allows a user to exit their Vault by filling an offline vault initiate order + /// @dev This method should pass (underlying, maturity, sender, maker, a) to MarketPlace.p2pVaultExchange + /// @param o Order being filled + /// @param a Amount of volume (principal) being filled by the taker's exit + /// @param c Components of a valid ECDSA signature + function exitVaultFillingVaultInitiate(Hash.Order calldata o, uint256 a, Sig.Components calldata c) internal { + bytes32 hash = validOrderHash(o, c); + + require(a <= (o.principal - filled[hash]), 'taker amount > available volume'); + + filled[hash] += a; + + uint256 premiumFilled = (((a * 1e18) / o.principal) * o.premium) / 1e18; + uint256 fee = ((premiumFilled * 1e18) / fenominator[3]) / 1e18; + + Erc20 uToken = Erc20(o.underlying); + // transfer premium minus fee from maker to sender + uToken.transferFrom(o.maker, msg.sender, premiumFilled - fee); + + // transfer fee in underlying to swivel from sender + uToken.transferFrom(msg.sender, address(this), fee); + + // transfer vault.notional (nTokens) from sender to maker + require(MarketPlace(marketPlace).p2pVaultExchange(o.underlying, o.maturity, msg.sender, o.maker, a), 'vault exchange failed'); + + emit Exit(o.key, hash, o.maker, o.vault, o.exit, msg.sender, a, premiumFilled); + } + + /// @notice Allows a user to exit their Vault filling an offline zcToken exit order + /// @dev This method should pass (underlying, maturity, maker, sender, a) to MarketPlace.exitFillingExit + /// @param o Order being filled + /// @param a Amount of volume (principal) being filled by the taker's exit + /// @param c Components of a valid ECDSA signature + function exitVaultFillingZcTokenExit(Hash.Order calldata o, uint256 a, Sig.Components calldata c) internal { + bytes32 hash = validOrderHash(o, c); + + require(a <= (o.principal - filled[hash]), 'taker amount > available volume'); + + filled[hash] += a; + + uint256 premiumFilled = (((a * 1e18) / o.principal) * o.premium) / 1e18; + uint256 fee = ((premiumFilled * 1e18) / fenominator[3]) / 1e18; + + // redeem underlying on Compound and burn cTokens + MarketPlace mPlace = MarketPlace(marketPlace); + address cTokenAddr = mPlace.cTokenAddress(o.underlying, o.maturity); + require((CErc20(cTokenAddr).redeemUnderlying(a) == 0), "compound redemption error"); + + Erc20 uToken = Erc20(o.underlying); + // transfer principal-premium back to fixed exit party now that the interest coupon and zcb have been redeemed + uToken.transfer(o.maker, a - premiumFilled); + // transfer premium-fee to floating exit party + uToken.transfer(msg.sender, premiumFilled - fee); + + // burn zcTokens + nTokens from o.maker and msg.sender respectively + require(mPlace.custodialExit(o.underlying, o.maturity, o.maker, msg.sender, a), 'custodial exit failed'); + + + emit Exit(o.key, hash, o.maker, o.vault, o.exit, msg.sender, a, premiumFilled); + } + + /// @notice Allows a user to exit their zcTokens by filling an offline vault exit order + /// @dev This method should pass (underlying, maturity, sender, maker, principalFilled) to MarketPlace.exitFillingExit + /// @param o Order being filled + /// @param a Amount of volume (interest) being filled by the taker's exit + /// @param c Components of a valid ECDSA signature + function exitZcTokenFillingVaultExit(Hash.Order calldata o, uint256 a, Sig.Components calldata c) internal { + bytes32 hash = validOrderHash(o, c); + + require(a <= (o.premium - filled[hash]), 'taker amount > available volume'); + + filled[hash] += a; + + uint256 principalFilled = (((a * 1e18) / o.premium) * o.principal) / 1e18; + uint256 fee = ((principalFilled * 1e18) / fenominator[1]) / 1e18; + + // redeem underlying on Compound and burn cTokens + MarketPlace mPlace = MarketPlace(marketPlace); + address cTokenAddr = mPlace.cTokenAddress(o.underlying, o.maturity); + require((CErc20(cTokenAddr).redeemUnderlying(principalFilled) == 0), "compound redemption error"); + + Erc20 uToken = Erc20(o.underlying); + // transfer principal-premium-fee back to fixed exit party now that the interest coupon and zcb have been redeemed + uToken.transfer(msg.sender, principalFilled - a - fee); + uToken.transfer(o.maker, a); + + // burn zcTokens + nTokens from msg.sender and o.maker respectively + require(mPlace.custodialExit(o.underlying, o.maturity, msg.sender, o.maker, principalFilled), 'custodial exit failed'); + + emit Exit(o.key, hash, o.maker, o.vault, o.exit, msg.sender, a, principalFilled); + } + + /// @notice Allows a user to cancel an order, preventing it from being filled in the future + /// @param o Order being cancelled + /// @param c Components of a valid ECDSA signature + function cancel(Hash.Order calldata o, Sig.Components calldata c) external returns (bool) { + bytes32 hash = validOrderHash(o, c); + + require(msg.sender == o.maker, 'sender must be maker'); + + cancelled[hash] = true; + + emit Cancel(o.key, hash); + + return true; + } + + // ********* ADMINISTRATIVE *************** + + /// @notice Allows the admin to schedule the withdrawal of tokens + /// @param e Address of token to withdraw + function scheduleWithdrawal(address e) external onlyAdmin(admin) { + uint256 when = block.timestamp + HOLD; + withdrawals[e] = when; + emit WithdrawalScheduled(e, when); + } + + /// @notice Emergency function to block unplanned withdrawals + /// @param e Address of token withdrawal to block + function blockWithdrawal(address e) external onlyAdmin(admin) { + withdrawals[e] = 0; + } + + /// @notice Allows the admin to withdraw the given token, provided the holding period has been observed + /// @param e Address of token to withdraw + function withdraw(address e) external onlyAdmin(admin) { + uint256 when = withdrawals[e]; + require (when != 0, 'no withdrawal scheduled'); + require (block.timestamp >= when, 'withdrawal still on hold'); + + withdrawals[e] = 0; + + Erc20 token = Erc20(e); + token.transfer(admin, token.balanceOf(address(this))); + } + + /// @notice Allows the admin to set a new fee denominator + /// @param t The index of the new fee denominator + /// @param d The new fee denominator + function setFee(uint16 t, uint16 d) external onlyAdmin(admin) returns (bool) { + fenominator[t] = d; + return true; + } + + // ********* PROTOCOL UTILITY *************** + + /// @notice Allows users to deposit underlying and in the process split it into/mint + /// zcTokens and vault notional. Calls mPlace.mintZcTokenAddingNotional + /// @param u Underlying token address associated with the market + /// @param m Maturity timestamp of the market + /// @param a Amount of underlying being deposited + function splitUnderlying(address u, uint256 m, uint256 a) external returns (bool) { + Erc20 uToken = Erc20(u); + uToken.transferFrom(msg.sender, address(this), a); + MarketPlace mPlace = MarketPlace(marketPlace); + address cTokenAddr = mPlace.cTokenAddress(u, m); + uToken.approve(cTokenAddr, a); + require(CErc20(cTokenAddr).mint(a) == 0, 'minting CToken Failed'); + require(mPlace.mintZcTokenAddingNotional(u, m, msg.sender, a), 'mint ZcToken adding Notional failed'); + + return true; + } + + /// @notice Allows users deposit/burn 1-1 amounts of both zcTokens and vault notional, + /// in the process "combining" the two, and redeeming underlying. Calls mPlace.burnZcTokenRemovingNotional. + /// @param u Underlying token address associated with the market + /// @param m Maturity timestamp of the market + /// @param a Amount of zcTokens being redeemed + function combineTokens(address u, uint256 m, uint256 a) external returns (bool) { + MarketPlace mPlace = MarketPlace(marketPlace); + require(mPlace.burnZcTokenRemovingNotional(u, m, msg.sender, a), 'burn ZcToken removing Notional failed'); + address cTokenAddr = mPlace.cTokenAddress(u, m); + require((CErc20(cTokenAddr).redeemUnderlying(a) == 0), "compound redemption error"); + Erc20(u).transfer(msg.sender, a); + + return true; + } + + /// @notice Allows zcToken holders to redeem their tokens for underlying tokens after maturity has been reached (via MarketPlace). + /// @param u Underlying token address associated with the market + /// @param m Maturity timestamp of the market + /// @param a Amount of zcTokens being redeemed + function redeemZcToken(address u, uint256 m, uint256 a) external returns (bool) { + MarketPlace mPlace = MarketPlace(marketPlace); + // call marketplace to determine the amount redeemed + uint256 redeemed = mPlace.redeemZcToken(u, m, msg.sender, a); + // redeem underlying from compound + require(CErc20(mPlace.cTokenAddress(u, m)).redeemUnderlying(redeemed) == 0, 'compound redemption failed'); + // transfer underlying back to msg.sender + Erc20(u).transfer(msg.sender, redeemed); + + return true; + } + + /// @notice Allows Vault owners to redeem any currently accrued interest (via MarketPlace) + /// @param u Underlying token address associated with the market + /// @param m Maturity timestamp of the market + function redeemVaultInterest(address u, uint256 m) external returns (bool) { + MarketPlace mPlace = MarketPlace(marketPlace); + // call marketplace to determine the amount redeemed + uint256 redeemed = mPlace.redeemVaultInterest(u, m, msg.sender); + // redeem underlying from compound + require(CErc20(mPlace.cTokenAddress(u, m)).redeemUnderlying(redeemed) == 0, 'compound redemption failed'); + // transfer underlying back to msg.sender + Erc20(u).transfer(msg.sender, redeemed); + + return true; + } + + /// @notice Varifies the validity of an order and it's signature. + /// @param o An offline Swivel.Order + /// @param c Components of a valid ECDSA signature + /// @return the hashed order. + function validOrderHash(Hash.Order calldata o, Sig.Components calldata c) internal view returns (bytes32) { + bytes32 hash = Hash.order(o); + + require(!cancelled[hash], 'order cancelled'); + require(o.expiry >= block.timestamp, 'order expired'); + require(o.maker == Sig.recover(Hash.message(domain, hash), c), 'invalid signature'); + + return hash; + } + + modifier onlyAdmin(address a) { + require(msg.sender == a, 'sender must be admin'); + _; + } +} diff --git a/gost/test/swivel/swivel.go b/gost/test/swivel/swivel.go new file mode 100644 index 0000000..01237bc --- /dev/null +++ b/gost/test/swivel/swivel.go @@ -0,0 +1,1382 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package swivel + +import ( + "math/big" + "strings" + + ethereum "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/event" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription +) + +// HashOrder is an auto generated low-level Go binding around an user-defined struct. +type HashOrder struct { + Key [32]byte + Maker common.Address + Underlying common.Address + Vault bool + Exit bool + Principal *big.Int + Premium *big.Int + Maturity *big.Int + Expiry *big.Int +} + +// SigComponents is an auto generated low-level Go binding around an user-defined struct. +type SigComponents struct { + V uint8 + R [32]byte + S [32]byte +} + +// SwivelABI is the input ABI used to generate the binding from. +const SwivelABI = "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"m\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"key\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"hash\",\"type\":\"bytes32\"}],\"name\":\"Cancel\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"key\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"hash\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"maker\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"vault\",\"type\":\"bool\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"exit\",\"type\":\"bool\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"filled\",\"type\":\"uint256\"}],\"name\":\"Exit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"key\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"hash\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"maker\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"vault\",\"type\":\"bool\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"exit\",\"type\":\"bool\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"filled\",\"type\":\"uint256\"}],\"name\":\"Initiate\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"hold\",\"type\":\"uint256\"}],\"name\":\"WithdrawalScheduled\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"HOLD\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"NAME\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"VERSION\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"admin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"e\",\"type\":\"address\"}],\"name\":\"blockWithdrawal\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"key\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"maker\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"underlying\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"vault\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"exit\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"principal\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"premium\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maturity\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"expiry\",\"type\":\"uint256\"}],\"internalType\":\"structHash.Order\",\"name\":\"o\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"r\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"s\",\"type\":\"bytes32\"}],\"internalType\":\"structSig.Components\",\"name\":\"c\",\"type\":\"tuple\"}],\"name\":\"cancel\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"cancelled\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"u\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"m\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"a\",\"type\":\"uint256\"}],\"name\":\"combineTokens\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"domain\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"key\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"maker\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"underlying\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"vault\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"exit\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"principal\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"premium\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maturity\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"expiry\",\"type\":\"uint256\"}],\"internalType\":\"structHash.Order[]\",\"name\":\"o\",\"type\":\"tuple[]\"},{\"internalType\":\"uint256[]\",\"name\":\"a\",\"type\":\"uint256[]\"},{\"components\":[{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"r\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"s\",\"type\":\"bytes32\"}],\"internalType\":\"structSig.Components[]\",\"name\":\"c\",\"type\":\"tuple[]\"}],\"name\":\"exit\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"fenominator\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"filled\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"key\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"maker\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"underlying\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"vault\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"exit\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"principal\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"premium\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maturity\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"expiry\",\"type\":\"uint256\"}],\"internalType\":\"structHash.Order[]\",\"name\":\"o\",\"type\":\"tuple[]\"},{\"internalType\":\"uint256[]\",\"name\":\"a\",\"type\":\"uint256[]\"},{\"components\":[{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"r\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"s\",\"type\":\"bytes32\"}],\"internalType\":\"structSig.Components[]\",\"name\":\"c\",\"type\":\"tuple[]\"}],\"name\":\"initiate\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"marketPlace\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"u\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"m\",\"type\":\"uint256\"}],\"name\":\"redeemVaultInterest\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"u\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"m\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"a\",\"type\":\"uint256\"}],\"name\":\"redeemZcToken\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"e\",\"type\":\"address\"}],\"name\":\"scheduleWithdrawal\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint16\",\"name\":\"t\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"d\",\"type\":\"uint16\"}],\"name\":\"setFee\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"u\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"m\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"a\",\"type\":\"uint256\"}],\"name\":\"splitUnderlying\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"e\",\"type\":\"address\"}],\"name\":\"withdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"withdrawals\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]" + +// SwivelBin is the compiled bytecode used for deploying new contracts. +var SwivelBin = "0x60e06040523480156200001157600080fd5b50604051620054a7380380620054a7833981016040819052620000349162000206565b3360601b60c052604080518082018252600e81526d53776976656c2046696e616e636560901b602080830191909152825180840190935260058352640322e302e360dc1b838201526200009592904690309062001caa620000e8821b17901c565b6080908152606082811b6001600160601b03191660a05260408051928301815260c880845261025860208501526101909184019190915290820152620000e09060039060046200013f565b505062000236565b8351602094850120835193850193909320604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f815295860194909452928401929092526060830152608082015260a0902090565b82805482825590600052602060002090600f01601090048101928215620001dd5791602002820160005b83821115620001ab57835183826101000a81548161ffff021916908361ffff160217905550926020019260020160208160010104928301926001030262000169565b8015620001db5782816101000a81549061ffff0219169055600201602081600101049283019260010302620001ab565b505b50620001eb929150620001ef565b5090565b5b80821115620001eb5760008155600101620001f0565b60006020828403121562000218578081fd5b81516001600160a01b03811681146200022f578182fd5b9392505050565b60805160a05160601c60c05160601c6151bd620002ea600039600081816103a601528181610e1b01528181610f9a015281816114b7015281816115900152611bc601526000818161020d01528181610466015281816107d301528181610b8801528181611198015281816121a101528181612659015281816128f601528181612f5f0152818161362901528181613dfd015281816143cf01526147cd0152600081816103620152611dec01526151bd6000f3fe608060405234801561001057600080fd5b50600436106101775760003560e01c806392ae3764116100d8578063c2fb26a61161008c578063f851a44011610066578063f851a440146103a1578063f8eaad35146103c8578063ffa1ad74146103db57600080fd5b8063c2fb26a61461035d578063d0886f9714610384578063d2144f581461038e57600080fd5b8063a102e384116100bd578063a102e384146102ee578063a3f4df7e14610301578063aba287011461034a57600080fd5b806392ae3764146102c857806399b64de1146102db57600080fd5b806333c810e91161012f57806340d37cdf1161011457806340d37cdf1461028057806351cff8d9146102935780637a9262a2146102a857600080fd5b806333c810e9146102475780633e1608b41461026d57600080fd5b8063288cdc9111610160578063288cdc91146101b75780632ac12622146101e55780632e25d2a61461020857600080fd5b80630908ff2d1461017c578063154e0f2e146101a4575b600080fd5b61018f61018a366004614e03565b610417565b60405190151581526020015b60405180910390f35b61018f6101b2366004614e03565b610784565b6101d76101c5366004614f31565b60016020526000908152604090205481565b60405190815260200161019b565b61018f6101f3366004614f31565b60006020819052908152604090205460ff1681565b61022f7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b03909116815260200161019b565b61025a610255366004614f31565b610a0b565b60405161ffff909116815260200161019b565b61018f61027b366004614f49565b610a43565b61018f61028e366004614dd8565b610b40565b6102a66102a1366004614da0565b610e19565b005b6101d76102b6366004614da0565b60026020526000908152604090205481565b61018f6102d6366004614e03565b6110b4565b61018f6102e9366004614faa565b6114b3565b6102a66102fc366004614da0565b61158e565b61033d6040518060400160405280600e81526020017f53776976656c2046696e616e636500000000000000000000000000000000000081525081565b60405161019b9190615015565b61018f610358366004614e37565b611622565b6101d77f000000000000000000000000000000000000000000000000000000000000000081565b6101d76203f48081565b61018f61039c366004614e37565b6118fa565b61022f7f000000000000000000000000000000000000000000000000000000000000000081565b6102a66103d6366004614da0565b611bc4565b61033d6040518060400160405280600581526020017f322e302e3000000000000000000000000000000000000000000000000000000081525081565b6040517fb50a66f70000000000000000000000000000000000000000000000000000000081526001600160a01b03848116600483015260248201849052336044830152606482018390526000917f00000000000000000000000000000000000000000000000000000000000000009182169063b50a66f790608401602060405180830381600087803b1580156104ac57600080fd5b505af11580156104c0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104e49190614f15565b61055b5760405162461bcd60e51b815260206004820152602560248201527f6275726e205a63546f6b656e2072656d6f76696e67204e6f74696f6e616c206660448201527f61696c656400000000000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b6040517f05e1dc250000000000000000000000000000000000000000000000000000000081526001600160a01b03868116600483015260248201869052600091908316906305e1dc2590604401602060405180830381600087803b1580156105c257600080fd5b505af11580156105d6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105fa9190614dbc565b6040517f852a12e3000000000000000000000000000000000000000000000000000000008152600481018690529091506001600160a01b0382169063852a12e390602401602060405180830381600087803b15801561065857600080fd5b505af115801561066c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106909190614fdc565b156106dd5760405162461bcd60e51b815260206004820152601960248201527f636f6d706f756e6420726564656d7074696f6e206572726f72000000000000006044820152606401610552565b6040517fa9059cbb000000000000000000000000000000000000000000000000000000008152336004820152602481018590526001600160a01b0387169063a9059cbb906044015b602060405180830381600087803b15801561073f57600080fd5b505af1158015610753573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107779190614f15565b5060019695505050505050565b6040517fc5ee114d0000000000000000000000000000000000000000000000000000000081526001600160a01b03848116600483015260248201849052336044830152606482018390526000917f00000000000000000000000000000000000000000000000000000000000000009183919083169063c5ee114d90608401602060405180830381600087803b15801561081c57600080fd5b505af1158015610830573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108549190614fdc565b6040517f05e1dc250000000000000000000000000000000000000000000000000000000081526001600160a01b03888116600483015260248201889052919250908316906305e1dc2590604401602060405180830381600087803b1580156108bb57600080fd5b505af11580156108cf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108f39190614dbc565b6001600160a01b031663852a12e3826040518263ffffffff1660e01b815260040161092091815260200190565b602060405180830381600087803b15801561093a57600080fd5b505af115801561094e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109729190614fdc565b156109bf5760405162461bcd60e51b815260206004820152601a60248201527f636f6d706f756e6420726564656d7074696f6e206661696c65640000000000006044820152606401610552565b6040517fa9059cbb000000000000000000000000000000000000000000000000000000008152336004820152602481018290526001600160a01b0387169063a9059cbb90604401610725565b60038181548110610a1b57600080fd5b9060005260206000209060109182820401919006600202915054906101000a900461ffff1681565b600080610a508484611d01565b9050610a626040850160208601614da0565b6001600160a01b0316336001600160a01b031614610ac25760405162461bcd60e51b815260206004820152601460248201527f73656e646572206d757374206265206d616b65720000000000000000000000006044820152606401610552565b6000818152602081905260409081902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055518435907f9e5d8891dc1b047de610617bc9bc2d8ccffebbc3d63363431a546831245858a690610b2e9084815260200190565b60405180910390a25060019392505050565b6040517fa11f48560000000000000000000000000000000000000000000000000000000081526001600160a01b038381166004830152602482018390523360448301526000917f00000000000000000000000000000000000000000000000000000000000000009183919083169063a11f485690606401602060405180830381600087803b158015610bd157600080fd5b505af1158015610be5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c099190614fdc565b6040517f05e1dc250000000000000000000000000000000000000000000000000000000081526001600160a01b03878116600483015260248201879052919250908316906305e1dc2590604401602060405180830381600087803b158015610c7057600080fd5b505af1158015610c84573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ca89190614dbc565b6001600160a01b031663852a12e3826040518263ffffffff1660e01b8152600401610cd591815260200190565b602060405180830381600087803b158015610cef57600080fd5b505af1158015610d03573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d279190614fdc565b15610d745760405162461bcd60e51b815260206004820152601a60248201527f636f6d706f756e6420726564656d7074696f6e206661696c65640000000000006044820152606401610552565b6040517fa9059cbb000000000000000000000000000000000000000000000000000000008152336004820152602481018290526001600160a01b0386169063a9059cbb90604401602060405180830381600087803b158015610dd557600080fd5b505af1158015610de9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e0d9190614f15565b50600195945050505050565b7f0000000000000000000000000000000000000000000000000000000000000000336001600160a01b03821614610e925760405162461bcd60e51b815260206004820152601460248201527f73656e646572206d7573742062652061646d696e0000000000000000000000006044820152606401610552565b6001600160a01b03821660009081526002602052604090205480610ef85760405162461bcd60e51b815260206004820152601760248201527f6e6f207769746864726177616c207363686564756c65640000000000000000006044820152606401610552565b80421015610f485760405162461bcd60e51b815260206004820152601860248201527f7769746864726177616c207374696c6c206f6e20686f6c6400000000000000006044820152606401610552565b6001600160a01b03831660008181526002602052604080822091909155517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015284919063a9059cbb907f00000000000000000000000000000000000000000000000000000000000000009083906370a0823190602401602060405180830381600087803b158015610fdf57600080fd5b505af1158015610ff3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110179190614fdc565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381600087803b15801561107557600080fd5b505af1158015611089573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110ad9190614f15565b5050505050565b6040517f23b872dd0000000000000000000000000000000000000000000000000000000081523360048201523060248201526044810182905260009084906001600160a01b038216906323b872dd90606401602060405180830381600087803b15801561112057600080fd5b505af1158015611134573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111589190614f15565b506040517f05e1dc250000000000000000000000000000000000000000000000000000000081526001600160a01b038681166004830152602482018690527f0000000000000000000000000000000000000000000000000000000000000000916000918316906305e1dc2590604401602060405180830381600087803b1580156111e157600080fd5b505af11580156111f5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112199190614dbc565b6040517f095ea7b30000000000000000000000000000000000000000000000000000000081526001600160a01b038083166004830152602482018890529192509084169063095ea7b390604401602060405180830381600087803b15801561128057600080fd5b505af1158015611294573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112b89190614f15565b506040517fa0712d68000000000000000000000000000000000000000000000000000000008152600481018690526001600160a01b0382169063a0712d6890602401602060405180830381600087803b15801561131457600080fd5b505af1158015611328573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061134c9190614fdc565b156113995760405162461bcd60e51b815260206004820152601560248201527f6d696e74696e672043546f6b656e204661696c656400000000000000000000006044820152606401610552565b6040517fef267f2c0000000000000000000000000000000000000000000000000000000081526001600160a01b038881166004830152602482018890523360448301526064820187905283169063ef267f2c90608401602060405180830381600087803b15801561140957600080fd5b505af115801561141d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114419190614f15565b6107775760405162461bcd60e51b815260206004820152602360248201527f6d696e74205a63546f6b656e20616464696e67204e6f74696f6e616c2066616960448201527f6c656400000000000000000000000000000000000000000000000000000000006064820152608401610552565b60007f0000000000000000000000000000000000000000000000000000000000000000336001600160a01b0382161461152e5760405162461bcd60e51b815260206004820152601460248201527f73656e646572206d7573742062652061646d696e0000000000000000000000006044820152606401610552565b8260038561ffff168154811061155457634e487b7160e01b600052603260045260246000fd5b90600052602060002090601091828204019190066002026101000a81548161ffff021916908361ffff160217905550600191505092915050565b7f0000000000000000000000000000000000000000000000000000000000000000336001600160a01b038216146116075760405162461bcd60e51b815260206004820152601460248201527f73656e646572206d7573742062652061646d696e0000000000000000000000006044820152606401610552565b506001600160a01b0316600090815260026020526040812055565b6000805b868110156118ec5787878281811061164e57634e487b7160e01b600052603260045260246000fd5b9050610120020160800160208101906116679190614ef9565b6117a55787878281811061168b57634e487b7160e01b600052603260045260246000fd5b9050610120020160600160208101906116a49190614ef9565b611729576117248888838181106116cb57634e487b7160e01b600052603260045260246000fd5b905061012002018787848181106116f257634e487b7160e01b600052603260045260246000fd5b9050602002013586868581811061171957634e487b7160e01b600052603260045260246000fd5b905060600201611e9b565b6118da565b61172488888381811061174c57634e487b7160e01b600052603260045260246000fd5b9050610120020187878481811061177357634e487b7160e01b600052603260045260246000fd5b9050602002013586868581811061179a57634e487b7160e01b600052603260045260246000fd5b90506060020161237d565b8787828181106117c557634e487b7160e01b600052603260045260246000fd5b9050610120020160600160208101906117de9190614ef9565b61185e5761172488888381811061180557634e487b7160e01b600052603260045260246000fd5b9050610120020187878481811061182c57634e487b7160e01b600052603260045260246000fd5b9050602002013586868581811061185357634e487b7160e01b600052603260045260246000fd5b9050606002016127a0565b6118da88888381811061188157634e487b7160e01b600052603260045260246000fd5b905061012002018787848181106118a857634e487b7160e01b600052603260045260246000fd5b905060200201358686858181106118cf57634e487b7160e01b600052603260045260246000fd5b905060600201612e08565b806118e481615112565b915050611626565b506001979650505050505050565b6000805b868110156118ec5787878281811061192657634e487b7160e01b600052603260045260246000fd5b90506101200201608001602081019061193f9190614ef9565b611a7d5787878281811061196357634e487b7160e01b600052603260045260246000fd5b90506101200201606001602081019061197c9190614ef9565b611a01576119fc8888838181106119a357634e487b7160e01b600052603260045260246000fd5b905061012002018787848181106119ca57634e487b7160e01b600052603260045260246000fd5b905060200201358686858181106119f157634e487b7160e01b600052603260045260246000fd5b905060600201613340565b611bb2565b6119fc888883818110611a2457634e487b7160e01b600052603260045260246000fd5b90506101200201878784818110611a4b57634e487b7160e01b600052603260045260246000fd5b90506020020135868685818110611a7257634e487b7160e01b600052603260045260246000fd5b905060600201613b19565b878782818110611a9d57634e487b7160e01b600052603260045260246000fd5b905061012002016060016020810190611ab69190614ef9565b611b36576119fc888883818110611add57634e487b7160e01b600052603260045260246000fd5b90506101200201878784818110611b0457634e487b7160e01b600052603260045260246000fd5b90506020020135868685818110611b2b57634e487b7160e01b600052603260045260246000fd5b90506060020161418c565b611bb2888883818110611b5957634e487b7160e01b600052603260045260246000fd5b90506101200201878784818110611b8057634e487b7160e01b600052603260045260246000fd5b90506020020135868685818110611ba757634e487b7160e01b600052603260045260246000fd5b9050606002016145a7565b80611bbc81615112565b9150506118fe565b7f0000000000000000000000000000000000000000000000000000000000000000336001600160a01b03821614611c3d5760405162461bcd60e51b815260206004820152601460248201527f73656e646572206d7573742062652061646d696e0000000000000000000000006044820152606401610552565b6000611c4c6203f48042615086565b6001600160a01b0384166000818152600260205260409081902083905551919250907fd9cf0116e5bb6fbe3d257dc8d1ee7ae76c303efeae77f1e93024d2cb218bedd390611c9d9084815260200190565b60405180910390a2505050565b8351602094850120835193850193909320604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f815295860194909452928401929092526060830152608082015260a0902090565b600080611d0d84614a7b565b60008181526020819052604090205490915060ff1615611d6f5760405162461bcd60e51b815260206004820152600f60248201527f6f726465722063616e63656c6c656400000000000000000000000000000000006044820152606401610552565b428461010001351015611dc45760405162461bcd60e51b815260206004820152600d60248201527f6f726465722065787069726564000000000000000000000000000000000000006044820152606401610552565b6040517f190100000000000000000000000000000000000000000000000000000000000081527f000000000000000000000000000000000000000000000000000000000000000060028201526022810182905260429020611e259084614b79565b6001600160a01b0316611e3e6040860160208701614da0565b6001600160a01b031614611e945760405162461bcd60e51b815260206004820152601160248201527f696e76616c6964207369676e61747572650000000000000000000000000000006044820152606401610552565b9392505050565b6000611ea78483611d01565b600081815260016020526040902054909150611ec79060c08601356150fb565b831115611f165760405162461bcd60e51b815260206004820152601f60248201527f74616b657220616d6f756e74203e20617661696c61626c6520766f6c756d65006044820152606401610552565b60008181526001602052604081208054859290611f34908490615086565b9091555060009050670de0b6b3a764000060a086013560c0870135611f5987846150be565b611f63919061509e565b611f6d91906150be565b611f77919061509e565b90506000670de0b6b3a76400006003600181548110611fa657634e487b7160e01b600052603260045260246000fd5b60009182526020909120601082040154600f9091166002026101000a900461ffff16611fda84670de0b6b3a76400006150be565b611fe4919061509e565b611fee919061509e565b905060006120026060880160408901614da0565b90506001600160a01b0381166323b872dd61202360408a0160208b01614da0565b338561202f8b896150fb565b61203991906150fb565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b1681526001600160a01b0393841660048201529290911660248301526044820152606401602060405180830381600087803b1580156120a057600080fd5b505af11580156120b4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120d89190614f15565b506001600160a01b0381166323b872dd6120f860408a0160208b01614da0565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b03909116600482015230602482015260448101859052606401602060405180830381600087803b15801561215e57600080fd5b505af1158015612172573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121969190614f15565b506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166365a963aa6121d660608a0160408b01614da0565b60e08a0135336121ec60408d0160208e01614da0565b60405160e086901b7fffffffff000000000000000000000000000000000000000000000000000000001681526001600160a01b0394851660048201526024810193909352908316604483015290911660648201526084810186905260a401602060405180830381600087803b15801561226457600080fd5b505af1158015612278573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061229c9190614f15565b6122e85760405162461bcd60e51b815260206004820152601760248201527f7a63546f6b656e2065786368616e6765206661696c65640000000000000000006044820152606401610552565b336122f96040890160208a01614da0565b6001600160a01b031688357f51cad9177cf46d59109ae978bb3cf5ffed2bb3d53fb3682fa56fbd92667128348761233660808d0160608e01614ef9565b61234660a08e0160808f01614ef9565b604080519384529115156020840152151590820152606081018b90526080810188905260a00160405180910390a450505050505050565b60006123898483611d01565b6000818152600160205260409020549091506123a99060a08601356150fb565b8311156123f85760405162461bcd60e51b815260206004820152601f60248201527f74616b657220616d6f756e74203e20617661696c61626c6520766f6c756d65006044820152606401610552565b60008181526001602052604081208054859290612416908490615086565b9091555060009050670de0b6b3a764000060c086013560a087013561243b87846150be565b612445919061509e565b61244f91906150be565b612459919061509e565b90506000670de0b6b3a76400006003808154811061248757634e487b7160e01b600052603260045260246000fd5b60009182526020909120601082040154600f9091166002026101000a900461ffff166124bb84670de0b6b3a76400006150be565b6124c5919061509e565b6124cf919061509e565b905060006124e36060880160408901614da0565b90506001600160a01b0381166323b872dd61250460408a0160208b01614da0565b3361250f86886150fb565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b1681526001600160a01b0393841660048201529290911660248301526044820152606401602060405180830381600087803b15801561257657600080fd5b505af115801561258a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125ae9190614f15565b506040517f23b872dd000000000000000000000000000000000000000000000000000000008152336004820152306024820152604481018390526001600160a01b038216906323b872dd90606401602060405180830381600087803b15801561261657600080fd5b505af115801561262a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061264e9190614f15565b506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663bddbfbe461268e60608a0160408b01614da0565b60e08a0135336126a460408d0160208e01614da0565b60405160e086901b7fffffffff000000000000000000000000000000000000000000000000000000001681526001600160a01b0394851660048201526024810193909352908316604483015290911660648201526084810189905260a401602060405180830381600087803b15801561271c57600080fd5b505af1158015612730573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127549190614f15565b6122e85760405162461bcd60e51b815260206004820152601560248201527f7661756c742065786368616e6765206661696c656400000000000000000000006044820152606401610552565b60006127ac8483611d01565b6000818152600160205260409020549091506127cc9060a08601356150fb565b83111561281b5760405162461bcd60e51b815260206004820152601f60248201527f74616b657220616d6f756e74203e20617661696c61626c6520766f6c756d65006044820152606401610552565b60008181526001602052604081208054859290612839908490615086565b9091555060009050670de0b6b3a764000060c086013560a087013561285e87846150be565b612868919061509e565b61287291906150be565b61287c919061509e565b90506000670de0b6b3a7640000600380815481106128aa57634e487b7160e01b600052603260045260246000fd5b60009182526020909120601082040154600f9091166002026101000a900461ffff166128de84670de0b6b3a76400006150be565b6128e8919061509e565b6128f2919061509e565b90507f000000000000000000000000000000000000000000000000000000000000000060006001600160a01b0382166305e1dc2561293660608b0160408c01614da0565b60405160e083811b7fffffffff000000000000000000000000000000000000000000000000000000001682526001600160a01b03929092166004820152908b01356024820152604401602060405180830381600087803b15801561299957600080fd5b505af11580156129ad573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129d19190614dbc565b6040517f852a12e3000000000000000000000000000000000000000000000000000000008152600481018990529091506001600160a01b0382169063852a12e390602401602060405180830381600087803b158015612a2f57600080fd5b505af1158015612a43573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a679190614fdc565b15612ab45760405162461bcd60e51b815260206004820152601960248201527f636f6d706f756e6420726564656d7074696f6e206572726f72000000000000006044820152606401610552565b6000612ac660608a0160408b01614da0565b90506001600160a01b03811663a9059cbb612ae760408c0160208d01614da0565b612af1888c6150fb565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381600087803b158015612b4f57600080fd5b505af1158015612b63573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b879190614f15565b506001600160a01b03811663a9059cbb33612ba287896150fb565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381600087803b158015612c0057600080fd5b505af1158015612c14573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c389190614f15565b506001600160a01b038316638c6b9b41612c5860608c0160408d01614da0565b60e08c0135612c6d60408e0160208f01614da0565b60405160e085901b7fffffffff000000000000000000000000000000000000000000000000000000001681526001600160a01b03938416600482015260248101929092529091166044820152336064820152608481018b905260a4015b602060405180830381600087803b158015612ce457600080fd5b505af1158015612cf8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d1c9190614f15565b612d685760405162461bcd60e51b815260206004820152601560248201527f637573746f6469616c2065786974206661696c656400000000000000000000006044820152606401610552565b33612d7960408b0160208c01614da0565b6001600160a01b03168a600001357f51cad9177cf46d59109ae978bb3cf5ffed2bb3d53fb3682fa56fbd9266712834898d6060016020810190612dbc9190614ef9565b8e6080016020810190612dcf9190614ef9565b604080519384529115156020840152151590820152606081018d9052608081018a905260a00160405180910390a4505050505050505050565b6000612e148483611d01565b600081815260016020526040902054909150612e349060c08601356150fb565b831115612e835760405162461bcd60e51b815260206004820152601f60248201527f74616b657220616d6f756e74203e20617661696c61626c6520766f6c756d65006044820152606401610552565b60008181526001602052604081208054859290612ea1908490615086565b9091555060009050670de0b6b3a764000060a086013560c0870135612ec687846150be565b612ed0919061509e565b612eda91906150be565b612ee4919061509e565b90506000670de0b6b3a76400006003600181548110612f1357634e487b7160e01b600052603260045260246000fd5b60009182526020909120601082040154600f9091166002026101000a900461ffff16612f4784670de0b6b3a76400006150be565b612f51919061509e565b612f5b919061509e565b90507f000000000000000000000000000000000000000000000000000000000000000060006001600160a01b0382166305e1dc25612f9f60608b0160408c01614da0565b60405160e083811b7fffffffff000000000000000000000000000000000000000000000000000000001682526001600160a01b03929092166004820152908b01356024820152604401602060405180830381600087803b15801561300257600080fd5b505af1158015613016573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061303a9190614dbc565b6040517f852a12e3000000000000000000000000000000000000000000000000000000008152600481018690529091506001600160a01b0382169063852a12e390602401602060405180830381600087803b15801561309857600080fd5b505af11580156130ac573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130d09190614fdc565b1561311d5760405162461bcd60e51b815260206004820152601960248201527f636f6d706f756e6420726564656d7074696f6e206572726f72000000000000006044820152606401610552565b600061312f60608a0160408b01614da0565b90506001600160a01b03811663a9059cbb338661314c8c8a6150fb565b61315691906150fb565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381600087803b1580156131b457600080fd5b505af11580156131c8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131ec9190614f15565b506001600160a01b03811663a9059cbb61320c60408c0160208d01614da0565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602481018b9052604401602060405180830381600087803b15801561326c57600080fd5b505af1158015613280573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132a49190614f15565b506001600160a01b038316638c6b9b416132c460608c0160408d01614da0565b8b60e00135338d60200160208101906132dd9190614da0565b60405160e086901b7fffffffff000000000000000000000000000000000000000000000000000000001681526001600160a01b0394851660048201526024810193909352908316604483015290911660648201526084810188905260a401612cca565b600061334c8483611d01565b60008181526001602052604090205490915061336c9060c08601356150fb565b8311156133bb5760405162461bcd60e51b815260206004820152601f60248201527f74616b657220616d6f756e74203e20617661696c61626c6520766f6c756d65006044820152606401610552565b600081815260016020526040812080548592906133d9908490615086565b9091555060009050670de0b6b3a764000060a086013560c08701356133fe87846150be565b613408919061509e565b61341291906150be565b61341c919061509e565b90506000670de0b6b3a7640000600360028154811061344b57634e487b7160e01b600052603260045260246000fd5b60009182526020909120601082040154600f9091166002026101000a900461ffff1661347f84670de0b6b3a76400006150be565b613489919061509e565b613493919061509e565b905060006134a76060880160408901614da0565b90506001600160a01b0381166323b872dd336134c960408b0160208c01614da0565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b1681526001600160a01b0392831660048201529116602482015260448101899052606401602060405180830381600087803b15801561353057600080fd5b505af1158015613544573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135689190614f15565b506001600160a01b0381166323b872dd61358860408a0160208b01614da0565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b03909116600482015230602482015260448101869052606401602060405180830381600087803b1580156135ee57600080fd5b505af1158015613602573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136269190614f15565b507f000000000000000000000000000000000000000000000000000000000000000060006001600160a01b0382166305e1dc2561366960608c0160408d01614da0565b60405160e083811b7fffffffff000000000000000000000000000000000000000000000000000000001682526001600160a01b03929092166004820152908c01356024820152604401602060405180830381600087803b1580156136cc57600080fd5b505af11580156136e0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137049190614dbc565b6040517f095ea7b30000000000000000000000000000000000000000000000000000000081526001600160a01b038083166004830152602482018890529192509084169063095ea7b390604401602060405180830381600087803b15801561376b57600080fd5b505af115801561377f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137a39190614f15565b506040517fa0712d68000000000000000000000000000000000000000000000000000000008152600481018690526001600160a01b0382169063a0712d6890602401602060405180830381600087803b1580156137ff57600080fd5b505af1158015613813573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138379190614fdc565b156138845760405162461bcd60e51b815260206004820152601560248201527f6d696e74696e672043546f6b656e206661696c656400000000000000000000006044820152606401610552565b6001600160a01b03821663f8e51bcb6138a360608c0160408d01614da0565b60e08c01356138b860408e0160208f01614da0565b60405160e085901b7fffffffff000000000000000000000000000000000000000000000000000000001681526001600160a01b039384166004820152602481019290925290911660448201523360648201526084810188905260a401602060405180830381600087803b15801561392e57600080fd5b505af1158015613942573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139669190614f15565b6139b25760405162461bcd60e51b815260206004820152601960248201527f637573746f6469616c20696e697469617465206661696c6564000000000000006044820152606401610552565b6001600160a01b038216633cf9a4e36139d160608c0160408d01614da0565b60405160e083811b7fffffffff000000000000000000000000000000000000000000000000000000001682526001600160a01b03929092166004820152908c0135602482015233604482015260648101879052608401602060405180830381600087803b158015613a4157600080fd5b505af1158015613a55573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a799190614f15565b613ac55760405162461bcd60e51b815260206004820152601c60248201527f6e6f74696f6e616c20666565207472616e73666572206661696c6564000000006044820152606401610552565b33613ad660408b0160208c01614da0565b6001600160a01b03168a600001357f32bc401d77ffde781b234d480866e0c360e724770a30ea3299309f9171e400ef898d6060016020810190612dbc9190614ef9565b6000613b258483611d01565b600081815260016020526040902054909150613b459060a08601356150fb565b831115613b945760405162461bcd60e51b815260206004820152601f60248201527f74616b657220616d6f756e74203e20617661696c61626c6520766f6c756d65006044820152606401610552565b60008181526001602052604081208054859290613bb2908490615086565b9091555060009050670de0b6b3a764000060c086013560a0870135613bd787846150be565b613be1919061509e565b613beb91906150be565b613bf5919061509e565b90506000670de0b6b3a76400006003600081548110613c2457634e487b7160e01b600052603260045260246000fd5b60009182526020909120601082040154600f9091166002026101000a900461ffff16613c5884670de0b6b3a76400006150be565b613c62919061509e565b613c6c919061509e565b90506000613c806060880160408901614da0565b90506001600160a01b0381166323b872dd613ca160408a0160208b01614da0565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b03909116600482015233602482015260448101869052606401602060405180830381600087803b158015613d0757600080fd5b505af1158015613d1b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613d3f9190614f15565b506001600160a01b0381166323b872dd3330613d5b868b615086565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b1681526001600160a01b0393841660048201529290911660248301526044820152606401602060405180830381600087803b158015613dc257600080fd5b505af1158015613dd6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613dfa9190614f15565b507f000000000000000000000000000000000000000000000000000000000000000060006001600160a01b0382166305e1dc25613e3d60608c0160408d01614da0565b60405160e083811b7fffffffff000000000000000000000000000000000000000000000000000000001682526001600160a01b03929092166004820152908c01356024820152604401602060405180830381600087803b158015613ea057600080fd5b505af1158015613eb4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ed89190614dbc565b6040517f095ea7b30000000000000000000000000000000000000000000000000000000081526001600160a01b038083166004830152602482018b90529192509084169063095ea7b390604401602060405180830381600087803b158015613f3f57600080fd5b505af1158015613f53573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f779190614f15565b506040517fa0712d68000000000000000000000000000000000000000000000000000000008152600481018990526001600160a01b0382169063a0712d6890602401602060405180830381600087803b158015613fd357600080fd5b505af1158015613fe7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061400b9190614fdc565b156140585760405162461bcd60e51b815260206004820152601560248201527f6d696e74696e672043546f6b656e204661696c656400000000000000000000006044820152606401610552565b6001600160a01b03821663f8e51bcb61407760608c0160408d01614da0565b8b60e00135338d60200160208101906140909190614da0565b60405160e086901b7fffffffff000000000000000000000000000000000000000000000000000000001681526001600160a01b039485166004820152602481019390935290831660448301529091166064820152608481018b905260a401602060405180830381600087803b15801561410857600080fd5b505af115801561411c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141409190614f15565b613ac55760405162461bcd60e51b815260206004820152601960248201527f637573746f6469616c20696e697469617465206661696c6564000000000000006044820152606401610552565b60006141988483611d01565b6000818152600160205260409020549091506141b89060a08601356150fb565b8311156142075760405162461bcd60e51b815260206004820152601f60248201527f74616b657220616d6f756e74203e20617661696c61626c6520766f6c756d65006044820152606401610552565b60008181526001602052604081208054859290614225908490615086565b9091555060009050670de0b6b3a764000060c086013560a087013561424a87846150be565b614254919061509e565b61425e91906150be565b614268919061509e565b90506000670de0b6b3a7640000600360008154811061429757634e487b7160e01b600052603260045260246000fd5b60009182526020909120601082040154600f9091166002026101000a900461ffff166142cb84670de0b6b3a76400006150be565b6142d5919061509e565b6142df919061509e565b90506142f16060870160408801614da0565b6001600160a01b03166323b872dd3361431060408a0160208b01614da0565b8461431b878b6150fb565b6143259190615086565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b1681526001600160a01b0393841660048201529290911660248301526044820152606401602060405180830381600087803b15801561438c57600080fd5b505af11580156143a0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906143c49190614f15565b506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166365a963aa6144046060890160408a01614da0565b60e089013561441960408b0160208c01614da0565b60405160e085901b7fffffffff000000000000000000000000000000000000000000000000000000001681526001600160a01b039384166004820152602481019290925290911660448201523360648201526084810188905260a401602060405180830381600087803b15801561448f57600080fd5b505af11580156144a3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906144c79190614f15565b6145135760405162461bcd60e51b815260206004820152601760248201527f7a63546f6b656e2065786368616e6765206661696c65640000000000000000006044820152606401610552565b336145246040880160208901614da0565b6001600160a01b031687357f32bc401d77ffde781b234d480866e0c360e724770a30ea3299309f9171e400ef8661456160808c0160608d01614ef9565b61457160a08d0160808e01614ef9565b604080519384529115156020840152151590820152606081018a90526080810187905260a00160405180910390a4505050505050565b60006145b38483611d01565b6000818152600160205260409020549091506145d39060c08601356150fb565b8311156146225760405162461bcd60e51b815260206004820152601f60248201527f74616b657220616d6f756e74203e20617661696c61626c6520766f6c756d65006044820152606401610552565b60008181526001602052604081208054859290614640908490615086565b9091555060009050670de0b6b3a764000060a086013560c087013561466587846150be565b61466f919061509e565b61467991906150be565b614683919061509e565b90506000670de0b6b3a764000060036002815481106146b257634e487b7160e01b600052603260045260246000fd5b60009182526020909120601082040154600f9091166002026101000a900461ffff166146e684670de0b6b3a76400006150be565b6146f0919061509e565b6146fa919061509e565b905061470c6060870160408801614da0565b6001600160a01b03166323b872dd3361472b60408a0160208b01614da0565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b1681526001600160a01b0392831660048201529116602482015260448101889052606401602060405180830381600087803b15801561479257600080fd5b505af11580156147a6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906147ca9190614f15565b507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03811663bddbfbe461480b60608a0160408b01614da0565b60e08a013561482060408c0160208d01614da0565b60405160e085901b7fffffffff000000000000000000000000000000000000000000000000000000001681526001600160a01b039384166004820152602481019290925290911660448201523360648201526084810186905260a401602060405180830381600087803b15801561489657600080fd5b505af11580156148aa573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906148ce9190614f15565b61491a5760405162461bcd60e51b815260206004820152601560248201527f7661756c742065786368616e6765206661696c656400000000000000000000006044820152606401610552565b6001600160a01b038116633cf9a4e361493960608a0160408b01614da0565b60405160e083811b7fffffffff000000000000000000000000000000000000000000000000000000001682526001600160a01b03929092166004820152908a0135602482015233604482015260648101859052608401602060405180830381600087803b1580156149a957600080fd5b505af11580156149bd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906149e19190614f15565b614a2d5760405162461bcd60e51b815260206004820152601c60248201527f6e6f74696f6e616c20666565207472616e73666572206661696c6564000000006044820152606401610552565b33614a3e6040890160208a01614da0565b6001600160a01b031688357f32bc401d77ffde781b234d480866e0c360e724770a30ea3299309f9171e400ef8761233660808d0160608e01614ef9565b60007f7ddd38ab5ed1c16b61ca90eeb9579e29da1ba821cf42d8cdef8f30a31a6a41468235614ab06040850160208601614da0565b614ac06060860160408701614da0565b614ad06080870160608801614ef9565b614ae060a0880160808901614ef9565b8760a001358860c001358960e001358a6101000135604051602001614b5c9a99989796959493929190998a5260208a01989098526001600160a01b0396871660408a01529490951660608801529115156080870152151560a086015260c085015260e08401919091526101008301526101208201526101400190565b604051602081830303815290604052805190602001209050919050565b60007f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a060408301351115614bef5760405162461bcd60e51b815260206004820152601b60248201527f696e76616c6964207369676e6174757265202273222076616c756500000000006044820152606401610552565b614bfc6020830183614ff4565b60ff16601b1480614c1c5750614c156020830183614ff4565b60ff16601c145b614c685760405162461bcd60e51b815260206004820152601b60248201527f696e76616c6964207369676e6174757265202276222076616c756500000000006044820152606401610552565b600183614c786020850185614ff4565b604080516000815260208181018084529490945260ff9092168282015291850135606082015290840135608082015260a0016020604051602081039080840390855afa158015614ccc573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00151949350505050565b60008083601f840112614d0d578182fd5b50813567ffffffffffffffff811115614d24578182fd5b602083019150836020606083028501011115614d3f57600080fd5b9250929050565b60008083601f840112614d57578182fd5b50813567ffffffffffffffff811115614d6e578182fd5b6020830191508360208260051b8501011115614d3f57600080fd5b803561ffff81168114614d9b57600080fd5b919050565b600060208284031215614db1578081fd5b8135611e9481615161565b600060208284031215614dcd578081fd5b8151611e9481615161565b60008060408385031215614dea578081fd5b8235614df581615161565b946020939093013593505050565b600080600060608486031215614e17578081fd5b8335614e2281615161565b95602085013595506040909401359392505050565b60008060008060008060608789031215614e4f578182fd5b863567ffffffffffffffff80821115614e66578384fd5b818901915089601f830112614e79578384fd5b813581811115614e87578485fd5b8a602061012083028501011115614e9c578485fd5b602092830198509650908801359080821115614eb6578384fd5b614ec28a838b01614d46565b90965094506040890135915080821115614eda578384fd5b50614ee789828a01614cfc565b979a9699509497509295939492505050565b600060208284031215614f0a578081fd5b8135611e9481615179565b600060208284031215614f26578081fd5b8151611e9481615179565b600060208284031215614f42578081fd5b5035919050565b600080828403610180811215614f5d578283fd5b61012080821215614f6c578384fd5b84935060607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee083011215614f9e578283fd5b92959390920193505050565b60008060408385031215614fbc578182fd5b614fc583614d89565b9150614fd360208401614d89565b90509250929050565b600060208284031215614fed578081fd5b5051919050565b600060208284031215615005578081fd5b813560ff81168114611e94578182fd5b6000602080835283518082850152825b8181101561504157858101830151858201604001528201615025565b818111156150525783604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016929092016040019392505050565b600082198211156150995761509961514b565b500190565b6000826150b957634e487b7160e01b81526012600452602481fd5b500490565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156150f6576150f661514b565b500290565b60008282101561510d5761510d61514b565b500390565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8214156151445761514461514b565b5060010190565b634e487b7160e01b600052601160045260246000fd5b6001600160a01b038116811461517657600080fd5b50565b801515811461517657600080fdfea26469706673582212204350d7df97aa463f28be506e125a157aad36ae11c989b1194f02096b4a5bf28f64736f6c63430008040033" + +// DeploySwivel deploys a new Ethereum contract, binding an instance of Swivel to it. +func DeploySwivel(auth *bind.TransactOpts, backend bind.ContractBackend, m common.Address) (common.Address, *types.Transaction, *Swivel, error) { + parsed, err := abi.JSON(strings.NewReader(SwivelABI)) + if err != nil { + return common.Address{}, nil, nil, err + } + + address, tx, contract, err := bind.DeployContract(auth, parsed, common.FromHex(SwivelBin), backend, m) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &Swivel{SwivelCaller: SwivelCaller{contract: contract}, SwivelTransactor: SwivelTransactor{contract: contract}, SwivelFilterer: SwivelFilterer{contract: contract}}, nil +} + +// Swivel is an auto generated Go binding around an Ethereum contract. +type Swivel struct { + SwivelCaller // Read-only binding to the contract + SwivelTransactor // Write-only binding to the contract + SwivelFilterer // Log filterer for contract events +} + +// SwivelCaller is an auto generated read-only Go binding around an Ethereum contract. +type SwivelCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// SwivelTransactor is an auto generated write-only Go binding around an Ethereum contract. +type SwivelTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// SwivelFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type SwivelFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// SwivelSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type SwivelSession struct { + Contract *Swivel // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// SwivelCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type SwivelCallerSession struct { + Contract *SwivelCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// SwivelTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type SwivelTransactorSession struct { + Contract *SwivelTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// SwivelRaw is an auto generated low-level Go binding around an Ethereum contract. +type SwivelRaw struct { + Contract *Swivel // Generic contract binding to access the raw methods on +} + +// SwivelCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type SwivelCallerRaw struct { + Contract *SwivelCaller // Generic read-only contract binding to access the raw methods on +} + +// SwivelTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type SwivelTransactorRaw struct { + Contract *SwivelTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewSwivel creates a new instance of Swivel, bound to a specific deployed contract. +func NewSwivel(address common.Address, backend bind.ContractBackend) (*Swivel, error) { + contract, err := bindSwivel(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &Swivel{SwivelCaller: SwivelCaller{contract: contract}, SwivelTransactor: SwivelTransactor{contract: contract}, SwivelFilterer: SwivelFilterer{contract: contract}}, nil +} + +// NewSwivelCaller creates a new read-only instance of Swivel, bound to a specific deployed contract. +func NewSwivelCaller(address common.Address, caller bind.ContractCaller) (*SwivelCaller, error) { + contract, err := bindSwivel(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &SwivelCaller{contract: contract}, nil +} + +// NewSwivelTransactor creates a new write-only instance of Swivel, bound to a specific deployed contract. +func NewSwivelTransactor(address common.Address, transactor bind.ContractTransactor) (*SwivelTransactor, error) { + contract, err := bindSwivel(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &SwivelTransactor{contract: contract}, nil +} + +// NewSwivelFilterer creates a new log filterer instance of Swivel, bound to a specific deployed contract. +func NewSwivelFilterer(address common.Address, filterer bind.ContractFilterer) (*SwivelFilterer, error) { + contract, err := bindSwivel(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &SwivelFilterer{contract: contract}, nil +} + +// bindSwivel binds a generic wrapper to an already deployed contract. +func bindSwivel(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := abi.JSON(strings.NewReader(SwivelABI)) + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_Swivel *SwivelRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _Swivel.Contract.SwivelCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_Swivel *SwivelRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Swivel.Contract.SwivelTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_Swivel *SwivelRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _Swivel.Contract.SwivelTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_Swivel *SwivelCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _Swivel.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_Swivel *SwivelTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Swivel.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_Swivel *SwivelTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _Swivel.Contract.contract.Transact(opts, method, params...) +} + +// HOLD is a free data retrieval call binding the contract method 0xd0886f97. +// +// Solidity: function HOLD() view returns(uint256) +func (_Swivel *SwivelCaller) HOLD(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _Swivel.contract.Call(opts, &out, "HOLD") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// HOLD is a free data retrieval call binding the contract method 0xd0886f97. +// +// Solidity: function HOLD() view returns(uint256) +func (_Swivel *SwivelSession) HOLD() (*big.Int, error) { + return _Swivel.Contract.HOLD(&_Swivel.CallOpts) +} + +// HOLD is a free data retrieval call binding the contract method 0xd0886f97. +// +// Solidity: function HOLD() view returns(uint256) +func (_Swivel *SwivelCallerSession) HOLD() (*big.Int, error) { + return _Swivel.Contract.HOLD(&_Swivel.CallOpts) +} + +// NAME is a free data retrieval call binding the contract method 0xa3f4df7e. +// +// Solidity: function NAME() view returns(string) +func (_Swivel *SwivelCaller) NAME(opts *bind.CallOpts) (string, error) { + var out []interface{} + err := _Swivel.contract.Call(opts, &out, "NAME") + + if err != nil { + return *new(string), err + } + + out0 := *abi.ConvertType(out[0], new(string)).(*string) + + return out0, err + +} + +// NAME is a free data retrieval call binding the contract method 0xa3f4df7e. +// +// Solidity: function NAME() view returns(string) +func (_Swivel *SwivelSession) NAME() (string, error) { + return _Swivel.Contract.NAME(&_Swivel.CallOpts) +} + +// NAME is a free data retrieval call binding the contract method 0xa3f4df7e. +// +// Solidity: function NAME() view returns(string) +func (_Swivel *SwivelCallerSession) NAME() (string, error) { + return _Swivel.Contract.NAME(&_Swivel.CallOpts) +} + +// VERSION is a free data retrieval call binding the contract method 0xffa1ad74. +// +// Solidity: function VERSION() view returns(string) +func (_Swivel *SwivelCaller) VERSION(opts *bind.CallOpts) (string, error) { + var out []interface{} + err := _Swivel.contract.Call(opts, &out, "VERSION") + + if err != nil { + return *new(string), err + } + + out0 := *abi.ConvertType(out[0], new(string)).(*string) + + return out0, err + +} + +// VERSION is a free data retrieval call binding the contract method 0xffa1ad74. +// +// Solidity: function VERSION() view returns(string) +func (_Swivel *SwivelSession) VERSION() (string, error) { + return _Swivel.Contract.VERSION(&_Swivel.CallOpts) +} + +// VERSION is a free data retrieval call binding the contract method 0xffa1ad74. +// +// Solidity: function VERSION() view returns(string) +func (_Swivel *SwivelCallerSession) VERSION() (string, error) { + return _Swivel.Contract.VERSION(&_Swivel.CallOpts) +} + +// Admin is a free data retrieval call binding the contract method 0xf851a440. +// +// Solidity: function admin() view returns(address) +func (_Swivel *SwivelCaller) Admin(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _Swivel.contract.Call(opts, &out, "admin") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// Admin is a free data retrieval call binding the contract method 0xf851a440. +// +// Solidity: function admin() view returns(address) +func (_Swivel *SwivelSession) Admin() (common.Address, error) { + return _Swivel.Contract.Admin(&_Swivel.CallOpts) +} + +// Admin is a free data retrieval call binding the contract method 0xf851a440. +// +// Solidity: function admin() view returns(address) +func (_Swivel *SwivelCallerSession) Admin() (common.Address, error) { + return _Swivel.Contract.Admin(&_Swivel.CallOpts) +} + +// Cancelled is a free data retrieval call binding the contract method 0x2ac12622. +// +// Solidity: function cancelled(bytes32 ) view returns(bool) +func (_Swivel *SwivelCaller) Cancelled(opts *bind.CallOpts, arg0 [32]byte) (bool, error) { + var out []interface{} + err := _Swivel.contract.Call(opts, &out, "cancelled", arg0) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// Cancelled is a free data retrieval call binding the contract method 0x2ac12622. +// +// Solidity: function cancelled(bytes32 ) view returns(bool) +func (_Swivel *SwivelSession) Cancelled(arg0 [32]byte) (bool, error) { + return _Swivel.Contract.Cancelled(&_Swivel.CallOpts, arg0) +} + +// Cancelled is a free data retrieval call binding the contract method 0x2ac12622. +// +// Solidity: function cancelled(bytes32 ) view returns(bool) +func (_Swivel *SwivelCallerSession) Cancelled(arg0 [32]byte) (bool, error) { + return _Swivel.Contract.Cancelled(&_Swivel.CallOpts, arg0) +} + +// Domain is a free data retrieval call binding the contract method 0xc2fb26a6. +// +// Solidity: function domain() view returns(bytes32) +func (_Swivel *SwivelCaller) Domain(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _Swivel.contract.Call(opts, &out, "domain") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// Domain is a free data retrieval call binding the contract method 0xc2fb26a6. +// +// Solidity: function domain() view returns(bytes32) +func (_Swivel *SwivelSession) Domain() ([32]byte, error) { + return _Swivel.Contract.Domain(&_Swivel.CallOpts) +} + +// Domain is a free data retrieval call binding the contract method 0xc2fb26a6. +// +// Solidity: function domain() view returns(bytes32) +func (_Swivel *SwivelCallerSession) Domain() ([32]byte, error) { + return _Swivel.Contract.Domain(&_Swivel.CallOpts) +} + +// Fenominator is a free data retrieval call binding the contract method 0x33c810e9. +// +// Solidity: function fenominator(uint256 ) view returns(uint16) +func (_Swivel *SwivelCaller) Fenominator(opts *bind.CallOpts, arg0 *big.Int) (uint16, error) { + var out []interface{} + err := _Swivel.contract.Call(opts, &out, "fenominator", arg0) + + if err != nil { + return *new(uint16), err + } + + out0 := *abi.ConvertType(out[0], new(uint16)).(*uint16) + + return out0, err + +} + +// Fenominator is a free data retrieval call binding the contract method 0x33c810e9. +// +// Solidity: function fenominator(uint256 ) view returns(uint16) +func (_Swivel *SwivelSession) Fenominator(arg0 *big.Int) (uint16, error) { + return _Swivel.Contract.Fenominator(&_Swivel.CallOpts, arg0) +} + +// Fenominator is a free data retrieval call binding the contract method 0x33c810e9. +// +// Solidity: function fenominator(uint256 ) view returns(uint16) +func (_Swivel *SwivelCallerSession) Fenominator(arg0 *big.Int) (uint16, error) { + return _Swivel.Contract.Fenominator(&_Swivel.CallOpts, arg0) +} + +// Filled is a free data retrieval call binding the contract method 0x288cdc91. +// +// Solidity: function filled(bytes32 ) view returns(uint256) +func (_Swivel *SwivelCaller) Filled(opts *bind.CallOpts, arg0 [32]byte) (*big.Int, error) { + var out []interface{} + err := _Swivel.contract.Call(opts, &out, "filled", arg0) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// Filled is a free data retrieval call binding the contract method 0x288cdc91. +// +// Solidity: function filled(bytes32 ) view returns(uint256) +func (_Swivel *SwivelSession) Filled(arg0 [32]byte) (*big.Int, error) { + return _Swivel.Contract.Filled(&_Swivel.CallOpts, arg0) +} + +// Filled is a free data retrieval call binding the contract method 0x288cdc91. +// +// Solidity: function filled(bytes32 ) view returns(uint256) +func (_Swivel *SwivelCallerSession) Filled(arg0 [32]byte) (*big.Int, error) { + return _Swivel.Contract.Filled(&_Swivel.CallOpts, arg0) +} + +// MarketPlace is a free data retrieval call binding the contract method 0x2e25d2a6. +// +// Solidity: function marketPlace() view returns(address) +func (_Swivel *SwivelCaller) MarketPlace(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _Swivel.contract.Call(opts, &out, "marketPlace") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// MarketPlace is a free data retrieval call binding the contract method 0x2e25d2a6. +// +// Solidity: function marketPlace() view returns(address) +func (_Swivel *SwivelSession) MarketPlace() (common.Address, error) { + return _Swivel.Contract.MarketPlace(&_Swivel.CallOpts) +} + +// MarketPlace is a free data retrieval call binding the contract method 0x2e25d2a6. +// +// Solidity: function marketPlace() view returns(address) +func (_Swivel *SwivelCallerSession) MarketPlace() (common.Address, error) { + return _Swivel.Contract.MarketPlace(&_Swivel.CallOpts) +} + +// Withdrawals is a free data retrieval call binding the contract method 0x7a9262a2. +// +// Solidity: function withdrawals(address ) view returns(uint256) +func (_Swivel *SwivelCaller) Withdrawals(opts *bind.CallOpts, arg0 common.Address) (*big.Int, error) { + var out []interface{} + err := _Swivel.contract.Call(opts, &out, "withdrawals", arg0) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// Withdrawals is a free data retrieval call binding the contract method 0x7a9262a2. +// +// Solidity: function withdrawals(address ) view returns(uint256) +func (_Swivel *SwivelSession) Withdrawals(arg0 common.Address) (*big.Int, error) { + return _Swivel.Contract.Withdrawals(&_Swivel.CallOpts, arg0) +} + +// Withdrawals is a free data retrieval call binding the contract method 0x7a9262a2. +// +// Solidity: function withdrawals(address ) view returns(uint256) +func (_Swivel *SwivelCallerSession) Withdrawals(arg0 common.Address) (*big.Int, error) { + return _Swivel.Contract.Withdrawals(&_Swivel.CallOpts, arg0) +} + +// BlockWithdrawal is a paid mutator transaction binding the contract method 0xa102e384. +// +// Solidity: function blockWithdrawal(address e) returns() +func (_Swivel *SwivelTransactor) BlockWithdrawal(opts *bind.TransactOpts, e common.Address) (*types.Transaction, error) { + return _Swivel.contract.Transact(opts, "blockWithdrawal", e) +} + +// BlockWithdrawal is a paid mutator transaction binding the contract method 0xa102e384. +// +// Solidity: function blockWithdrawal(address e) returns() +func (_Swivel *SwivelSession) BlockWithdrawal(e common.Address) (*types.Transaction, error) { + return _Swivel.Contract.BlockWithdrawal(&_Swivel.TransactOpts, e) +} + +// BlockWithdrawal is a paid mutator transaction binding the contract method 0xa102e384. +// +// Solidity: function blockWithdrawal(address e) returns() +func (_Swivel *SwivelTransactorSession) BlockWithdrawal(e common.Address) (*types.Transaction, error) { + return _Swivel.Contract.BlockWithdrawal(&_Swivel.TransactOpts, e) +} + +// Cancel is a paid mutator transaction binding the contract method 0x3e1608b4. +// +// Solidity: function cancel((bytes32,address,address,bool,bool,uint256,uint256,uint256,uint256) o, (uint8,bytes32,bytes32) c) returns(bool) +func (_Swivel *SwivelTransactor) Cancel(opts *bind.TransactOpts, o HashOrder, c SigComponents) (*types.Transaction, error) { + return _Swivel.contract.Transact(opts, "cancel", o, c) +} + +// Cancel is a paid mutator transaction binding the contract method 0x3e1608b4. +// +// Solidity: function cancel((bytes32,address,address,bool,bool,uint256,uint256,uint256,uint256) o, (uint8,bytes32,bytes32) c) returns(bool) +func (_Swivel *SwivelSession) Cancel(o HashOrder, c SigComponents) (*types.Transaction, error) { + return _Swivel.Contract.Cancel(&_Swivel.TransactOpts, o, c) +} + +// Cancel is a paid mutator transaction binding the contract method 0x3e1608b4. +// +// Solidity: function cancel((bytes32,address,address,bool,bool,uint256,uint256,uint256,uint256) o, (uint8,bytes32,bytes32) c) returns(bool) +func (_Swivel *SwivelTransactorSession) Cancel(o HashOrder, c SigComponents) (*types.Transaction, error) { + return _Swivel.Contract.Cancel(&_Swivel.TransactOpts, o, c) +} + +// CombineTokens is a paid mutator transaction binding the contract method 0x0908ff2d. +// +// Solidity: function combineTokens(address u, uint256 m, uint256 a) returns(bool) +func (_Swivel *SwivelTransactor) CombineTokens(opts *bind.TransactOpts, u common.Address, m *big.Int, a *big.Int) (*types.Transaction, error) { + return _Swivel.contract.Transact(opts, "combineTokens", u, m, a) +} + +// CombineTokens is a paid mutator transaction binding the contract method 0x0908ff2d. +// +// Solidity: function combineTokens(address u, uint256 m, uint256 a) returns(bool) +func (_Swivel *SwivelSession) CombineTokens(u common.Address, m *big.Int, a *big.Int) (*types.Transaction, error) { + return _Swivel.Contract.CombineTokens(&_Swivel.TransactOpts, u, m, a) +} + +// CombineTokens is a paid mutator transaction binding the contract method 0x0908ff2d. +// +// Solidity: function combineTokens(address u, uint256 m, uint256 a) returns(bool) +func (_Swivel *SwivelTransactorSession) CombineTokens(u common.Address, m *big.Int, a *big.Int) (*types.Transaction, error) { + return _Swivel.Contract.CombineTokens(&_Swivel.TransactOpts, u, m, a) +} + +// Exit is a paid mutator transaction binding the contract method 0xaba28701. +// +// Solidity: function exit((bytes32,address,address,bool,bool,uint256,uint256,uint256,uint256)[] o, uint256[] a, (uint8,bytes32,bytes32)[] c) returns(bool) +func (_Swivel *SwivelTransactor) Exit(opts *bind.TransactOpts, o []HashOrder, a []*big.Int, c []SigComponents) (*types.Transaction, error) { + return _Swivel.contract.Transact(opts, "exit", o, a, c) +} + +// Exit is a paid mutator transaction binding the contract method 0xaba28701. +// +// Solidity: function exit((bytes32,address,address,bool,bool,uint256,uint256,uint256,uint256)[] o, uint256[] a, (uint8,bytes32,bytes32)[] c) returns(bool) +func (_Swivel *SwivelSession) Exit(o []HashOrder, a []*big.Int, c []SigComponents) (*types.Transaction, error) { + return _Swivel.Contract.Exit(&_Swivel.TransactOpts, o, a, c) +} + +// Exit is a paid mutator transaction binding the contract method 0xaba28701. +// +// Solidity: function exit((bytes32,address,address,bool,bool,uint256,uint256,uint256,uint256)[] o, uint256[] a, (uint8,bytes32,bytes32)[] c) returns(bool) +func (_Swivel *SwivelTransactorSession) Exit(o []HashOrder, a []*big.Int, c []SigComponents) (*types.Transaction, error) { + return _Swivel.Contract.Exit(&_Swivel.TransactOpts, o, a, c) +} + +// Initiate is a paid mutator transaction binding the contract method 0xd2144f58. +// +// Solidity: function initiate((bytes32,address,address,bool,bool,uint256,uint256,uint256,uint256)[] o, uint256[] a, (uint8,bytes32,bytes32)[] c) returns(bool) +func (_Swivel *SwivelTransactor) Initiate(opts *bind.TransactOpts, o []HashOrder, a []*big.Int, c []SigComponents) (*types.Transaction, error) { + return _Swivel.contract.Transact(opts, "initiate", o, a, c) +} + +// Initiate is a paid mutator transaction binding the contract method 0xd2144f58. +// +// Solidity: function initiate((bytes32,address,address,bool,bool,uint256,uint256,uint256,uint256)[] o, uint256[] a, (uint8,bytes32,bytes32)[] c) returns(bool) +func (_Swivel *SwivelSession) Initiate(o []HashOrder, a []*big.Int, c []SigComponents) (*types.Transaction, error) { + return _Swivel.Contract.Initiate(&_Swivel.TransactOpts, o, a, c) +} + +// Initiate is a paid mutator transaction binding the contract method 0xd2144f58. +// +// Solidity: function initiate((bytes32,address,address,bool,bool,uint256,uint256,uint256,uint256)[] o, uint256[] a, (uint8,bytes32,bytes32)[] c) returns(bool) +func (_Swivel *SwivelTransactorSession) Initiate(o []HashOrder, a []*big.Int, c []SigComponents) (*types.Transaction, error) { + return _Swivel.Contract.Initiate(&_Swivel.TransactOpts, o, a, c) +} + +// RedeemVaultInterest is a paid mutator transaction binding the contract method 0x40d37cdf. +// +// Solidity: function redeemVaultInterest(address u, uint256 m) returns(bool) +func (_Swivel *SwivelTransactor) RedeemVaultInterest(opts *bind.TransactOpts, u common.Address, m *big.Int) (*types.Transaction, error) { + return _Swivel.contract.Transact(opts, "redeemVaultInterest", u, m) +} + +// RedeemVaultInterest is a paid mutator transaction binding the contract method 0x40d37cdf. +// +// Solidity: function redeemVaultInterest(address u, uint256 m) returns(bool) +func (_Swivel *SwivelSession) RedeemVaultInterest(u common.Address, m *big.Int) (*types.Transaction, error) { + return _Swivel.Contract.RedeemVaultInterest(&_Swivel.TransactOpts, u, m) +} + +// RedeemVaultInterest is a paid mutator transaction binding the contract method 0x40d37cdf. +// +// Solidity: function redeemVaultInterest(address u, uint256 m) returns(bool) +func (_Swivel *SwivelTransactorSession) RedeemVaultInterest(u common.Address, m *big.Int) (*types.Transaction, error) { + return _Swivel.Contract.RedeemVaultInterest(&_Swivel.TransactOpts, u, m) +} + +// RedeemZcToken is a paid mutator transaction binding the contract method 0x154e0f2e. +// +// Solidity: function redeemZcToken(address u, uint256 m, uint256 a) returns(bool) +func (_Swivel *SwivelTransactor) RedeemZcToken(opts *bind.TransactOpts, u common.Address, m *big.Int, a *big.Int) (*types.Transaction, error) { + return _Swivel.contract.Transact(opts, "redeemZcToken", u, m, a) +} + +// RedeemZcToken is a paid mutator transaction binding the contract method 0x154e0f2e. +// +// Solidity: function redeemZcToken(address u, uint256 m, uint256 a) returns(bool) +func (_Swivel *SwivelSession) RedeemZcToken(u common.Address, m *big.Int, a *big.Int) (*types.Transaction, error) { + return _Swivel.Contract.RedeemZcToken(&_Swivel.TransactOpts, u, m, a) +} + +// RedeemZcToken is a paid mutator transaction binding the contract method 0x154e0f2e. +// +// Solidity: function redeemZcToken(address u, uint256 m, uint256 a) returns(bool) +func (_Swivel *SwivelTransactorSession) RedeemZcToken(u common.Address, m *big.Int, a *big.Int) (*types.Transaction, error) { + return _Swivel.Contract.RedeemZcToken(&_Swivel.TransactOpts, u, m, a) +} + +// ScheduleWithdrawal is a paid mutator transaction binding the contract method 0xf8eaad35. +// +// Solidity: function scheduleWithdrawal(address e) returns() +func (_Swivel *SwivelTransactor) ScheduleWithdrawal(opts *bind.TransactOpts, e common.Address) (*types.Transaction, error) { + return _Swivel.contract.Transact(opts, "scheduleWithdrawal", e) +} + +// ScheduleWithdrawal is a paid mutator transaction binding the contract method 0xf8eaad35. +// +// Solidity: function scheduleWithdrawal(address e) returns() +func (_Swivel *SwivelSession) ScheduleWithdrawal(e common.Address) (*types.Transaction, error) { + return _Swivel.Contract.ScheduleWithdrawal(&_Swivel.TransactOpts, e) +} + +// ScheduleWithdrawal is a paid mutator transaction binding the contract method 0xf8eaad35. +// +// Solidity: function scheduleWithdrawal(address e) returns() +func (_Swivel *SwivelTransactorSession) ScheduleWithdrawal(e common.Address) (*types.Transaction, error) { + return _Swivel.Contract.ScheduleWithdrawal(&_Swivel.TransactOpts, e) +} + +// SetFee is a paid mutator transaction binding the contract method 0x99b64de1. +// +// Solidity: function setFee(uint16 t, uint16 d) returns(bool) +func (_Swivel *SwivelTransactor) SetFee(opts *bind.TransactOpts, t uint16, d uint16) (*types.Transaction, error) { + return _Swivel.contract.Transact(opts, "setFee", t, d) +} + +// SetFee is a paid mutator transaction binding the contract method 0x99b64de1. +// +// Solidity: function setFee(uint16 t, uint16 d) returns(bool) +func (_Swivel *SwivelSession) SetFee(t uint16, d uint16) (*types.Transaction, error) { + return _Swivel.Contract.SetFee(&_Swivel.TransactOpts, t, d) +} + +// SetFee is a paid mutator transaction binding the contract method 0x99b64de1. +// +// Solidity: function setFee(uint16 t, uint16 d) returns(bool) +func (_Swivel *SwivelTransactorSession) SetFee(t uint16, d uint16) (*types.Transaction, error) { + return _Swivel.Contract.SetFee(&_Swivel.TransactOpts, t, d) +} + +// SplitUnderlying is a paid mutator transaction binding the contract method 0x92ae3764. +// +// Solidity: function splitUnderlying(address u, uint256 m, uint256 a) returns(bool) +func (_Swivel *SwivelTransactor) SplitUnderlying(opts *bind.TransactOpts, u common.Address, m *big.Int, a *big.Int) (*types.Transaction, error) { + return _Swivel.contract.Transact(opts, "splitUnderlying", u, m, a) +} + +// SplitUnderlying is a paid mutator transaction binding the contract method 0x92ae3764. +// +// Solidity: function splitUnderlying(address u, uint256 m, uint256 a) returns(bool) +func (_Swivel *SwivelSession) SplitUnderlying(u common.Address, m *big.Int, a *big.Int) (*types.Transaction, error) { + return _Swivel.Contract.SplitUnderlying(&_Swivel.TransactOpts, u, m, a) +} + +// SplitUnderlying is a paid mutator transaction binding the contract method 0x92ae3764. +// +// Solidity: function splitUnderlying(address u, uint256 m, uint256 a) returns(bool) +func (_Swivel *SwivelTransactorSession) SplitUnderlying(u common.Address, m *big.Int, a *big.Int) (*types.Transaction, error) { + return _Swivel.Contract.SplitUnderlying(&_Swivel.TransactOpts, u, m, a) +} + +// Withdraw is a paid mutator transaction binding the contract method 0x51cff8d9. +// +// Solidity: function withdraw(address e) returns() +func (_Swivel *SwivelTransactor) Withdraw(opts *bind.TransactOpts, e common.Address) (*types.Transaction, error) { + return _Swivel.contract.Transact(opts, "withdraw", e) +} + +// Withdraw is a paid mutator transaction binding the contract method 0x51cff8d9. +// +// Solidity: function withdraw(address e) returns() +func (_Swivel *SwivelSession) Withdraw(e common.Address) (*types.Transaction, error) { + return _Swivel.Contract.Withdraw(&_Swivel.TransactOpts, e) +} + +// Withdraw is a paid mutator transaction binding the contract method 0x51cff8d9. +// +// Solidity: function withdraw(address e) returns() +func (_Swivel *SwivelTransactorSession) Withdraw(e common.Address) (*types.Transaction, error) { + return _Swivel.Contract.Withdraw(&_Swivel.TransactOpts, e) +} + +// SwivelCancelIterator is returned from FilterCancel and is used to iterate over the raw logs and unpacked data for Cancel events raised by the Swivel contract. +type SwivelCancelIterator struct { + Event *SwivelCancel // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *SwivelCancelIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(SwivelCancel) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(SwivelCancel) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *SwivelCancelIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *SwivelCancelIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// SwivelCancel represents a Cancel event raised by the Swivel contract. +type SwivelCancel struct { + Key [32]byte + Hash [32]byte + Raw types.Log // Blockchain specific contextual infos +} + +// FilterCancel is a free log retrieval operation binding the contract event 0x9e5d8891dc1b047de610617bc9bc2d8ccffebbc3d63363431a546831245858a6. +// +// Solidity: event Cancel(bytes32 indexed key, bytes32 hash) +func (_Swivel *SwivelFilterer) FilterCancel(opts *bind.FilterOpts, key [][32]byte) (*SwivelCancelIterator, error) { + + var keyRule []interface{} + for _, keyItem := range key { + keyRule = append(keyRule, keyItem) + } + + logs, sub, err := _Swivel.contract.FilterLogs(opts, "Cancel", keyRule) + if err != nil { + return nil, err + } + return &SwivelCancelIterator{contract: _Swivel.contract, event: "Cancel", logs: logs, sub: sub}, nil +} + +// WatchCancel is a free log subscription operation binding the contract event 0x9e5d8891dc1b047de610617bc9bc2d8ccffebbc3d63363431a546831245858a6. +// +// Solidity: event Cancel(bytes32 indexed key, bytes32 hash) +func (_Swivel *SwivelFilterer) WatchCancel(opts *bind.WatchOpts, sink chan<- *SwivelCancel, key [][32]byte) (event.Subscription, error) { + + var keyRule []interface{} + for _, keyItem := range key { + keyRule = append(keyRule, keyItem) + } + + logs, sub, err := _Swivel.contract.WatchLogs(opts, "Cancel", keyRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(SwivelCancel) + if err := _Swivel.contract.UnpackLog(event, "Cancel", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseCancel is a log parse operation binding the contract event 0x9e5d8891dc1b047de610617bc9bc2d8ccffebbc3d63363431a546831245858a6. +// +// Solidity: event Cancel(bytes32 indexed key, bytes32 hash) +func (_Swivel *SwivelFilterer) ParseCancel(log types.Log) (*SwivelCancel, error) { + event := new(SwivelCancel) + if err := _Swivel.contract.UnpackLog(event, "Cancel", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// SwivelExitIterator is returned from FilterExit and is used to iterate over the raw logs and unpacked data for Exit events raised by the Swivel contract. +type SwivelExitIterator struct { + Event *SwivelExit // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *SwivelExitIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(SwivelExit) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(SwivelExit) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *SwivelExitIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *SwivelExitIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// SwivelExit represents a Exit event raised by the Swivel contract. +type SwivelExit struct { + Key [32]byte + Hash [32]byte + Maker common.Address + Vault bool + Exit bool + Sender common.Address + Amount *big.Int + Filled *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterExit is a free log retrieval operation binding the contract event 0x51cad9177cf46d59109ae978bb3cf5ffed2bb3d53fb3682fa56fbd9266712834. +// +// Solidity: event Exit(bytes32 indexed key, bytes32 hash, address indexed maker, bool vault, bool exit, address indexed sender, uint256 amount, uint256 filled) +func (_Swivel *SwivelFilterer) FilterExit(opts *bind.FilterOpts, key [][32]byte, maker []common.Address, sender []common.Address) (*SwivelExitIterator, error) { + + var keyRule []interface{} + for _, keyItem := range key { + keyRule = append(keyRule, keyItem) + } + + var makerRule []interface{} + for _, makerItem := range maker { + makerRule = append(makerRule, makerItem) + } + + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _Swivel.contract.FilterLogs(opts, "Exit", keyRule, makerRule, senderRule) + if err != nil { + return nil, err + } + return &SwivelExitIterator{contract: _Swivel.contract, event: "Exit", logs: logs, sub: sub}, nil +} + +// WatchExit is a free log subscription operation binding the contract event 0x51cad9177cf46d59109ae978bb3cf5ffed2bb3d53fb3682fa56fbd9266712834. +// +// Solidity: event Exit(bytes32 indexed key, bytes32 hash, address indexed maker, bool vault, bool exit, address indexed sender, uint256 amount, uint256 filled) +func (_Swivel *SwivelFilterer) WatchExit(opts *bind.WatchOpts, sink chan<- *SwivelExit, key [][32]byte, maker []common.Address, sender []common.Address) (event.Subscription, error) { + + var keyRule []interface{} + for _, keyItem := range key { + keyRule = append(keyRule, keyItem) + } + + var makerRule []interface{} + for _, makerItem := range maker { + makerRule = append(makerRule, makerItem) + } + + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _Swivel.contract.WatchLogs(opts, "Exit", keyRule, makerRule, senderRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(SwivelExit) + if err := _Swivel.contract.UnpackLog(event, "Exit", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseExit is a log parse operation binding the contract event 0x51cad9177cf46d59109ae978bb3cf5ffed2bb3d53fb3682fa56fbd9266712834. +// +// Solidity: event Exit(bytes32 indexed key, bytes32 hash, address indexed maker, bool vault, bool exit, address indexed sender, uint256 amount, uint256 filled) +func (_Swivel *SwivelFilterer) ParseExit(log types.Log) (*SwivelExit, error) { + event := new(SwivelExit) + if err := _Swivel.contract.UnpackLog(event, "Exit", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// SwivelInitiateIterator is returned from FilterInitiate and is used to iterate over the raw logs and unpacked data for Initiate events raised by the Swivel contract. +type SwivelInitiateIterator struct { + Event *SwivelInitiate // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *SwivelInitiateIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(SwivelInitiate) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(SwivelInitiate) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *SwivelInitiateIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *SwivelInitiateIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// SwivelInitiate represents a Initiate event raised by the Swivel contract. +type SwivelInitiate struct { + Key [32]byte + Hash [32]byte + Maker common.Address + Vault bool + Exit bool + Sender common.Address + Amount *big.Int + Filled *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterInitiate is a free log retrieval operation binding the contract event 0x32bc401d77ffde781b234d480866e0c360e724770a30ea3299309f9171e400ef. +// +// Solidity: event Initiate(bytes32 indexed key, bytes32 hash, address indexed maker, bool vault, bool exit, address indexed sender, uint256 amount, uint256 filled) +func (_Swivel *SwivelFilterer) FilterInitiate(opts *bind.FilterOpts, key [][32]byte, maker []common.Address, sender []common.Address) (*SwivelInitiateIterator, error) { + + var keyRule []interface{} + for _, keyItem := range key { + keyRule = append(keyRule, keyItem) + } + + var makerRule []interface{} + for _, makerItem := range maker { + makerRule = append(makerRule, makerItem) + } + + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _Swivel.contract.FilterLogs(opts, "Initiate", keyRule, makerRule, senderRule) + if err != nil { + return nil, err + } + return &SwivelInitiateIterator{contract: _Swivel.contract, event: "Initiate", logs: logs, sub: sub}, nil +} + +// WatchInitiate is a free log subscription operation binding the contract event 0x32bc401d77ffde781b234d480866e0c360e724770a30ea3299309f9171e400ef. +// +// Solidity: event Initiate(bytes32 indexed key, bytes32 hash, address indexed maker, bool vault, bool exit, address indexed sender, uint256 amount, uint256 filled) +func (_Swivel *SwivelFilterer) WatchInitiate(opts *bind.WatchOpts, sink chan<- *SwivelInitiate, key [][32]byte, maker []common.Address, sender []common.Address) (event.Subscription, error) { + + var keyRule []interface{} + for _, keyItem := range key { + keyRule = append(keyRule, keyItem) + } + + var makerRule []interface{} + for _, makerItem := range maker { + makerRule = append(makerRule, makerItem) + } + + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _Swivel.contract.WatchLogs(opts, "Initiate", keyRule, makerRule, senderRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(SwivelInitiate) + if err := _Swivel.contract.UnpackLog(event, "Initiate", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseInitiate is a log parse operation binding the contract event 0x32bc401d77ffde781b234d480866e0c360e724770a30ea3299309f9171e400ef. +// +// Solidity: event Initiate(bytes32 indexed key, bytes32 hash, address indexed maker, bool vault, bool exit, address indexed sender, uint256 amount, uint256 filled) +func (_Swivel *SwivelFilterer) ParseInitiate(log types.Log) (*SwivelInitiate, error) { + event := new(SwivelInitiate) + if err := _Swivel.contract.UnpackLog(event, "Initiate", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// SwivelWithdrawalScheduledIterator is returned from FilterWithdrawalScheduled and is used to iterate over the raw logs and unpacked data for WithdrawalScheduled events raised by the Swivel contract. +type SwivelWithdrawalScheduledIterator struct { + Event *SwivelWithdrawalScheduled // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *SwivelWithdrawalScheduledIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(SwivelWithdrawalScheduled) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(SwivelWithdrawalScheduled) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *SwivelWithdrawalScheduledIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *SwivelWithdrawalScheduledIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// SwivelWithdrawalScheduled represents a WithdrawalScheduled event raised by the Swivel contract. +type SwivelWithdrawalScheduled struct { + Token common.Address + Hold *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterWithdrawalScheduled is a free log retrieval operation binding the contract event 0xd9cf0116e5bb6fbe3d257dc8d1ee7ae76c303efeae77f1e93024d2cb218bedd3. +// +// Solidity: event WithdrawalScheduled(address indexed token, uint256 hold) +func (_Swivel *SwivelFilterer) FilterWithdrawalScheduled(opts *bind.FilterOpts, token []common.Address) (*SwivelWithdrawalScheduledIterator, error) { + + var tokenRule []interface{} + for _, tokenItem := range token { + tokenRule = append(tokenRule, tokenItem) + } + + logs, sub, err := _Swivel.contract.FilterLogs(opts, "WithdrawalScheduled", tokenRule) + if err != nil { + return nil, err + } + return &SwivelWithdrawalScheduledIterator{contract: _Swivel.contract, event: "WithdrawalScheduled", logs: logs, sub: sub}, nil +} + +// WatchWithdrawalScheduled is a free log subscription operation binding the contract event 0xd9cf0116e5bb6fbe3d257dc8d1ee7ae76c303efeae77f1e93024d2cb218bedd3. +// +// Solidity: event WithdrawalScheduled(address indexed token, uint256 hold) +func (_Swivel *SwivelFilterer) WatchWithdrawalScheduled(opts *bind.WatchOpts, sink chan<- *SwivelWithdrawalScheduled, token []common.Address) (event.Subscription, error) { + + var tokenRule []interface{} + for _, tokenItem := range token { + tokenRule = append(tokenRule, tokenItem) + } + + logs, sub, err := _Swivel.contract.WatchLogs(opts, "WithdrawalScheduled", tokenRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(SwivelWithdrawalScheduled) + if err := _Swivel.contract.UnpackLog(event, "WithdrawalScheduled", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseWithdrawalScheduled is a log parse operation binding the contract event 0xd9cf0116e5bb6fbe3d257dc8d1ee7ae76c303efeae77f1e93024d2cb218bedd3. +// +// Solidity: event WithdrawalScheduled(address indexed token, uint256 hold) +func (_Swivel *SwivelFilterer) ParseWithdrawalScheduled(log types.Log) (*SwivelWithdrawalScheduled, error) { + event := new(SwivelWithdrawalScheduled) + if err := _Swivel.contract.UnpackLog(event, "WithdrawalScheduled", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} diff --git a/gost/test/tokens/Erc2612.abi b/gost/test/tokens/Erc2612.abi new file mode 100644 index 0000000..759ac33 --- /dev/null +++ b/gost/test/tokens/Erc2612.abi @@ -0,0 +1 @@ +[{"inputs":[{"internalType":"string","name":"n","type":"string"},{"internalType":"string","name":"s","type":"string"},{"internalType":"uint8","name":"d","type":"uint8"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"address","name":"o","type":"address"},{"internalType":"address","name":"s","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"s","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"a","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"s","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"domain","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"s","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"o","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"},{"internalType":"uint256","name":"d","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"r","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"s","type":"address"},{"internalType":"address","name":"r","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file diff --git a/gost/test/tokens/Erc2612.bin b/gost/test/tokens/Erc2612.bin new file mode 100644 index 0000000..87cf195 --- /dev/null +++ b/gost/test/tokens/Erc2612.bin @@ -0,0 +1 @@ +60a06040523480156200001157600080fd5b5060405162001f2138038062001f21833981810160405281019062000037919062000285565b8282828260049080519060200190620000529291906200014c565b5081600590805190602001906200006b9291906200014c565b5080600260006101000a81548160ff021916908360ff160217905550505050620000d8836040518060400160405280600181526020017f31000000000000000000000000000000000000000000000000000000000000008152504630620000e860201b620009ec1760201c565b60808181525050505050620004a4565b60008085516020870120855160208701206040517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f815282602082015281604082015286606082015285608082015260a08120935050505080915050949350505050565b8280546200015a90620003af565b90600052602060002090601f0160209004810192826200017e5760008555620001ca565b82601f106200019957805160ff1916838001178555620001ca565b82800160010185558215620001ca579182015b82811115620001c9578251825591602001919060010190620001ac565b5b509050620001d99190620001dd565b5090565b5b80821115620001f8576000816000905550600101620001de565b5090565b6000620002136200020d8462000336565b6200030d565b9050828152602081018484840111156200022c57600080fd5b6200023984828562000379565b509392505050565b600082601f8301126200025357600080fd5b815162000265848260208601620001fc565b91505092915050565b6000815190506200027f816200048a565b92915050565b6000806000606084860312156200029b57600080fd5b600084015167ffffffffffffffff811115620002b657600080fd5b620002c48682870162000241565b935050602084015167ffffffffffffffff811115620002e257600080fd5b620002f08682870162000241565b925050604062000303868287016200026e565b9150509250925092565b6000620003196200032c565b9050620003278282620003e5565b919050565b6000604051905090565b600067ffffffffffffffff8211156200035457620003536200044a565b5b6200035f8262000479565b9050602081019050919050565b600060ff82169050919050565b60005b83811015620003995780820151818401526020810190506200037c565b83811115620003a9576000848401525b50505050565b60006002820490506001821680620003c857607f821691505b60208210811415620003df57620003de6200041b565b5b50919050565b620003f08262000479565b810181811067ffffffffffffffff821117156200041257620004116200044a565b5b80604052505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000601f19601f8301169050919050565b62000495816200036c565b8114620004a157600080fd5b50565b608051611a5a620004c76000396000818161075d015261082d0152611a5a6000f3fe608060405234801561001057600080fd5b50600436106100ea5760003560e01c80637ecebe001161008c578063a9059cbb11610066578063a9059cbb14610287578063c2fb26a6146102b7578063d505accf146102d5578063dd62ed3e146102f1576100ea565b80637ecebe001461020957806395d89b4114610239578063a457c2d714610257576100ea565b806323b872dd116100c857806323b872dd1461015b578063313ce5671461018b57806339509351146101a957806370a08231146101d9576100ea565b806306fdde03146100ef578063095ea7b31461010d57806318160ddd1461013d575b600080fd5b6100f7610321565b60405161010491906113b3565b60405180910390f35b610127600480360381019061012291906110dc565b6103af565b60405161013491906112d7565b60405180910390f35b6101456103c6565b60405161015291906114f5565b60405180910390f35b61017560048036038101906101709190610fef565b6103cc565b60405161018291906112d7565b60405180910390f35b6101936104bf565b6040516101a09190611510565b60405180910390f35b6101c360048036038101906101be91906110dc565b6104d2565b6040516101d091906112d7565b60405180910390f35b6101f360048036038101906101ee9190610f8a565b610570565b60405161020091906114f5565b60405180910390f35b610223600480360381019061021e9190610f8a565b6105b8565b60405161023091906114f5565b60405180910390f35b6102416105d0565b60405161024e91906113b3565b60405180910390f35b610271600480360381019061026c91906110dc565b61065e565b60405161027e91906112d7565b60405180910390f35b6102a1600480360381019061029c91906110dc565b610744565b6040516102ae91906112d7565b60405180910390f35b6102bf61075b565b6040516102cc91906112f2565b60405180910390f35b6102ef60048036038101906102ea919061103e565b61077f565b005b61030b60048036038101906103069190610fb3565b610965565b60405161031891906114f5565b60405180910390f35b6004805461032e90611663565b80601f016020809104026020016040519081016040528092919081815260200182805461035a90611663565b80156103a75780601f1061037c576101008083540402835291602001916103a7565b820191906000526020600020905b81548152906001019060200180831161038a57829003601f168201915b505050505081565b60006103bc338484610a50565b6001905092915050565b60035481565b60006103d9848484610c1b565b6000600160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490508281101561049d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161049490611495565b60405180910390fd5b6104b3853385846104ae919061159d565b610a50565b60019150509392505050565b600260009054906101000a900460ff1681565b6000610566338484600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546105619190611547565b610a50565b6001905092915050565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b60066020528060005260406000206000915090505481565b600580546105dd90611663565b80601f016020809104026020016040519081016040528092919081815260200182805461060990611663565b80156106565780601f1061062b57610100808354040283529160200191610656565b820191906000526020600020905b81548152906001019060200180831161063957829003601f168201915b505050505081565b600080600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905082811015610723576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161071a906114d5565b60405180910390fd5b61073933858584610734919061159d565b610a50565b600191505092915050565b6000610751338484610c1b565b6001905092915050565b7f000000000000000000000000000000000000000000000000000000000000000081565b428410156107c2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107b990611455565b60405180910390fd5b6000610824888888600660008d73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600081548092919061081a90611695565b9190505589610e8f565b905060006108527f000000000000000000000000000000000000000000000000000000000000000083610ef0565b9050600060018287878760405160008152602001604052604051610879949392919061136e565b6020604051602081039080840390855afa15801561089b573d6000803e3d6000fd5b505050602060405103519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415801561090f57508973ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16145b61094e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161094590611475565b60405180910390fd5b6109598a8a8a610a50565b50505050505050505050565b6000600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905092915050565b60008085516020870120855160208701206040517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f815282602082015281604082015286606082015285608082015260a08120935050505080915050949350505050565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415610ac0576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610ab7906114b5565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415610b30576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b27906113f5565b60405180910390fd5b80600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92583604051610c0e91906114f5565b60405180910390a3505050565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415610c8b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c8290611415565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415610cfb576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610cf2906113d5565b60405180910390fd5b60008060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905081811015610d81576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d7890611435565b60405180910390fd5b8181610d8d919061159d565b6000808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254610e1d9190611547565b925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84604051610e8191906114f5565b60405180910390a350505050565b60007f80772249b4aef1688b30651778f4249b05cb73b517d98482439b9d8999b3060260001b8686868686604051602001610ecf9695949392919061130d565b60405160208183030381529060405280519060200120905095945050505050565b6000806040517f19010000000000000000000000000000000000000000000000000000000000008152846002820152836022820152604281209150508091505092915050565b600081359050610f45816119c8565b92915050565b600081359050610f5a816119df565b92915050565b600081359050610f6f816119f6565b92915050565b600081359050610f8481611a0d565b92915050565b600060208284031215610f9c57600080fd5b6000610faa84828501610f36565b91505092915050565b60008060408385031215610fc657600080fd5b6000610fd485828601610f36565b9250506020610fe585828601610f36565b9150509250929050565b60008060006060848603121561100457600080fd5b600061101286828701610f36565b935050602061102386828701610f36565b925050604061103486828701610f60565b9150509250925092565b600080600080600080600060e0888a03121561105957600080fd5b60006110678a828b01610f36565b97505060206110788a828b01610f36565b96505060406110898a828b01610f60565b955050606061109a8a828b01610f60565b94505060806110ab8a828b01610f75565b93505060a06110bc8a828b01610f4b565b92505060c06110cd8a828b01610f4b565b91505092959891949750929550565b600080604083850312156110ef57600080fd5b60006110fd85828601610f36565b925050602061110e85828601610f60565b9150509250929050565b611121816115d1565b82525050565b611130816115e3565b82525050565b61113f816115ef565b82525050565b60006111508261152b565b61115a8185611536565b935061116a818560208601611630565b6111738161173c565b840191505092915050565b600061118b602283611536565b91506111968261174d565b604082019050919050565b60006111ae602183611536565b91506111b98261179c565b604082019050919050565b60006111d1602483611536565b91506111dc826117eb565b604082019050919050565b60006111f4602583611536565b91506111ff8261183a565b604082019050919050565b6000611217601883611536565b915061122282611889565b602082019050919050565b600061123a601983611536565b9150611245826118b2565b602082019050919050565b600061125d602783611536565b9150611268826118db565b604082019050919050565b6000611280602383611536565b915061128b8261192a565b604082019050919050565b60006112a3602483611536565b91506112ae82611979565b604082019050919050565b6112c281611619565b82525050565b6112d181611623565b82525050565b60006020820190506112ec6000830184611127565b92915050565b60006020820190506113076000830184611136565b92915050565b600060c0820190506113226000830189611136565b61132f6020830188611118565b61133c6040830187611118565b61134960608301866112b9565b61135660808301856112b9565b61136360a08301846112b9565b979650505050505050565b60006080820190506113836000830187611136565b61139060208301866112c8565b61139d6040830185611136565b6113aa6060830184611136565b95945050505050565b600060208201905081810360008301526113cd8184611145565b905092915050565b600060208201905081810360008301526113ee8161117e565b9050919050565b6000602082019050818103600083015261140e816111a1565b9050919050565b6000602082019050818103600083015261142e816111c4565b9050919050565b6000602082019050818103600083015261144e816111e7565b9050919050565b6000602082019050818103600083015261146e8161120a565b9050919050565b6000602082019050818103600083015261148e8161122d565b9050919050565b600060208201905081810360008301526114ae81611250565b9050919050565b600060208201905081810360008301526114ce81611273565b9050919050565b600060208201905081810360008301526114ee81611296565b9050919050565b600060208201905061150a60008301846112b9565b92915050565b600060208201905061152560008301846112c8565b92915050565b600081519050919050565b600082825260208201905092915050565b600061155282611619565b915061155d83611619565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff03821115611592576115916116de565b5b828201905092915050565b60006115a882611619565b91506115b383611619565b9250828210156115c6576115c56116de565b5b828203905092915050565b60006115dc826115f9565b9050919050565b60008115159050919050565b6000819050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b600060ff82169050919050565b60005b8381101561164e578082015181840152602081019050611633565b8381111561165d576000848401525b50505050565b6000600282049050600182168061167b57607f821691505b6020821081141561168f5761168e61170d565b5b50919050565b60006116a082611619565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8214156116d3576116d26116de565b5b600182019050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b6000601f19601f8301169050919050565b7f6572633230207472616e7366657220746f20746865207a65726f20616464726560008201527f7373000000000000000000000000000000000000000000000000000000000000602082015250565b7f657263323020617070726f766520746f20746865207a65726f2061646472657360008201527f7300000000000000000000000000000000000000000000000000000000000000602082015250565b7f6572633230207472616e736665722066726f6d20746865207a65726f2061646460008201527f7265737300000000000000000000000000000000000000000000000000000000602082015250565b7f6572633230207472616e7366657220616d6f756e74206578636565647320626160008201527f6c616e6365000000000000000000000000000000000000000000000000000000602082015250565b7f65726332363132206578706972656420646561646c696e650000000000000000600082015250565b7f6572633236313220696e76616c6964207369676e617475726500000000000000600082015250565b7f6572633230207472616e7366657220616d6f756e74206578636565647320616c60008201527f6c6f77616e636500000000000000000000000000000000000000000000000000602082015250565b7f657263323020617070726f76652066726f6d20746865207a65726f206164647260008201527f6573730000000000000000000000000000000000000000000000000000000000602082015250565b7f65726332302064656372656173656420616c6c6f77616e63652062656c6f772060008201527f7a65726f00000000000000000000000000000000000000000000000000000000602082015250565b6119d1816115d1565b81146119dc57600080fd5b50565b6119e8816115ef565b81146119f357600080fd5b50565b6119ff81611619565b8114611a0a57600080fd5b50565b611a1681611623565b8114611a2157600080fd5b5056fea2646970667358221220ce448f13656609b5234b80481804557158eb409f18c031446de786b122f9111d64736f6c63430008040033 \ No newline at end of file diff --git a/gost/test/tokens/Erc2612.sol b/gost/test/tokens/Erc2612.sol new file mode 100644 index 0000000..eddc366 --- /dev/null +++ b/gost/test/tokens/Erc2612.sol @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// Adapted from OpenZeppelin ERC2612 (ERC20Permit) + +pragma solidity 0.8.4; + +import './Hash.sol'; +import './PErc20.sol'; +import './IErc2612.sol'; + +/** +* @dev Extension of {ERC20} that allows token holders to use their tokens +* without sending any transactions by setting {IERC20-allowance} with a +* signature using the {permit} method, and then spend them via +* {IERC20-transferFrom}. +* NOTE: Naming convention is kept OZStyle vs our own OzStyle to prevent clashing +* +* The {permit} signature mechanism conforms to the {IERC2612} interface. +*/ +contract Erc2612 is PErc20, IErc2612 { + mapping (address => uint256) public override nonces; + + bytes32 public immutable domain; + + /// @param n name for the token + /// @param s symbol for the token + /// @param d decimals for the token + constructor(string memory n, string memory s, uint8 d) PErc20(n, s, d) { + domain = Hash.domain(n, '1', block.chainid, address(this)); + } + + /** + * @dev See {IERC2612-permit}. + * + * In cases where the free option is not a concern, deadline can simply be + * set to uint(-1), so it should be seen as an optional parameter + * + * @param o Address of the owner + * @param spender Address of the spender + * @param a Amount to be approved + * @param d Deadline at which the permission is no longer valid + * NOTE: Last three args (v, r, s) are the components of a valid ECDSA signature + */ + function permit(address o, address spender, uint256 a, uint256 d, uint8 v, bytes32 r, bytes32 s) public virtual override { + require(d >= block.timestamp, 'erc2612 expired deadline'); + + bytes32 hashStruct = Hash.permit(o, spender, a, nonces[o]++, d); + bytes32 hash = Hash.message(domain, hashStruct); + address signer = ecrecover(hash, v, r, s); + + require(signer != address(0) && signer == o, 'erc2612 invalid signature'); + _approve(o, spender, a); + } +} diff --git a/gost/test/tokens/Hash.abi b/gost/test/tokens/Hash.abi new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/gost/test/tokens/Hash.abi @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/gost/test/tokens/Hash.bin b/gost/test/tokens/Hash.bin new file mode 100644 index 0000000..215fb7e --- /dev/null +++ b/gost/test/tokens/Hash.bin @@ -0,0 +1 @@ +60566050600b82828239805160001a6073146043577f4e487b7100000000000000000000000000000000000000000000000000000000600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220a2a6fdc61e66714b737046ba3bcf23174b5f081d1642c0802699742dba15119764736f6c63430008040033 \ No newline at end of file diff --git a/gost/test/tokens/Hash.sol b/gost/test/tokens/Hash.sol new file mode 100644 index 0000000..861dc3f --- /dev/null +++ b/gost/test/tokens/Hash.sol @@ -0,0 +1,80 @@ +// SPDX-License-Identifier: UNLICENSED + +pragma solidity 0.8.4; + +/** + @notice Encapsulation of the logic to produce EIP712 hashed domain and messages. + Also to produce / verify hashed and signed Permits. +*/ + +library Hash { + // EIP712 Domain Separator typeHash + // keccak256(abi.encodePacked( + // 'EIP712Domain(', + // 'string name,', + // 'string version,', + // 'uint256 chainId,', + // 'address verifyingContract', + // ')' + // )); + bytes32 constant internal DOMAIN_TYPEHASH = 0x8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f; + + // EIP2612 typeHash of a Permit + // keccak256(abi.encodePacked( + // 'Permit(', + // 'address owner,', + // 'address spender,', + // 'uint256 value,', + // 'uint256 nonce,', + // 'uint256 deadline,', + // ')' + // )); + bytes32 constant internal PERMIT_TYPEHASH = 0x80772249b4aef1688b30651778f4249b05cb73b517d98482439b9d8999b30602; + + /// @param n EIP712 domain name + /// @param version EIP712 semantic version string + /// @param i Chain ID + /// @param verifier address of the verifying contract + function domain(string memory n, string memory version, uint256 i, address verifier) internal pure returns (bytes32) { + bytes32 hash; + + assembly { + let nameHash := keccak256(add(n, 32), mload(n)) + let versionHash := keccak256(add(version, 32), mload(version)) + let pointer := mload(64) + mstore(pointer, DOMAIN_TYPEHASH) + mstore(add(pointer, 32), nameHash) + mstore(add(pointer, 64), versionHash) + mstore(add(pointer, 96), i) + mstore(add(pointer, 128), verifier) + hash := keccak256(pointer, 160) + } + + return hash; + } + + /// @param d Type hash of the domain separator (see Hash.domain) + /// @param h EIP712 hash struct (Permit for example) + function message(bytes32 d, bytes32 h) internal pure returns (bytes32) { + bytes32 hash; + + assembly { + let pointer := mload(64) + mstore(pointer, 0x1901000000000000000000000000000000000000000000000000000000000000) + mstore(add(pointer, 2), d) + mstore(add(pointer, 34), h) + hash := keccak256(pointer, 66) + } + + return hash; + } + + /// @param o Address of the owner + /// @param s Address of the spender + /// @param a Amount to be approved + /// @param n Current nonce + /// @param d Deadline at which the permission is no longer valid + function permit(address o, address s, uint256 a, uint256 n, uint256 d) internal pure returns (bytes32) { + return keccak256(abi.encode(PERMIT_TYPEHASH, o, s, a, n, d)); + } +} diff --git a/gost/test/tokens/IErc2612.abi b/gost/test/tokens/IErc2612.abi new file mode 100644 index 0000000..5afedea --- /dev/null +++ b/gost/test/tokens/IErc2612.abi @@ -0,0 +1 @@ +[{"inputs":[{"internalType":"address","name":"o","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"o","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"},{"internalType":"uint256","name":"d","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file diff --git a/gost/test/tokens/IErc2612.bin b/gost/test/tokens/IErc2612.bin new file mode 100644 index 0000000..e69de29 diff --git a/gost/test/tokens/IErc2612.sol b/gost/test/tokens/IErc2612.sol new file mode 100644 index 0000000..685d994 --- /dev/null +++ b/gost/test/tokens/IErc2612.sol @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// Code adapted from OpenZeppelin IERCPermit +pragma solidity 0.8.4; + +/** + * @dev Interface of the ERC2612 standard as defined in the EIP. + * + * Adds the {permit} method, which can be used to change one's + * {IERC20-allowance} without having to send a transaction, by signing a + * message. This allows users to spend tokens without having to hold Ether. + * + * See https://eips.ethereum.org/EIPS/eip-2612. + */ +interface IErc2612 { + /** + * @dev Sets `amount` as the allowance of `spender` over `owner`'s tokens, + * given `owner`'s signed approval. + * @param o The owner + * @param spender The spender + * @param a The amount + * @param d The deadline + * @param v v portion of the ECDSA + * @param r r portion of the ECDSA + * @param s s portion of the ECDSA + * + * IMPORTANT: The same issues {IERC20-approve} has related to transaction + * ordering also apply here. + * + * Emits an {Approval} event. + * + * Requirements: + * + * - `owner` cannot be the zero address. + * - `spender` cannot be the zero address. + * - `deadline` must be a timestamp in the future. + * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` + * over the EIP712-formatted function arguments. + * - the signature must use ``owner``'s current nonce (see {nonces}). + * + * For more information on the signature format, see the + * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP + * section]. + */ + function permit(address o, address spender, uint256 a, uint256 d, uint8 v, bytes32 r, bytes32 s) external; + + /** + * @dev Returns the current ERC2612 nonce for `owner`. This value must be + * @param o The owner + * + * included whenever a signature is generated for {permit}. + * + * Every successful call to {permit} increases ``owner``'s nonce by one. This + * prevents a signature from being used multiple times. + */ + function nonces(address o) external view returns (uint256); +} diff --git a/gost/test/tokens/IPErc20.abi b/gost/test/tokens/IPErc20.abi new file mode 100644 index 0000000..459a18e --- /dev/null +++ b/gost/test/tokens/IPErc20.abi @@ -0,0 +1 @@ +[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"address","name":"o","type":"address"},{"internalType":"address","name":"s","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"s","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"a","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"r","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"s","type":"address"},{"internalType":"address","name":"r","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file diff --git a/gost/test/tokens/IPErc20.bin b/gost/test/tokens/IPErc20.bin new file mode 100644 index 0000000..e69de29 diff --git a/gost/test/tokens/IPErc20.sol b/gost/test/tokens/IPErc20.sol new file mode 100644 index 0000000..8affd0c --- /dev/null +++ b/gost/test/tokens/IPErc20.sol @@ -0,0 +1,80 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.8.4; + +/** + * @dev Interface of the ERC20 standard as defined in the EIP. + */ +interface IPErc20 { + /** + * @dev Returns the amount of tokens owned by `account`. + * @param a Adress to fetch balance of + */ + function balanceOf(address a) external view returns (uint256); + + /** + * @dev Moves `amount` tokens from the caller's account to `recipient`. + * @param r The recipient + * @param a The amount transferred + * + * Emits a {Transfer} event. + */ + function transfer(address r, uint256 a) external returns (bool); + + /** + * @dev Returns the remaining number of tokens that `spender` will be + * allowed to spend on behalf of `owner` through {transferFrom}. This is + * zero by default. + * @param o The owner + * @param s The spender + * + * This value changes when {approve} or {transferFrom} are called. + */ + function allowance(address o, address s) external view returns (uint256); + + /** + * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * IMPORTANT: Beware that changing an allowance with this method brings the risk + * that someone may use both the old and the new allowance by unfortunate + * transaction ordering. One possible solution to mitigate this race + * condition is to first reduce the spender's allowance to 0 and set the + * desired value afterwards: + * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 + * @param s The spender + * @param a The amount to approve + * + * Emits an {Approval} event. + */ + function approve(address s, uint256 a) external returns (bool); + + /** + * @dev Moves `amount` tokens from `sender` to `recipient` using the + * allowance mechanism. `amount` is then deducted from the caller's + * allowance. + * @param s The sender + * @param r The recipient + * @param a The amount to transfer + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transferFrom(address s, address r, uint256 a) external returns (bool); + + /** + * @dev Emitted when `value` tokens are moved from one account (`from`) to + * another (`to`). + * + * Note that `value` may be zero. + */ + event Transfer(address indexed from, address indexed to, uint256 value); + + /** + * @dev Emitted when the allowance of a `spender` for an `owner` is set by + * a call to {approve}. `value` is the new allowance. + */ + event Approval(address indexed owner, address indexed spender, uint256 value); +} diff --git a/gost/test/tokens/IZcToken.abi b/gost/test/tokens/IZcToken.abi new file mode 100644 index 0000000..b2326d1 --- /dev/null +++ b/gost/test/tokens/IZcToken.abi @@ -0,0 +1 @@ +[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"address","name":"o","type":"address"},{"internalType":"address","name":"s","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"s","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"a","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"burn","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"mint","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"r","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"s","type":"address"},{"internalType":"address","name":"r","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file diff --git a/gost/test/tokens/IZcToken.bin b/gost/test/tokens/IZcToken.bin new file mode 100644 index 0000000..e69de29 diff --git a/gost/test/tokens/IZcToken.sol b/gost/test/tokens/IZcToken.sol new file mode 100644 index 0000000..8efbda8 --- /dev/null +++ b/gost/test/tokens/IZcToken.sol @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.8.4; + +import "./IPErc20.sol"; + +/** + * @dev Mint and burn interface for the ZCToken + * + */ +interface IZcToken is IPErc20 { + /** + * @dev Mints... + */ + function mint(address, uint256) external returns(bool); + + /** + * @dev Burns... + */ + function burn(address, uint256) external returns(bool); +} diff --git a/gost/test/tokens/PErc20.abi b/gost/test/tokens/PErc20.abi new file mode 100644 index 0000000..c8ceec3 --- /dev/null +++ b/gost/test/tokens/PErc20.abi @@ -0,0 +1 @@ +[{"inputs":[{"internalType":"string","name":"n","type":"string"},{"internalType":"string","name":"s","type":"string"},{"internalType":"uint8","name":"d","type":"uint8"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"address","name":"o","type":"address"},{"internalType":"address","name":"s","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"s","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"a","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"s","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"s","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"r","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"s","type":"address"},{"internalType":"address","name":"r","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file diff --git a/gost/test/tokens/PErc20.bin b/gost/test/tokens/PErc20.bin new file mode 100644 index 0000000..0934a9b --- /dev/null +++ b/gost/test/tokens/PErc20.bin @@ -0,0 +1 @@ +60806040523480156200001157600080fd5b5060405162001777380380620017778339818101604052810190620000379190620001c6565b82600490805190602001906200004f9291906200008d565b508160059080519060200190620000689291906200008d565b5080600260006101000a81548160ff021916908360ff160217905550505050620003e5565b8280546200009b90620002f0565b90600052602060002090601f016020900481019282620000bf57600085556200010b565b82601f10620000da57805160ff19168380011785556200010b565b828001600101855582156200010b579182015b828111156200010a578251825591602001919060010190620000ed565b5b5090506200011a91906200011e565b5090565b5b80821115620001395760008160009055506001016200011f565b5090565b6000620001546200014e8462000277565b6200024e565b9050828152602081018484840111156200016d57600080fd5b6200017a848285620002ba565b509392505050565b600082601f8301126200019457600080fd5b8151620001a68482602086016200013d565b91505092915050565b600081519050620001c081620003cb565b92915050565b600080600060608486031215620001dc57600080fd5b600084015167ffffffffffffffff811115620001f757600080fd5b620002058682870162000182565b935050602084015167ffffffffffffffff8111156200022357600080fd5b620002318682870162000182565b92505060406200024486828701620001af565b9150509250925092565b60006200025a6200026d565b905062000268828262000326565b919050565b6000604051905090565b600067ffffffffffffffff8211156200029557620002946200038b565b5b620002a082620003ba565b9050602081019050919050565b600060ff82169050919050565b60005b83811015620002da578082015181840152602081019050620002bd565b83811115620002ea576000848401525b50505050565b600060028204905060018216806200030957607f821691505b6020821081141562000320576200031f6200035c565b5b50919050565b6200033182620003ba565b810181811067ffffffffffffffff821117156200035357620003526200038b565b5b80604052505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000601f19601f8301169050919050565b620003d681620002ad565b8114620003e257600080fd5b50565b61138280620003f56000396000f3fe608060405234801561001057600080fd5b50600436106100a95760003560e01c80633950935111610071578063395093511461016857806370a082311461019857806395d89b41146101c8578063a457c2d7146101e6578063a9059cbb14610216578063dd62ed3e14610246576100a9565b806306fdde03146100ae578063095ea7b3146100cc57806318160ddd146100fc57806323b872dd1461011a578063313ce5671461014a575b600080fd5b6100b6610276565b6040516100c39190610dee565b60405180910390f35b6100e660048036038101906100e19190610c3c565b610304565b6040516100f39190610dd3565b60405180910390f35b61010461031b565b6040516101119190610ef0565b60405180910390f35b610134600480360381019061012f9190610bed565b610321565b6040516101419190610dd3565b60405180910390f35b610152610414565b60405161015f9190610f0b565b60405180910390f35b610182600480360381019061017d9190610c3c565b610427565b60405161018f9190610dd3565b60405180910390f35b6101b260048036038101906101ad9190610b88565b6104c5565b6040516101bf9190610ef0565b60405180910390f35b6101d061050d565b6040516101dd9190610dee565b60405180910390f35b61020060048036038101906101fb9190610c3c565b61059b565b60405161020d9190610dd3565b60405180910390f35b610230600480360381019061022b9190610c3c565b610681565b60405161023d9190610dd3565b60405180910390f35b610260600480360381019061025b9190610bb1565b610698565b60405161026d9190610ef0565b60405180910390f35b6004805461028390611054565b80601f01602080910402602001604051908101604052809291908181526020018280546102af90611054565b80156102fc5780601f106102d1576101008083540402835291602001916102fc565b820191906000526020600020905b8154815290600101906020018083116102df57829003601f168201915b505050505081565b600061031133848461071f565b6001905092915050565b60035481565b600061032e8484846108ea565b6000600160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050828110156103f2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016103e990610e90565b60405180910390fd5b610408853385846104039190610f98565b61071f565b60019150509392505050565b600260009054906101000a900460ff1681565b60006104bb338484600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546104b69190610f42565b61071f565b6001905092915050565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b6005805461051a90611054565b80601f016020809104026020016040519081016040528092919081815260200182805461054690611054565b80156105935780601f1061056857610100808354040283529160200191610593565b820191906000526020600020905b81548152906001019060200180831161057657829003601f168201915b505050505081565b600080600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905082811015610660576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161065790610ed0565b60405180910390fd5b610676338585846106719190610f98565b61071f565b600191505092915050565b600061068e3384846108ea565b6001905092915050565b6000600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905092915050565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16141561078f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161078690610eb0565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614156107ff576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107f690610e30565b60405180910390fd5b80600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925836040516108dd9190610ef0565b60405180910390a3505050565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16141561095a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161095190610e50565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614156109ca576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109c190610e10565b60405180910390fd5b60008060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905081811015610a50576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a4790610e70565b60405180910390fd5b8181610a5c9190610f98565b6000808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254610aec9190610f42565b925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84604051610b509190610ef0565b60405180910390a350505050565b600081359050610b6d8161131e565b92915050565b600081359050610b8281611335565b92915050565b600060208284031215610b9a57600080fd5b6000610ba884828501610b5e565b91505092915050565b60008060408385031215610bc457600080fd5b6000610bd285828601610b5e565b9250506020610be385828601610b5e565b9150509250929050565b600080600060608486031215610c0257600080fd5b6000610c1086828701610b5e565b9350506020610c2186828701610b5e565b9250506040610c3286828701610b73565b9150509250925092565b60008060408385031215610c4f57600080fd5b6000610c5d85828601610b5e565b9250506020610c6e85828601610b73565b9150509250929050565b610c8181610fde565b82525050565b6000610c9282610f26565b610c9c8185610f31565b9350610cac818560208601611021565b610cb5816110e4565b840191505092915050565b6000610ccd602283610f31565b9150610cd8826110f5565b604082019050919050565b6000610cf0602183610f31565b9150610cfb82611144565b604082019050919050565b6000610d13602483610f31565b9150610d1e82611193565b604082019050919050565b6000610d36602583610f31565b9150610d41826111e2565b604082019050919050565b6000610d59602783610f31565b9150610d6482611231565b604082019050919050565b6000610d7c602383610f31565b9150610d8782611280565b604082019050919050565b6000610d9f602483610f31565b9150610daa826112cf565b604082019050919050565b610dbe8161100a565b82525050565b610dcd81611014565b82525050565b6000602082019050610de86000830184610c78565b92915050565b60006020820190508181036000830152610e088184610c87565b905092915050565b60006020820190508181036000830152610e2981610cc0565b9050919050565b60006020820190508181036000830152610e4981610ce3565b9050919050565b60006020820190508181036000830152610e6981610d06565b9050919050565b60006020820190508181036000830152610e8981610d29565b9050919050565b60006020820190508181036000830152610ea981610d4c565b9050919050565b60006020820190508181036000830152610ec981610d6f565b9050919050565b60006020820190508181036000830152610ee981610d92565b9050919050565b6000602082019050610f056000830184610db5565b92915050565b6000602082019050610f206000830184610dc4565b92915050565b600081519050919050565b600082825260208201905092915050565b6000610f4d8261100a565b9150610f588361100a565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff03821115610f8d57610f8c611086565b5b828201905092915050565b6000610fa38261100a565b9150610fae8361100a565b925082821015610fc157610fc0611086565b5b828203905092915050565b6000610fd782610fea565b9050919050565b60008115159050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b600060ff82169050919050565b60005b8381101561103f578082015181840152602081019050611024565b8381111561104e576000848401525b50505050565b6000600282049050600182168061106c57607f821691505b602082108114156110805761107f6110b5565b5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b6000601f19601f8301169050919050565b7f6572633230207472616e7366657220746f20746865207a65726f20616464726560008201527f7373000000000000000000000000000000000000000000000000000000000000602082015250565b7f657263323020617070726f766520746f20746865207a65726f2061646472657360008201527f7300000000000000000000000000000000000000000000000000000000000000602082015250565b7f6572633230207472616e736665722066726f6d20746865207a65726f2061646460008201527f7265737300000000000000000000000000000000000000000000000000000000602082015250565b7f6572633230207472616e7366657220616d6f756e74206578636565647320626160008201527f6c616e6365000000000000000000000000000000000000000000000000000000602082015250565b7f6572633230207472616e7366657220616d6f756e74206578636565647320616c60008201527f6c6f77616e636500000000000000000000000000000000000000000000000000602082015250565b7f657263323020617070726f76652066726f6d20746865207a65726f206164647260008201527f6573730000000000000000000000000000000000000000000000000000000000602082015250565b7f65726332302064656372656173656420616c6c6f77616e63652062656c6f772060008201527f7a65726f00000000000000000000000000000000000000000000000000000000602082015250565b61132781610fcc565b811461133257600080fd5b50565b61133e8161100a565b811461134957600080fd5b5056fea26469706673582212202336f5cbb91f6e251ccaec67567fc63a1abc650a986d625bf958baa5c6954a7064736f6c63430008040033 \ No newline at end of file diff --git a/gost/test/tokens/PErc20.sol b/gost/test/tokens/PErc20.sol new file mode 100644 index 0000000..b129724 --- /dev/null +++ b/gost/test/tokens/PErc20.sol @@ -0,0 +1,278 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.8.4; + +import "./IPErc20.sol"; + +/** + * @dev Implementation of the {IERC20} interface. + * + * NOTES: This is an adaptation of the Open Zeppelin ERC20, with changes made per audit + * requests, and to fit overall Swivel Style. We use it specifically as the base for + * the Erc2612 hence the `Perc` (Permissioned erc20) naming. + * + * Dangling underscores are generally not allowed within swivel style but the + * internal, abstracted implementation methods inherted from the O.Z contract are maintained here. + * Hence, when you see a dangling underscore prefix, you know it is *only* allowed for + * one of these method calls. It is not allowed for any other purpose. These are: + _approve + _transfer + _mint + _burn + * + * This implementation is agnostic to the way tokens are created. This means + * that a supply mechanism has to be added in a derived contract using {_mint}. + * For a generic mechanism see {ERC20PresetMinterPauser}. + * + * TIP: For a detailed writeup see our guide + * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How + * to implement supply mechanisms]. + * + * We have followed general OpenZeppelin guidelines: functions revert instead + * of returning `false` on failure. This behavior is nonetheless conventional + * and does not conflict with the expectations of ERC20 applications. + * + * Additionally, an {Approval} event is emitted on calls to {transferFrom}. + * This allows applications to reconstruct the allowance for all accounts just + * by listening to said events. Other implementations of the EIP may not emit + * these events, as it isn't required by the specification. + * + * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} + * functions have been added to mitigate the well-known issues around setting + * allowances. See {IERC20-approve}. + + + */ +contract PErc20 is IPErc20 { + mapping (address => uint256) private balances; + mapping (address => mapping (address => uint256)) private allowances; + + uint8 public decimals; + uint256 public totalSupply; + string public name; // NOTE: cannot make strings immutable + string public symbol; // NOTE: see above + + /** + * @dev Sets the values for {name} and {symbol}. + * @param n Name of the token + * @param s Symbol of the token + * @param d Decimals of the token + */ + constructor (string memory n, string memory s, uint8 d) { + name = n; + symbol = s; + decimals = d; + } + + /** + * @dev See {IERC20-balanceOf}. + * @param a Adress to fetch balance of + */ + function balanceOf(address a) public view virtual override returns (uint256) { + return balances[a]; + } + + /** + * @dev See {IERC20-transfer}. + * @param r The recipient + * @param a The amount transferred + * + * Requirements: + * + * - `recipient` cannot be the zero address. + * - the caller must have a balance of at least `amount`. + */ + function transfer(address r, uint256 a) public virtual override returns (bool) { + _transfer(msg.sender, r, a); + return true; + } + + /** + * @dev See {IERC20-allowance}. + * @param o The owner + * @param s The spender + */ + function allowance(address o, address s) public view virtual override returns (uint256) { + return allowances[o][s]; + } + + /** + * @dev See {IERC20-approve}. + * @param s The spender + * @param a The amount to approve + * + * Requirements: + * + * - `spender` cannot be the zero address. + */ + function approve(address s, uint256 a) public virtual override returns (bool) { + _approve(msg.sender, s, a); + return true; + } + + /** + * @dev See {IERC20-transferFrom}. + * + * @param s The sender + * @param r The recipient + * @param a The amount to transfer + * + * Emits an {Approval} event indicating the updated allowance. This is not + * required by the EIP. See the note at the beginning of {ERC20}. + * + * Requirements: + * + * - `sender` and `recipient` cannot be the zero address. + * - `sender` must have a balance of at least `amount`. + * - the caller must have allowance for ``sender``'s tokens of at least + * `amount`. + */ + function transferFrom(address s, address r, uint256 a) public virtual override returns (bool) { + _transfer(s, r, a); + + uint256 currentAllowance = allowances[s][msg.sender]; + require(currentAllowance >= a, "erc20 transfer amount exceeds allowance"); + _approve(s, msg.sender, currentAllowance - a); + + return true; + } + + /** + * @dev Atomically increases the allowance granted to `spender` by the caller. + * @param s The spender + * @param a The amount increased + * + * This is an alternative to {approve} that can be used as a mitigation for + * problems described in {IERC20-approve}. + * + * Emits an {Approval} event indicating the updated allowance. + * + * Requirements: + * + * - `spender` cannot be the zero address. + */ + function increaseAllowance(address s, uint256 a) public virtual returns (bool) { + _approve(msg.sender, s, allowances[msg.sender][s] + a); + return true; + } + + /** + * @dev Atomically decreases the allowance granted to `spender` by the caller. + * @param s The spender + * @param a The amount subtracted + * + * This is an alternative to {approve} that can be used as a mitigation for + * problems described in {IERC20-approve}. + * + * Emits an {Approval} event indicating the updated allowance. + * + * Requirements: + * + * - `spender` cannot be the zero address. + * - `spender` must have allowance for the caller of at least + * `subtractedValue`. + */ + function decreaseAllowance(address s, uint256 a) public virtual returns (bool) { + uint256 currentAllowance = allowances[msg.sender][s]; + require(currentAllowance >= a, "erc20 decreased allowance below zero"); + _approve(msg.sender, s, currentAllowance - a); + + return true; + } + + /** + * @dev Moves tokens `amount` from `sender` to `recipient`. + * @param s The sender + * @param r The recipient + * @param a The amount to transfer + * + * This is internal function is equivalent to {transfer}, and can be used to + * e.g. implement automatic token fees, slashing mechanisms, etc. + * + * Emits a {Transfer} event. + * + * Requirements: + * + * - `sender` cannot be the zero address. + * - `recipient` cannot be the zero address. + * - `sender` must have a balance of at least `amount`. + */ + function _transfer(address s, address r, uint256 a) internal virtual { + require(s != address(0), "erc20 transfer from the zero address"); + require(r != address(0), "erc20 transfer to the zero address"); + + uint256 senderBalance = balances[s]; + require(senderBalance >= a, "erc20 transfer amount exceeds balance"); + balances[s] = senderBalance - a; + balances[r] += a; + + emit Transfer(s, r, a); + } + + /** @dev Creates `amount` tokens and assigns them to `account`, increasing + * the total supply. + * @param r The recipient + * @param a The amount to mint + * + * Emits a {Transfer} event with `from` set to the zero address. + * + * Requirements: + * + * - `recipient` cannot be the zero address. + */ + function _mint(address r, uint256 a) internal virtual { + require(r != address(0), "erc20 mint to the zero address"); + + totalSupply += a; + balances[r] += a; + emit Transfer(address(0), r, a); + } + + /** + * @dev Destroys `amount` tokens from `owner`, reducing the + * total supply. + * @param o The owner of the amount being burned + * @param a The amount to burn + * + * Emits a {Transfer} event with `to` set to the zero address. + * + * Requirements: + * + * - `owner` cannot be the zero address. + * - `owner` must have at least `amount` tokens. + */ + function _burn(address o, uint256 a) internal virtual { + require(o != address(0), "erc20 burn from the zero address"); + + uint256 accountBalance = balances[o]; + require(accountBalance >= a, "erc20 burn amount exceeds balance"); + balances[o] = accountBalance - a; + totalSupply -= a; + + emit Transfer(o, address(0), a); + } + + /** + * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens. + * @param o The owner + * @param s The spender + * @param a The amount + * + * This internal function is equivalent to `approve`, and can be used to + * e.g. set automatic allowances for certain subsystems, etc. + * + * Emits an {Approval} event. + * + * Requirements: + * + * - `owner` cannot be the zero address. + * - `spender` cannot be the zero address. + */ + function _approve(address o, address s, uint256 a) internal virtual { + require(o != address(0), "erc20 approve from the zero address"); + require(s != address(0), "erc20 approve to the zero address"); + + allowances[o][s] = a; + emit Approval(o, s, a); + } +} diff --git a/gost/test/tokens/Underlying.abi b/gost/test/tokens/Underlying.abi new file mode 100644 index 0000000..30adc1d --- /dev/null +++ b/gost/test/tokens/Underlying.abi @@ -0,0 +1 @@ +[{"inputs":[{"internalType":"address","name":"o","type":"address"},{"internalType":"address","name":"s","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"allowances","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"o","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balances","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}] \ No newline at end of file diff --git a/gost/test/tokens/Underlying.bin b/gost/test/tokens/Underlying.bin new file mode 100644 index 0000000..9dae3be --- /dev/null +++ b/gost/test/tokens/Underlying.bin @@ -0,0 +1 @@ +608060405234801561001057600080fd5b5061034a806100206000396000f3fe608060405234801561001057600080fd5b506004361061004c5760003560e01c806327e235e31461005157806355b6ed5c1461008157806370a08231146100b1578063dd62ed3e146100e1575b600080fd5b61006b60048036038101906100669190610232565b610111565b60405161007891906102a6565b60405180910390f35b61009b6004803603810190610096919061025b565b610129565b6040516100a891906102a6565b60405180910390f35b6100cb60048036038101906100c69190610232565b61014e565b6040516100d891906102a6565b60405180910390f35b6100fb60048036038101906100f6919061025b565b610196565b60405161010891906102a6565b60405180910390f35b60006020528060005260406000206000915090505481565b6001602052816000526040600020602052806000526040600020600091509150505481565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b6000600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905092915050565b60008135905061022c816102fd565b92915050565b60006020828403121561024457600080fd5b60006102528482850161021d565b91505092915050565b6000806040838503121561026e57600080fd5b600061027c8582860161021d565b925050602061028d8582860161021d565b9150509250929050565b6102a0816102f3565b82525050565b60006020820190506102bb6000830184610297565b92915050565b60006102cc826102d3565b9050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b610306816102c1565b811461031157600080fd5b5056fea264697066735822122013bedab1aeabfd659c4f1c7247eb6c02865d69420a68a6241a39c63e09a9829964736f6c63430008040033 \ No newline at end of file diff --git a/gost/test/tokens/Underlying.sol b/gost/test/tokens/Underlying.sol new file mode 100644 index 0000000..07928e6 --- /dev/null +++ b/gost/test/tokens/Underlying.sol @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: UNLICENSED + +/** + Underlying is a (for now) ERC20 compatible token interface +*/ + +pragma solidity 0.8.4; + +// For v2 we only need to read the balance and allowance of underlying +contract Underlying { + mapping (address => uint256) public balances; + + mapping (address => mapping (address => uint256)) public allowances; + + function balanceOf(address o) public view returns (uint256) { + return balances[o]; // this should not matter to the abi. i think... + } + + function allowance(address o, address s) public view returns (uint256) { + return allowances[o][s]; + } +} diff --git a/gost/test/tokens/ZcToken.abi b/gost/test/tokens/ZcToken.abi new file mode 100644 index 0000000..84cb9cb --- /dev/null +++ b/gost/test/tokens/ZcToken.abi @@ -0,0 +1 @@ +[{"inputs":[{"internalType":"address","name":"u","type":"address"},{"internalType":"uint256","name":"m","type":"uint256"},{"internalType":"string","name":"n","type":"string"},{"internalType":"string","name":"s","type":"string"},{"internalType":"uint8","name":"d","type":"uint8"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"admin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"o","type":"address"},{"internalType":"address","name":"s","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"s","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"a","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"f","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"burn","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"s","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"domain","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"s","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"maturity","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"t","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"mint","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"o","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"},{"internalType":"uint256","name":"d","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"r","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"s","type":"address"},{"internalType":"address","name":"r","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"underlying","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}] \ No newline at end of file diff --git a/gost/test/tokens/ZcToken.bin b/gost/test/tokens/ZcToken.bin new file mode 100644 index 0000000..c0f36b1 --- /dev/null +++ b/gost/test/tokens/ZcToken.bin @@ -0,0 +1 @@ +6101006040523480156200001257600080fd5b506040516200284838038062002848833981810160405281019062000038919062000332565b828282828282826004908051906020019062000056929190620001cb565b5081600590805190602001906200006f929190620001cb565b5080600260006101000a81548160ff021916908360ff160217905550505050620000dc836040518060400160405280600181526020017f310000000000000000000000000000000000000000000000000000000000000081525046306200016760201b62000c951760201c565b608081815250505050503373ffffffffffffffffffffffffffffffffffffffff1660a08173ffffffffffffffffffffffffffffffffffffffff1660601b815250508473ffffffffffffffffffffffffffffffffffffffff1660c08173ffffffffffffffffffffffffffffffffffffffff1660601b815250508360e081815250505050505050620005ef565b60008085516020870120855160208701206040517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f815282602082015281604082015286606082015285608082015260a08120935050505080915050949350505050565b828054620001d990620004c6565b90600052602060002090601f016020900481019282620001fd576000855562000249565b82601f106200021857805160ff191683800117855562000249565b8280016001018555821562000249579182015b82811115620002485782518255916020019190600101906200022b565b5b5090506200025891906200025c565b5090565b5b80821115620002775760008160009055506001016200025d565b5090565b6000620002926200028c846200040f565b620003e6565b905082815260208101848484011115620002ab57600080fd5b620002b884828562000490565b509392505050565b600081519050620002d181620005a1565b92915050565b600082601f830112620002e957600080fd5b8151620002fb8482602086016200027b565b91505092915050565b6000815190506200031581620005bb565b92915050565b6000815190506200032c81620005d5565b92915050565b600080600080600060a086880312156200034b57600080fd5b60006200035b88828901620002c0565b95505060206200036e8882890162000304565b945050604086015167ffffffffffffffff8111156200038c57600080fd5b6200039a88828901620002d7565b935050606086015167ffffffffffffffff811115620003b857600080fd5b620003c688828901620002d7565b9250506080620003d9888289016200031b565b9150509295509295909350565b6000620003f262000405565b9050620004008282620004fc565b919050565b6000604051905090565b600067ffffffffffffffff8211156200042d576200042c62000561565b5b620004388262000590565b9050602081019050919050565b6000620004528262000459565b9050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b600060ff82169050919050565b60005b83811015620004b057808201518184015260208101905062000493565b83811115620004c0576000848401525b50505050565b60006002820490506001821680620004df57607f821691505b60208210811415620004f657620004f562000532565b5b50919050565b620005078262000590565b810181811067ffffffffffffffff8211171562000529576200052862000561565b5b80604052505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000601f19601f8301169050919050565b620005ac8162000445565b8114620005b857600080fd5b50565b620005c68162000479565b8114620005d257600080fd5b50565b620005e08162000483565b8114620005ec57600080fd5b50565b60805160a05160601c60c05160601c60e0516122046200064460003960006104bf0152600061072d015260008181610689015281816108410152610c730152600081816109e20152610ab201526122046000f3fe608060405234801561001057600080fd5b50600436106101215760003560e01c806370a08231116100ad578063a9059cbb11610071578063a9059cbb1461035a578063c2fb26a61461038a578063d505accf146103a8578063dd62ed3e146103c4578063f851a440146103f457610121565b806370a082311461027c5780637ecebe00146102ac57806395d89b41146102dc5780639dc29fac146102fa578063a457c2d71461032a57610121565b806323b872dd116100f457806323b872dd146101b0578063313ce567146101e057806339509351146101fe57806340c10f191461022e5780636f307dc31461025e57610121565b806306fdde0314610126578063095ea7b31461014457806318160ddd14610174578063204f83f914610192575b600080fd5b61012e610412565b60405161013b9190611a13565b60405180910390f35b61015e60048036038101906101599190611695565b6104a0565b60405161016b9190611937565b60405180910390f35b61017c6104b7565b6040516101899190611bd5565b60405180910390f35b61019a6104bd565b6040516101a79190611bd5565b60405180910390f35b6101ca60048036038101906101c591906115a8565b6104e1565b6040516101d79190611937565b60405180910390f35b6101e86105d4565b6040516101f59190611bf0565b60405180910390f35b61021860048036038101906102139190611695565b6105e7565b6040516102259190611937565b60405180910390f35b61024860048036038101906102439190611695565b610685565b6040516102559190611937565b60405180910390f35b61026661072b565b604051610273919061191c565b60405180910390f35b61029660048036038101906102919190611543565b61074f565b6040516102a39190611bd5565b60405180910390f35b6102c660048036038101906102c19190611543565b610797565b6040516102d39190611bd5565b60405180910390f35b6102e46107af565b6040516102f19190611a13565b60405180910390f35b610314600480360381019061030f9190611695565b61083d565b6040516103219190611937565b60405180910390f35b610344600480360381019061033f9190611695565b6108e3565b6040516103519190611937565b60405180910390f35b610374600480360381019061036f9190611695565b6109c9565b6040516103819190611937565b60405180910390f35b6103926109e0565b60405161039f9190611952565b60405180910390f35b6103c260048036038101906103bd91906115f7565b610a04565b005b6103de60048036038101906103d9919061156c565b610bea565b6040516103eb9190611bd5565b60405180910390f35b6103fc610c71565b604051610409919061191c565b60405180910390f35b6004805461041f90611d43565b80601f016020809104026020016040519081016040528092919081815260200182805461044b90611d43565b80156104985780601f1061046d57610100808354040283529160200191610498565b820191906000526020600020905b81548152906001019060200180831161047b57829003601f168201915b505050505081565b60006104ad338484610cf9565b6001905092915050565b60035481565b7f000000000000000000000000000000000000000000000000000000000000000081565b60006104ee848484610ec4565b6000600160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050828110156105b2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016105a990611b75565b60405180910390fd5b6105c8853385846105c39190611c7d565b610cf9565b60019150509392505050565b600260009054906101000a900460ff1681565b600061067b338484600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546106769190611c27565b610cf9565b6001905092915050565b60007f00000000000000000000000000000000000000000000000000000000000000008073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610716576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161070d90611a35565b60405180910390fd5b6107208484611138565b600191505092915050565b7f000000000000000000000000000000000000000000000000000000000000000081565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b60066020528060005260406000206000915090505481565b600580546107bc90611d43565b80601f01602080910402602001604051908101604052809291908181526020018280546107e890611d43565b80156108355780601f1061080a57610100808354040283529160200191610835565b820191906000526020600020905b81548152906001019060200180831161081857829003601f168201915b505050505081565b60007f00000000000000000000000000000000000000000000000000000000000000008073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146108ce576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108c590611a35565b60405180910390fd5b6108d88484611280565b600191505092915050565b600080600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050828110156109a8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161099f90611bb5565b60405180910390fd5b6109be338585846109b99190611c7d565b610cf9565b600191505092915050565b60006109d6338484610ec4565b6001905092915050565b7f000000000000000000000000000000000000000000000000000000000000000081565b42841015610a47576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a3e90611b15565b60405180910390fd5b6000610aa9888888600660008d73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000815480929190610a9f90611d75565b9190505589611448565b90506000610ad77f0000000000000000000000000000000000000000000000000000000000000000836114a9565b9050600060018287878760405160008152602001604052604051610afe94939291906119ce565b6020604051602081039080840390855afa158015610b20573d6000803e3d6000fd5b505050602060405103519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614158015610b9457508973ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16145b610bd3576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bca90611b35565b60405180910390fd5b610bde8a8a8a610cf9565b50505050505050505050565b6000600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905092915050565b7f000000000000000000000000000000000000000000000000000000000000000081565b60008085516020870120855160208701206040517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f815282602082015281604082015286606082015285608082015260a08120935050505080915050949350505050565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415610d69576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d6090611b95565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415610dd9576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610dd090611a95565b60405180910390fd5b80600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92583604051610eb79190611bd5565b60405180910390a3505050565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415610f34576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f2b90611ad5565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415610fa4576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f9b90611a55565b60405180910390fd5b60008060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490508181101561102a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161102190611af5565b60405180910390fd5b81816110369190611c7d565b6000808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282546110c69190611c27565b925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8460405161112a9190611bd5565b60405180910390a350505050565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614156111a8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161119f90611ab5565b60405180910390fd5b80600360008282546111ba9190611c27565b92505081905550806000808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825461120f9190611c27565b925050819055508173ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040516112749190611bd5565b60405180910390a35050565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614156112f0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016112e790611b55565b60405180910390fd5b60008060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905081811015611376576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161136d90611a75565b60405180910390fd5b81816113829190611c7d565b6000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555081600360008282546113d69190611c7d565b92505081905550600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8460405161143b9190611bd5565b60405180910390a3505050565b60007f80772249b4aef1688b30651778f4249b05cb73b517d98482439b9d8999b3060260001b86868686866040516020016114889695949392919061196d565b60405160208183030381529060405280519060200120905095945050505050565b6000806040517f19010000000000000000000000000000000000000000000000000000000000008152846002820152836022820152604281209150508091505092915050565b6000813590506114fe81612172565b92915050565b60008135905061151381612189565b92915050565b600081359050611528816121a0565b92915050565b60008135905061153d816121b7565b92915050565b60006020828403121561155557600080fd5b6000611563848285016114ef565b91505092915050565b6000806040838503121561157f57600080fd5b600061158d858286016114ef565b925050602061159e858286016114ef565b9150509250929050565b6000806000606084860312156115bd57600080fd5b60006115cb868287016114ef565b93505060206115dc868287016114ef565b92505060406115ed86828701611519565b9150509250925092565b600080600080600080600060e0888a03121561161257600080fd5b60006116208a828b016114ef565b97505060206116318a828b016114ef565b96505060406116428a828b01611519565b95505060606116538a828b01611519565b94505060806116648a828b0161152e565b93505060a06116758a828b01611504565b92505060c06116868a828b01611504565b91505092959891949750929550565b600080604083850312156116a857600080fd5b60006116b6858286016114ef565b92505060206116c785828601611519565b9150509250929050565b6116da81611cb1565b82525050565b6116e981611cc3565b82525050565b6116f881611ccf565b82525050565b600061170982611c0b565b6117138185611c16565b9350611723818560208601611d10565b61172c81611e1c565b840191505092915050565b6000611744601483611c16565b915061174f82611e2d565b602082019050919050565b6000611767602283611c16565b915061177282611e56565b604082019050919050565b600061178a602183611c16565b915061179582611ea5565b604082019050919050565b60006117ad602183611c16565b91506117b882611ef4565b604082019050919050565b60006117d0601e83611c16565b91506117db82611f43565b602082019050919050565b60006117f3602483611c16565b91506117fe82611f6c565b604082019050919050565b6000611816602583611c16565b915061182182611fbb565b604082019050919050565b6000611839601883611c16565b91506118448261200a565b602082019050919050565b600061185c601983611c16565b915061186782612033565b602082019050919050565b600061187f602083611c16565b915061188a8261205c565b602082019050919050565b60006118a2602783611c16565b91506118ad82612085565b604082019050919050565b60006118c5602383611c16565b91506118d0826120d4565b604082019050919050565b60006118e8602483611c16565b91506118f382612123565b604082019050919050565b61190781611cf9565b82525050565b61191681611d03565b82525050565b600060208201905061193160008301846116d1565b92915050565b600060208201905061194c60008301846116e0565b92915050565b600060208201905061196760008301846116ef565b92915050565b600060c08201905061198260008301896116ef565b61198f60208301886116d1565b61199c60408301876116d1565b6119a960608301866118fe565b6119b660808301856118fe565b6119c360a08301846118fe565b979650505050505050565b60006080820190506119e360008301876116ef565b6119f0602083018661190d565b6119fd60408301856116ef565b611a0a60608301846116ef565b95945050505050565b60006020820190508181036000830152611a2d81846116fe565b905092915050565b60006020820190508181036000830152611a4e81611737565b9050919050565b60006020820190508181036000830152611a6e8161175a565b9050919050565b60006020820190508181036000830152611a8e8161177d565b9050919050565b60006020820190508181036000830152611aae816117a0565b9050919050565b60006020820190508181036000830152611ace816117c3565b9050919050565b60006020820190508181036000830152611aee816117e6565b9050919050565b60006020820190508181036000830152611b0e81611809565b9050919050565b60006020820190508181036000830152611b2e8161182c565b9050919050565b60006020820190508181036000830152611b4e8161184f565b9050919050565b60006020820190508181036000830152611b6e81611872565b9050919050565b60006020820190508181036000830152611b8e81611895565b9050919050565b60006020820190508181036000830152611bae816118b8565b9050919050565b60006020820190508181036000830152611bce816118db565b9050919050565b6000602082019050611bea60008301846118fe565b92915050565b6000602082019050611c05600083018461190d565b92915050565b600081519050919050565b600082825260208201905092915050565b6000611c3282611cf9565b9150611c3d83611cf9565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff03821115611c7257611c71611dbe565b5b828201905092915050565b6000611c8882611cf9565b9150611c9383611cf9565b925082821015611ca657611ca5611dbe565b5b828203905092915050565b6000611cbc82611cd9565b9050919050565b60008115159050919050565b6000819050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b600060ff82169050919050565b60005b83811015611d2e578082015181840152602081019050611d13565b83811115611d3d576000848401525b50505050565b60006002820490506001821680611d5b57607f821691505b60208210811415611d6f57611d6e611ded565b5b50919050565b6000611d8082611cf9565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415611db357611db2611dbe565b5b600182019050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b6000601f19601f8301169050919050565b7f73656e646572206d7573742062652061646d696e000000000000000000000000600082015250565b7f6572633230207472616e7366657220746f20746865207a65726f20616464726560008201527f7373000000000000000000000000000000000000000000000000000000000000602082015250565b7f6572633230206275726e20616d6f756e7420657863656564732062616c616e6360008201527f6500000000000000000000000000000000000000000000000000000000000000602082015250565b7f657263323020617070726f766520746f20746865207a65726f2061646472657360008201527f7300000000000000000000000000000000000000000000000000000000000000602082015250565b7f6572633230206d696e7420746f20746865207a65726f20616464726573730000600082015250565b7f6572633230207472616e736665722066726f6d20746865207a65726f2061646460008201527f7265737300000000000000000000000000000000000000000000000000000000602082015250565b7f6572633230207472616e7366657220616d6f756e74206578636565647320626160008201527f6c616e6365000000000000000000000000000000000000000000000000000000602082015250565b7f65726332363132206578706972656420646561646c696e650000000000000000600082015250565b7f6572633236313220696e76616c6964207369676e617475726500000000000000600082015250565b7f6572633230206275726e2066726f6d20746865207a65726f2061646472657373600082015250565b7f6572633230207472616e7366657220616d6f756e74206578636565647320616c60008201527f6c6f77616e636500000000000000000000000000000000000000000000000000602082015250565b7f657263323020617070726f76652066726f6d20746865207a65726f206164647260008201527f6573730000000000000000000000000000000000000000000000000000000000602082015250565b7f65726332302064656372656173656420616c6c6f77616e63652062656c6f772060008201527f7a65726f00000000000000000000000000000000000000000000000000000000602082015250565b61217b81611cb1565b811461218657600080fd5b50565b61219281611ccf565b811461219d57600080fd5b50565b6121a981611cf9565b81146121b457600080fd5b50565b6121c081611d03565b81146121cb57600080fd5b5056fea26469706673582212207309ffda06d13d45bc97465a1092e5a99cba8ee3bcdf814e503aa1922a4b141d64736f6c63430008040033 \ No newline at end of file diff --git a/gost/test/tokens/ZcToken.sol b/gost/test/tokens/ZcToken.sol new file mode 100644 index 0000000..897c05b --- /dev/null +++ b/gost/test/tokens/ZcToken.sol @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: MIT + +// NOTE: whomever decided methods which are the implementation of a stated interface +// need to be labeled 'override' should to be publicly flogged. + +pragma solidity 0.8.4; + +import './Erc2612.sol'; +import './IZcToken.sol'; + +/// NOTE the OZStlye naming conventions are kept for the internal methods +/// _burn and _mint as dangling underscores are generally not allowed. +contract ZcToken is Erc2612, IZcToken { + address public immutable admin; + address public immutable underlying; + uint256 public immutable maturity; + + /// @param u Underlying + /// @param m Maturity + /// @param n Name + /// @param s Symbol + /// @param d Decimals + constructor(address u, uint256 m, string memory n, string memory s, uint8 d) Erc2612(n, s, d) { + admin = msg.sender; + underlying = u; + maturity = m; + } + + /// @param f Address to burn from + /// @param a Amount to burn + function burn(address f, uint256 a) external onlyAdmin(admin) override returns(bool) { + _burn(f, a); + return true; + } + + /// @param t Address recieving the minted amount + /// @param a The amount to mint + function mint(address t, uint256 a) external onlyAdmin(admin) override returns(bool) { + _mint(t, a); + return true; + } + + /// @param a Admin address + modifier onlyAdmin(address a) { + require(msg.sender == a, 'sender must be admin'); + _; + } +} diff --git a/gost/test/tokens/underlying.go b/gost/test/tokens/underlying.go new file mode 100644 index 0000000..24077d2 --- /dev/null +++ b/gost/test/tokens/underlying.go @@ -0,0 +1,313 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package tokens + +import ( + "math/big" + "strings" + + ethereum "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/event" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription +) + +// UnderlyingABI is the input ABI used to generate the binding from. +const UnderlyingABI = "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"o\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"s\",\"type\":\"address\"}],\"name\":\"allowance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"allowances\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"o\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"balances\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]" + +// UnderlyingBin is the compiled bytecode used for deploying new contracts. +var UnderlyingBin = "0x608060405234801561001057600080fd5b5061034a806100206000396000f3fe608060405234801561001057600080fd5b506004361061004c5760003560e01c806327e235e31461005157806355b6ed5c1461008157806370a08231146100b1578063dd62ed3e146100e1575b600080fd5b61006b60048036038101906100669190610232565b610111565b60405161007891906102a6565b60405180910390f35b61009b6004803603810190610096919061025b565b610129565b6040516100a891906102a6565b60405180910390f35b6100cb60048036038101906100c69190610232565b61014e565b6040516100d891906102a6565b60405180910390f35b6100fb60048036038101906100f6919061025b565b610196565b60405161010891906102a6565b60405180910390f35b60006020528060005260406000206000915090505481565b6001602052816000526040600020602052806000526040600020600091509150505481565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b6000600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905092915050565b60008135905061022c816102fd565b92915050565b60006020828403121561024457600080fd5b60006102528482850161021d565b91505092915050565b6000806040838503121561026e57600080fd5b600061027c8582860161021d565b925050602061028d8582860161021d565b9150509250929050565b6102a0816102f3565b82525050565b60006020820190506102bb6000830184610297565b92915050565b60006102cc826102d3565b9050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b610306816102c1565b811461031157600080fd5b5056fea264697066735822122013bedab1aeabfd659c4f1c7247eb6c02865d69420a68a6241a39c63e09a9829964736f6c63430008040033" + +// DeployUnderlying deploys a new Ethereum contract, binding an instance of Underlying to it. +func DeployUnderlying(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *Underlying, error) { + parsed, err := abi.JSON(strings.NewReader(UnderlyingABI)) + if err != nil { + return common.Address{}, nil, nil, err + } + + address, tx, contract, err := bind.DeployContract(auth, parsed, common.FromHex(UnderlyingBin), backend) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &Underlying{UnderlyingCaller: UnderlyingCaller{contract: contract}, UnderlyingTransactor: UnderlyingTransactor{contract: contract}, UnderlyingFilterer: UnderlyingFilterer{contract: contract}}, nil +} + +// Underlying is an auto generated Go binding around an Ethereum contract. +type Underlying struct { + UnderlyingCaller // Read-only binding to the contract + UnderlyingTransactor // Write-only binding to the contract + UnderlyingFilterer // Log filterer for contract events +} + +// UnderlyingCaller is an auto generated read-only Go binding around an Ethereum contract. +type UnderlyingCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// UnderlyingTransactor is an auto generated write-only Go binding around an Ethereum contract. +type UnderlyingTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// UnderlyingFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type UnderlyingFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// UnderlyingSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type UnderlyingSession struct { + Contract *Underlying // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// UnderlyingCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type UnderlyingCallerSession struct { + Contract *UnderlyingCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// UnderlyingTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type UnderlyingTransactorSession struct { + Contract *UnderlyingTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// UnderlyingRaw is an auto generated low-level Go binding around an Ethereum contract. +type UnderlyingRaw struct { + Contract *Underlying // Generic contract binding to access the raw methods on +} + +// UnderlyingCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type UnderlyingCallerRaw struct { + Contract *UnderlyingCaller // Generic read-only contract binding to access the raw methods on +} + +// UnderlyingTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type UnderlyingTransactorRaw struct { + Contract *UnderlyingTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewUnderlying creates a new instance of Underlying, bound to a specific deployed contract. +func NewUnderlying(address common.Address, backend bind.ContractBackend) (*Underlying, error) { + contract, err := bindUnderlying(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &Underlying{UnderlyingCaller: UnderlyingCaller{contract: contract}, UnderlyingTransactor: UnderlyingTransactor{contract: contract}, UnderlyingFilterer: UnderlyingFilterer{contract: contract}}, nil +} + +// NewUnderlyingCaller creates a new read-only instance of Underlying, bound to a specific deployed contract. +func NewUnderlyingCaller(address common.Address, caller bind.ContractCaller) (*UnderlyingCaller, error) { + contract, err := bindUnderlying(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &UnderlyingCaller{contract: contract}, nil +} + +// NewUnderlyingTransactor creates a new write-only instance of Underlying, bound to a specific deployed contract. +func NewUnderlyingTransactor(address common.Address, transactor bind.ContractTransactor) (*UnderlyingTransactor, error) { + contract, err := bindUnderlying(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &UnderlyingTransactor{contract: contract}, nil +} + +// NewUnderlyingFilterer creates a new log filterer instance of Underlying, bound to a specific deployed contract. +func NewUnderlyingFilterer(address common.Address, filterer bind.ContractFilterer) (*UnderlyingFilterer, error) { + contract, err := bindUnderlying(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &UnderlyingFilterer{contract: contract}, nil +} + +// bindUnderlying binds a generic wrapper to an already deployed contract. +func bindUnderlying(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := abi.JSON(strings.NewReader(UnderlyingABI)) + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_Underlying *UnderlyingRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _Underlying.Contract.UnderlyingCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_Underlying *UnderlyingRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Underlying.Contract.UnderlyingTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_Underlying *UnderlyingRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _Underlying.Contract.UnderlyingTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_Underlying *UnderlyingCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _Underlying.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_Underlying *UnderlyingTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Underlying.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_Underlying *UnderlyingTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _Underlying.Contract.contract.Transact(opts, method, params...) +} + +// Allowance is a free data retrieval call binding the contract method 0xdd62ed3e. +// +// Solidity: function allowance(address o, address s) view returns(uint256) +func (_Underlying *UnderlyingCaller) Allowance(opts *bind.CallOpts, o common.Address, s common.Address) (*big.Int, error) { + var out []interface{} + err := _Underlying.contract.Call(opts, &out, "allowance", o, s) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// Allowance is a free data retrieval call binding the contract method 0xdd62ed3e. +// +// Solidity: function allowance(address o, address s) view returns(uint256) +func (_Underlying *UnderlyingSession) Allowance(o common.Address, s common.Address) (*big.Int, error) { + return _Underlying.Contract.Allowance(&_Underlying.CallOpts, o, s) +} + +// Allowance is a free data retrieval call binding the contract method 0xdd62ed3e. +// +// Solidity: function allowance(address o, address s) view returns(uint256) +func (_Underlying *UnderlyingCallerSession) Allowance(o common.Address, s common.Address) (*big.Int, error) { + return _Underlying.Contract.Allowance(&_Underlying.CallOpts, o, s) +} + +// Allowances is a free data retrieval call binding the contract method 0x55b6ed5c. +// +// Solidity: function allowances(address , address ) view returns(uint256) +func (_Underlying *UnderlyingCaller) Allowances(opts *bind.CallOpts, arg0 common.Address, arg1 common.Address) (*big.Int, error) { + var out []interface{} + err := _Underlying.contract.Call(opts, &out, "allowances", arg0, arg1) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// Allowances is a free data retrieval call binding the contract method 0x55b6ed5c. +// +// Solidity: function allowances(address , address ) view returns(uint256) +func (_Underlying *UnderlyingSession) Allowances(arg0 common.Address, arg1 common.Address) (*big.Int, error) { + return _Underlying.Contract.Allowances(&_Underlying.CallOpts, arg0, arg1) +} + +// Allowances is a free data retrieval call binding the contract method 0x55b6ed5c. +// +// Solidity: function allowances(address , address ) view returns(uint256) +func (_Underlying *UnderlyingCallerSession) Allowances(arg0 common.Address, arg1 common.Address) (*big.Int, error) { + return _Underlying.Contract.Allowances(&_Underlying.CallOpts, arg0, arg1) +} + +// BalanceOf is a free data retrieval call binding the contract method 0x70a08231. +// +// Solidity: function balanceOf(address o) view returns(uint256) +func (_Underlying *UnderlyingCaller) BalanceOf(opts *bind.CallOpts, o common.Address) (*big.Int, error) { + var out []interface{} + err := _Underlying.contract.Call(opts, &out, "balanceOf", o) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// BalanceOf is a free data retrieval call binding the contract method 0x70a08231. +// +// Solidity: function balanceOf(address o) view returns(uint256) +func (_Underlying *UnderlyingSession) BalanceOf(o common.Address) (*big.Int, error) { + return _Underlying.Contract.BalanceOf(&_Underlying.CallOpts, o) +} + +// BalanceOf is a free data retrieval call binding the contract method 0x70a08231. +// +// Solidity: function balanceOf(address o) view returns(uint256) +func (_Underlying *UnderlyingCallerSession) BalanceOf(o common.Address) (*big.Int, error) { + return _Underlying.Contract.BalanceOf(&_Underlying.CallOpts, o) +} + +// Balances is a free data retrieval call binding the contract method 0x27e235e3. +// +// Solidity: function balances(address ) view returns(uint256) +func (_Underlying *UnderlyingCaller) Balances(opts *bind.CallOpts, arg0 common.Address) (*big.Int, error) { + var out []interface{} + err := _Underlying.contract.Call(opts, &out, "balances", arg0) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// Balances is a free data retrieval call binding the contract method 0x27e235e3. +// +// Solidity: function balances(address ) view returns(uint256) +func (_Underlying *UnderlyingSession) Balances(arg0 common.Address) (*big.Int, error) { + return _Underlying.Contract.Balances(&_Underlying.CallOpts, arg0) +} + +// Balances is a free data retrieval call binding the contract method 0x27e235e3. +// +// Solidity: function balances(address ) view returns(uint256) +func (_Underlying *UnderlyingCallerSession) Balances(arg0 common.Address) (*big.Int, error) { + return _Underlying.Contract.Balances(&_Underlying.CallOpts, arg0) +} diff --git a/gost/test/tokens/zctoken.go b/gost/test/tokens/zctoken.go new file mode 100644 index 0000000..8aac633 --- /dev/null +++ b/gost/test/tokens/zctoken.go @@ -0,0 +1,1006 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package tokens + +import ( + "math/big" + "strings" + + ethereum "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/event" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription +) + +// ZcTokenABI is the input ABI used to generate the binding from. +const ZcTokenABI = "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"u\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"m\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"n\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"s\",\"type\":\"string\"},{\"internalType\":\"uint8\",\"name\":\"d\",\"type\":\"uint8\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"admin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"o\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"s\",\"type\":\"address\"}],\"name\":\"allowance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"s\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"a\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"a\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"f\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"a\",\"type\":\"uint256\"}],\"name\":\"burn\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"decimals\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"s\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"a\",\"type\":\"uint256\"}],\"name\":\"decreaseAllowance\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"domain\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"s\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"a\",\"type\":\"uint256\"}],\"name\":\"increaseAllowance\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"maturity\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"t\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"a\",\"type\":\"uint256\"}],\"name\":\"mint\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"nonces\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"o\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"a\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"d\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"r\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"s\",\"type\":\"bytes32\"}],\"name\":\"permit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"symbol\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"r\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"a\",\"type\":\"uint256\"}],\"name\":\"transfer\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"s\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"r\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"a\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"underlying\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]" + +// ZcTokenBin is the compiled bytecode used for deploying new contracts. +var ZcTokenBin = "0x6101006040523480156200001257600080fd5b506040516200284838038062002848833981810160405281019062000038919062000332565b828282828282826004908051906020019062000056929190620001cb565b5081600590805190602001906200006f929190620001cb565b5080600260006101000a81548160ff021916908360ff160217905550505050620000dc836040518060400160405280600181526020017f310000000000000000000000000000000000000000000000000000000000000081525046306200016760201b62000c951760201c565b608081815250505050503373ffffffffffffffffffffffffffffffffffffffff1660a08173ffffffffffffffffffffffffffffffffffffffff1660601b815250508473ffffffffffffffffffffffffffffffffffffffff1660c08173ffffffffffffffffffffffffffffffffffffffff1660601b815250508360e081815250505050505050620005ef565b60008085516020870120855160208701206040517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f815282602082015281604082015286606082015285608082015260a08120935050505080915050949350505050565b828054620001d990620004c6565b90600052602060002090601f016020900481019282620001fd576000855562000249565b82601f106200021857805160ff191683800117855562000249565b8280016001018555821562000249579182015b82811115620002485782518255916020019190600101906200022b565b5b5090506200025891906200025c565b5090565b5b80821115620002775760008160009055506001016200025d565b5090565b6000620002926200028c846200040f565b620003e6565b905082815260208101848484011115620002ab57600080fd5b620002b884828562000490565b509392505050565b600081519050620002d181620005a1565b92915050565b600082601f830112620002e957600080fd5b8151620002fb8482602086016200027b565b91505092915050565b6000815190506200031581620005bb565b92915050565b6000815190506200032c81620005d5565b92915050565b600080600080600060a086880312156200034b57600080fd5b60006200035b88828901620002c0565b95505060206200036e8882890162000304565b945050604086015167ffffffffffffffff8111156200038c57600080fd5b6200039a88828901620002d7565b935050606086015167ffffffffffffffff811115620003b857600080fd5b620003c688828901620002d7565b9250506080620003d9888289016200031b565b9150509295509295909350565b6000620003f262000405565b9050620004008282620004fc565b919050565b6000604051905090565b600067ffffffffffffffff8211156200042d576200042c62000561565b5b620004388262000590565b9050602081019050919050565b6000620004528262000459565b9050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b600060ff82169050919050565b60005b83811015620004b057808201518184015260208101905062000493565b83811115620004c0576000848401525b50505050565b60006002820490506001821680620004df57607f821691505b60208210811415620004f657620004f562000532565b5b50919050565b620005078262000590565b810181811067ffffffffffffffff8211171562000529576200052862000561565b5b80604052505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000601f19601f8301169050919050565b620005ac8162000445565b8114620005b857600080fd5b50565b620005c68162000479565b8114620005d257600080fd5b50565b620005e08162000483565b8114620005ec57600080fd5b50565b60805160a05160601c60c05160601c60e0516122046200064460003960006104bf0152600061072d015260008181610689015281816108410152610c730152600081816109e20152610ab201526122046000f3fe608060405234801561001057600080fd5b50600436106101215760003560e01c806370a08231116100ad578063a9059cbb11610071578063a9059cbb1461035a578063c2fb26a61461038a578063d505accf146103a8578063dd62ed3e146103c4578063f851a440146103f457610121565b806370a082311461027c5780637ecebe00146102ac57806395d89b41146102dc5780639dc29fac146102fa578063a457c2d71461032a57610121565b806323b872dd116100f457806323b872dd146101b0578063313ce567146101e057806339509351146101fe57806340c10f191461022e5780636f307dc31461025e57610121565b806306fdde0314610126578063095ea7b31461014457806318160ddd14610174578063204f83f914610192575b600080fd5b61012e610412565b60405161013b9190611a13565b60405180910390f35b61015e60048036038101906101599190611695565b6104a0565b60405161016b9190611937565b60405180910390f35b61017c6104b7565b6040516101899190611bd5565b60405180910390f35b61019a6104bd565b6040516101a79190611bd5565b60405180910390f35b6101ca60048036038101906101c591906115a8565b6104e1565b6040516101d79190611937565b60405180910390f35b6101e86105d4565b6040516101f59190611bf0565b60405180910390f35b61021860048036038101906102139190611695565b6105e7565b6040516102259190611937565b60405180910390f35b61024860048036038101906102439190611695565b610685565b6040516102559190611937565b60405180910390f35b61026661072b565b604051610273919061191c565b60405180910390f35b61029660048036038101906102919190611543565b61074f565b6040516102a39190611bd5565b60405180910390f35b6102c660048036038101906102c19190611543565b610797565b6040516102d39190611bd5565b60405180910390f35b6102e46107af565b6040516102f19190611a13565b60405180910390f35b610314600480360381019061030f9190611695565b61083d565b6040516103219190611937565b60405180910390f35b610344600480360381019061033f9190611695565b6108e3565b6040516103519190611937565b60405180910390f35b610374600480360381019061036f9190611695565b6109c9565b6040516103819190611937565b60405180910390f35b6103926109e0565b60405161039f9190611952565b60405180910390f35b6103c260048036038101906103bd91906115f7565b610a04565b005b6103de60048036038101906103d9919061156c565b610bea565b6040516103eb9190611bd5565b60405180910390f35b6103fc610c71565b604051610409919061191c565b60405180910390f35b6004805461041f90611d43565b80601f016020809104026020016040519081016040528092919081815260200182805461044b90611d43565b80156104985780601f1061046d57610100808354040283529160200191610498565b820191906000526020600020905b81548152906001019060200180831161047b57829003601f168201915b505050505081565b60006104ad338484610cf9565b6001905092915050565b60035481565b7f000000000000000000000000000000000000000000000000000000000000000081565b60006104ee848484610ec4565b6000600160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050828110156105b2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016105a990611b75565b60405180910390fd5b6105c8853385846105c39190611c7d565b610cf9565b60019150509392505050565b600260009054906101000a900460ff1681565b600061067b338484600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546106769190611c27565b610cf9565b6001905092915050565b60007f00000000000000000000000000000000000000000000000000000000000000008073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610716576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161070d90611a35565b60405180910390fd5b6107208484611138565b600191505092915050565b7f000000000000000000000000000000000000000000000000000000000000000081565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b60066020528060005260406000206000915090505481565b600580546107bc90611d43565b80601f01602080910402602001604051908101604052809291908181526020018280546107e890611d43565b80156108355780601f1061080a57610100808354040283529160200191610835565b820191906000526020600020905b81548152906001019060200180831161081857829003601f168201915b505050505081565b60007f00000000000000000000000000000000000000000000000000000000000000008073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146108ce576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108c590611a35565b60405180910390fd5b6108d88484611280565b600191505092915050565b600080600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050828110156109a8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161099f90611bb5565b60405180910390fd5b6109be338585846109b99190611c7d565b610cf9565b600191505092915050565b60006109d6338484610ec4565b6001905092915050565b7f000000000000000000000000000000000000000000000000000000000000000081565b42841015610a47576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a3e90611b15565b60405180910390fd5b6000610aa9888888600660008d73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000815480929190610a9f90611d75565b9190505589611448565b90506000610ad77f0000000000000000000000000000000000000000000000000000000000000000836114a9565b9050600060018287878760405160008152602001604052604051610afe94939291906119ce565b6020604051602081039080840390855afa158015610b20573d6000803e3d6000fd5b505050602060405103519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614158015610b9457508973ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16145b610bd3576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bca90611b35565b60405180910390fd5b610bde8a8a8a610cf9565b50505050505050505050565b6000600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905092915050565b7f000000000000000000000000000000000000000000000000000000000000000081565b60008085516020870120855160208701206040517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f815282602082015281604082015286606082015285608082015260a08120935050505080915050949350505050565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415610d69576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d6090611b95565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415610dd9576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610dd090611a95565b60405180910390fd5b80600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92583604051610eb79190611bd5565b60405180910390a3505050565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415610f34576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f2b90611ad5565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415610fa4576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f9b90611a55565b60405180910390fd5b60008060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490508181101561102a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161102190611af5565b60405180910390fd5b81816110369190611c7d565b6000808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282546110c69190611c27565b925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8460405161112a9190611bd5565b60405180910390a350505050565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614156111a8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161119f90611ab5565b60405180910390fd5b80600360008282546111ba9190611c27565b92505081905550806000808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825461120f9190611c27565b925050819055508173ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040516112749190611bd5565b60405180910390a35050565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614156112f0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016112e790611b55565b60405180910390fd5b60008060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905081811015611376576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161136d90611a75565b60405180910390fd5b81816113829190611c7d565b6000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555081600360008282546113d69190611c7d565b92505081905550600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8460405161143b9190611bd5565b60405180910390a3505050565b60007f80772249b4aef1688b30651778f4249b05cb73b517d98482439b9d8999b3060260001b86868686866040516020016114889695949392919061196d565b60405160208183030381529060405280519060200120905095945050505050565b6000806040517f19010000000000000000000000000000000000000000000000000000000000008152846002820152836022820152604281209150508091505092915050565b6000813590506114fe81612172565b92915050565b60008135905061151381612189565b92915050565b600081359050611528816121a0565b92915050565b60008135905061153d816121b7565b92915050565b60006020828403121561155557600080fd5b6000611563848285016114ef565b91505092915050565b6000806040838503121561157f57600080fd5b600061158d858286016114ef565b925050602061159e858286016114ef565b9150509250929050565b6000806000606084860312156115bd57600080fd5b60006115cb868287016114ef565b93505060206115dc868287016114ef565b92505060406115ed86828701611519565b9150509250925092565b600080600080600080600060e0888a03121561161257600080fd5b60006116208a828b016114ef565b97505060206116318a828b016114ef565b96505060406116428a828b01611519565b95505060606116538a828b01611519565b94505060806116648a828b0161152e565b93505060a06116758a828b01611504565b92505060c06116868a828b01611504565b91505092959891949750929550565b600080604083850312156116a857600080fd5b60006116b6858286016114ef565b92505060206116c785828601611519565b9150509250929050565b6116da81611cb1565b82525050565b6116e981611cc3565b82525050565b6116f881611ccf565b82525050565b600061170982611c0b565b6117138185611c16565b9350611723818560208601611d10565b61172c81611e1c565b840191505092915050565b6000611744601483611c16565b915061174f82611e2d565b602082019050919050565b6000611767602283611c16565b915061177282611e56565b604082019050919050565b600061178a602183611c16565b915061179582611ea5565b604082019050919050565b60006117ad602183611c16565b91506117b882611ef4565b604082019050919050565b60006117d0601e83611c16565b91506117db82611f43565b602082019050919050565b60006117f3602483611c16565b91506117fe82611f6c565b604082019050919050565b6000611816602583611c16565b915061182182611fbb565b604082019050919050565b6000611839601883611c16565b91506118448261200a565b602082019050919050565b600061185c601983611c16565b915061186782612033565b602082019050919050565b600061187f602083611c16565b915061188a8261205c565b602082019050919050565b60006118a2602783611c16565b91506118ad82612085565b604082019050919050565b60006118c5602383611c16565b91506118d0826120d4565b604082019050919050565b60006118e8602483611c16565b91506118f382612123565b604082019050919050565b61190781611cf9565b82525050565b61191681611d03565b82525050565b600060208201905061193160008301846116d1565b92915050565b600060208201905061194c60008301846116e0565b92915050565b600060208201905061196760008301846116ef565b92915050565b600060c08201905061198260008301896116ef565b61198f60208301886116d1565b61199c60408301876116d1565b6119a960608301866118fe565b6119b660808301856118fe565b6119c360a08301846118fe565b979650505050505050565b60006080820190506119e360008301876116ef565b6119f0602083018661190d565b6119fd60408301856116ef565b611a0a60608301846116ef565b95945050505050565b60006020820190508181036000830152611a2d81846116fe565b905092915050565b60006020820190508181036000830152611a4e81611737565b9050919050565b60006020820190508181036000830152611a6e8161175a565b9050919050565b60006020820190508181036000830152611a8e8161177d565b9050919050565b60006020820190508181036000830152611aae816117a0565b9050919050565b60006020820190508181036000830152611ace816117c3565b9050919050565b60006020820190508181036000830152611aee816117e6565b9050919050565b60006020820190508181036000830152611b0e81611809565b9050919050565b60006020820190508181036000830152611b2e8161182c565b9050919050565b60006020820190508181036000830152611b4e8161184f565b9050919050565b60006020820190508181036000830152611b6e81611872565b9050919050565b60006020820190508181036000830152611b8e81611895565b9050919050565b60006020820190508181036000830152611bae816118b8565b9050919050565b60006020820190508181036000830152611bce816118db565b9050919050565b6000602082019050611bea60008301846118fe565b92915050565b6000602082019050611c05600083018461190d565b92915050565b600081519050919050565b600082825260208201905092915050565b6000611c3282611cf9565b9150611c3d83611cf9565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff03821115611c7257611c71611dbe565b5b828201905092915050565b6000611c8882611cf9565b9150611c9383611cf9565b925082821015611ca657611ca5611dbe565b5b828203905092915050565b6000611cbc82611cd9565b9050919050565b60008115159050919050565b6000819050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b600060ff82169050919050565b60005b83811015611d2e578082015181840152602081019050611d13565b83811115611d3d576000848401525b50505050565b60006002820490506001821680611d5b57607f821691505b60208210811415611d6f57611d6e611ded565b5b50919050565b6000611d8082611cf9565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415611db357611db2611dbe565b5b600182019050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b6000601f19601f8301169050919050565b7f73656e646572206d7573742062652061646d696e000000000000000000000000600082015250565b7f6572633230207472616e7366657220746f20746865207a65726f20616464726560008201527f7373000000000000000000000000000000000000000000000000000000000000602082015250565b7f6572633230206275726e20616d6f756e7420657863656564732062616c616e6360008201527f6500000000000000000000000000000000000000000000000000000000000000602082015250565b7f657263323020617070726f766520746f20746865207a65726f2061646472657360008201527f7300000000000000000000000000000000000000000000000000000000000000602082015250565b7f6572633230206d696e7420746f20746865207a65726f20616464726573730000600082015250565b7f6572633230207472616e736665722066726f6d20746865207a65726f2061646460008201527f7265737300000000000000000000000000000000000000000000000000000000602082015250565b7f6572633230207472616e7366657220616d6f756e74206578636565647320626160008201527f6c616e6365000000000000000000000000000000000000000000000000000000602082015250565b7f65726332363132206578706972656420646561646c696e650000000000000000600082015250565b7f6572633236313220696e76616c6964207369676e617475726500000000000000600082015250565b7f6572633230206275726e2066726f6d20746865207a65726f2061646472657373600082015250565b7f6572633230207472616e7366657220616d6f756e74206578636565647320616c60008201527f6c6f77616e636500000000000000000000000000000000000000000000000000602082015250565b7f657263323020617070726f76652066726f6d20746865207a65726f206164647260008201527f6573730000000000000000000000000000000000000000000000000000000000602082015250565b7f65726332302064656372656173656420616c6c6f77616e63652062656c6f772060008201527f7a65726f00000000000000000000000000000000000000000000000000000000602082015250565b61217b81611cb1565b811461218657600080fd5b50565b61219281611ccf565b811461219d57600080fd5b50565b6121a981611cf9565b81146121b457600080fd5b50565b6121c081611d03565b81146121cb57600080fd5b5056fea26469706673582212207309ffda06d13d45bc97465a1092e5a99cba8ee3bcdf814e503aa1922a4b141d64736f6c63430008040033" + +// DeployZcToken deploys a new Ethereum contract, binding an instance of ZcToken to it. +func DeployZcToken(auth *bind.TransactOpts, backend bind.ContractBackend, u common.Address, m *big.Int, n string, s string, d uint8) (common.Address, *types.Transaction, *ZcToken, error) { + parsed, err := abi.JSON(strings.NewReader(ZcTokenABI)) + if err != nil { + return common.Address{}, nil, nil, err + } + + address, tx, contract, err := bind.DeployContract(auth, parsed, common.FromHex(ZcTokenBin), backend, u, m, n, s, d) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &ZcToken{ZcTokenCaller: ZcTokenCaller{contract: contract}, ZcTokenTransactor: ZcTokenTransactor{contract: contract}, ZcTokenFilterer: ZcTokenFilterer{contract: contract}}, nil +} + +// ZcToken is an auto generated Go binding around an Ethereum contract. +type ZcToken struct { + ZcTokenCaller // Read-only binding to the contract + ZcTokenTransactor // Write-only binding to the contract + ZcTokenFilterer // Log filterer for contract events +} + +// ZcTokenCaller is an auto generated read-only Go binding around an Ethereum contract. +type ZcTokenCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// ZcTokenTransactor is an auto generated write-only Go binding around an Ethereum contract. +type ZcTokenTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// ZcTokenFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type ZcTokenFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// ZcTokenSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type ZcTokenSession struct { + Contract *ZcToken // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// ZcTokenCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type ZcTokenCallerSession struct { + Contract *ZcTokenCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// ZcTokenTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type ZcTokenTransactorSession struct { + Contract *ZcTokenTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// ZcTokenRaw is an auto generated low-level Go binding around an Ethereum contract. +type ZcTokenRaw struct { + Contract *ZcToken // Generic contract binding to access the raw methods on +} + +// ZcTokenCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type ZcTokenCallerRaw struct { + Contract *ZcTokenCaller // Generic read-only contract binding to access the raw methods on +} + +// ZcTokenTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type ZcTokenTransactorRaw struct { + Contract *ZcTokenTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewZcToken creates a new instance of ZcToken, bound to a specific deployed contract. +func NewZcToken(address common.Address, backend bind.ContractBackend) (*ZcToken, error) { + contract, err := bindZcToken(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &ZcToken{ZcTokenCaller: ZcTokenCaller{contract: contract}, ZcTokenTransactor: ZcTokenTransactor{contract: contract}, ZcTokenFilterer: ZcTokenFilterer{contract: contract}}, nil +} + +// NewZcTokenCaller creates a new read-only instance of ZcToken, bound to a specific deployed contract. +func NewZcTokenCaller(address common.Address, caller bind.ContractCaller) (*ZcTokenCaller, error) { + contract, err := bindZcToken(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &ZcTokenCaller{contract: contract}, nil +} + +// NewZcTokenTransactor creates a new write-only instance of ZcToken, bound to a specific deployed contract. +func NewZcTokenTransactor(address common.Address, transactor bind.ContractTransactor) (*ZcTokenTransactor, error) { + contract, err := bindZcToken(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &ZcTokenTransactor{contract: contract}, nil +} + +// NewZcTokenFilterer creates a new log filterer instance of ZcToken, bound to a specific deployed contract. +func NewZcTokenFilterer(address common.Address, filterer bind.ContractFilterer) (*ZcTokenFilterer, error) { + contract, err := bindZcToken(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &ZcTokenFilterer{contract: contract}, nil +} + +// bindZcToken binds a generic wrapper to an already deployed contract. +func bindZcToken(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := abi.JSON(strings.NewReader(ZcTokenABI)) + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_ZcToken *ZcTokenRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _ZcToken.Contract.ZcTokenCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_ZcToken *ZcTokenRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _ZcToken.Contract.ZcTokenTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_ZcToken *ZcTokenRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _ZcToken.Contract.ZcTokenTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_ZcToken *ZcTokenCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _ZcToken.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_ZcToken *ZcTokenTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _ZcToken.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_ZcToken *ZcTokenTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _ZcToken.Contract.contract.Transact(opts, method, params...) +} + +// Admin is a free data retrieval call binding the contract method 0xf851a440. +// +// Solidity: function admin() view returns(address) +func (_ZcToken *ZcTokenCaller) Admin(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _ZcToken.contract.Call(opts, &out, "admin") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// Admin is a free data retrieval call binding the contract method 0xf851a440. +// +// Solidity: function admin() view returns(address) +func (_ZcToken *ZcTokenSession) Admin() (common.Address, error) { + return _ZcToken.Contract.Admin(&_ZcToken.CallOpts) +} + +// Admin is a free data retrieval call binding the contract method 0xf851a440. +// +// Solidity: function admin() view returns(address) +func (_ZcToken *ZcTokenCallerSession) Admin() (common.Address, error) { + return _ZcToken.Contract.Admin(&_ZcToken.CallOpts) +} + +// Allowance is a free data retrieval call binding the contract method 0xdd62ed3e. +// +// Solidity: function allowance(address o, address s) view returns(uint256) +func (_ZcToken *ZcTokenCaller) Allowance(opts *bind.CallOpts, o common.Address, s common.Address) (*big.Int, error) { + var out []interface{} + err := _ZcToken.contract.Call(opts, &out, "allowance", o, s) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// Allowance is a free data retrieval call binding the contract method 0xdd62ed3e. +// +// Solidity: function allowance(address o, address s) view returns(uint256) +func (_ZcToken *ZcTokenSession) Allowance(o common.Address, s common.Address) (*big.Int, error) { + return _ZcToken.Contract.Allowance(&_ZcToken.CallOpts, o, s) +} + +// Allowance is a free data retrieval call binding the contract method 0xdd62ed3e. +// +// Solidity: function allowance(address o, address s) view returns(uint256) +func (_ZcToken *ZcTokenCallerSession) Allowance(o common.Address, s common.Address) (*big.Int, error) { + return _ZcToken.Contract.Allowance(&_ZcToken.CallOpts, o, s) +} + +// BalanceOf is a free data retrieval call binding the contract method 0x70a08231. +// +// Solidity: function balanceOf(address a) view returns(uint256) +func (_ZcToken *ZcTokenCaller) BalanceOf(opts *bind.CallOpts, a common.Address) (*big.Int, error) { + var out []interface{} + err := _ZcToken.contract.Call(opts, &out, "balanceOf", a) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// BalanceOf is a free data retrieval call binding the contract method 0x70a08231. +// +// Solidity: function balanceOf(address a) view returns(uint256) +func (_ZcToken *ZcTokenSession) BalanceOf(a common.Address) (*big.Int, error) { + return _ZcToken.Contract.BalanceOf(&_ZcToken.CallOpts, a) +} + +// BalanceOf is a free data retrieval call binding the contract method 0x70a08231. +// +// Solidity: function balanceOf(address a) view returns(uint256) +func (_ZcToken *ZcTokenCallerSession) BalanceOf(a common.Address) (*big.Int, error) { + return _ZcToken.Contract.BalanceOf(&_ZcToken.CallOpts, a) +} + +// Decimals is a free data retrieval call binding the contract method 0x313ce567. +// +// Solidity: function decimals() view returns(uint8) +func (_ZcToken *ZcTokenCaller) Decimals(opts *bind.CallOpts) (uint8, error) { + var out []interface{} + err := _ZcToken.contract.Call(opts, &out, "decimals") + + if err != nil { + return *new(uint8), err + } + + out0 := *abi.ConvertType(out[0], new(uint8)).(*uint8) + + return out0, err + +} + +// Decimals is a free data retrieval call binding the contract method 0x313ce567. +// +// Solidity: function decimals() view returns(uint8) +func (_ZcToken *ZcTokenSession) Decimals() (uint8, error) { + return _ZcToken.Contract.Decimals(&_ZcToken.CallOpts) +} + +// Decimals is a free data retrieval call binding the contract method 0x313ce567. +// +// Solidity: function decimals() view returns(uint8) +func (_ZcToken *ZcTokenCallerSession) Decimals() (uint8, error) { + return _ZcToken.Contract.Decimals(&_ZcToken.CallOpts) +} + +// Domain is a free data retrieval call binding the contract method 0xc2fb26a6. +// +// Solidity: function domain() view returns(bytes32) +func (_ZcToken *ZcTokenCaller) Domain(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _ZcToken.contract.Call(opts, &out, "domain") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// Domain is a free data retrieval call binding the contract method 0xc2fb26a6. +// +// Solidity: function domain() view returns(bytes32) +func (_ZcToken *ZcTokenSession) Domain() ([32]byte, error) { + return _ZcToken.Contract.Domain(&_ZcToken.CallOpts) +} + +// Domain is a free data retrieval call binding the contract method 0xc2fb26a6. +// +// Solidity: function domain() view returns(bytes32) +func (_ZcToken *ZcTokenCallerSession) Domain() ([32]byte, error) { + return _ZcToken.Contract.Domain(&_ZcToken.CallOpts) +} + +// Maturity is a free data retrieval call binding the contract method 0x204f83f9. +// +// Solidity: function maturity() view returns(uint256) +func (_ZcToken *ZcTokenCaller) Maturity(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _ZcToken.contract.Call(opts, &out, "maturity") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// Maturity is a free data retrieval call binding the contract method 0x204f83f9. +// +// Solidity: function maturity() view returns(uint256) +func (_ZcToken *ZcTokenSession) Maturity() (*big.Int, error) { + return _ZcToken.Contract.Maturity(&_ZcToken.CallOpts) +} + +// Maturity is a free data retrieval call binding the contract method 0x204f83f9. +// +// Solidity: function maturity() view returns(uint256) +func (_ZcToken *ZcTokenCallerSession) Maturity() (*big.Int, error) { + return _ZcToken.Contract.Maturity(&_ZcToken.CallOpts) +} + +// Name is a free data retrieval call binding the contract method 0x06fdde03. +// +// Solidity: function name() view returns(string) +func (_ZcToken *ZcTokenCaller) Name(opts *bind.CallOpts) (string, error) { + var out []interface{} + err := _ZcToken.contract.Call(opts, &out, "name") + + if err != nil { + return *new(string), err + } + + out0 := *abi.ConvertType(out[0], new(string)).(*string) + + return out0, err + +} + +// Name is a free data retrieval call binding the contract method 0x06fdde03. +// +// Solidity: function name() view returns(string) +func (_ZcToken *ZcTokenSession) Name() (string, error) { + return _ZcToken.Contract.Name(&_ZcToken.CallOpts) +} + +// Name is a free data retrieval call binding the contract method 0x06fdde03. +// +// Solidity: function name() view returns(string) +func (_ZcToken *ZcTokenCallerSession) Name() (string, error) { + return _ZcToken.Contract.Name(&_ZcToken.CallOpts) +} + +// Nonces is a free data retrieval call binding the contract method 0x7ecebe00. +// +// Solidity: function nonces(address ) view returns(uint256) +func (_ZcToken *ZcTokenCaller) Nonces(opts *bind.CallOpts, arg0 common.Address) (*big.Int, error) { + var out []interface{} + err := _ZcToken.contract.Call(opts, &out, "nonces", arg0) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// Nonces is a free data retrieval call binding the contract method 0x7ecebe00. +// +// Solidity: function nonces(address ) view returns(uint256) +func (_ZcToken *ZcTokenSession) Nonces(arg0 common.Address) (*big.Int, error) { + return _ZcToken.Contract.Nonces(&_ZcToken.CallOpts, arg0) +} + +// Nonces is a free data retrieval call binding the contract method 0x7ecebe00. +// +// Solidity: function nonces(address ) view returns(uint256) +func (_ZcToken *ZcTokenCallerSession) Nonces(arg0 common.Address) (*big.Int, error) { + return _ZcToken.Contract.Nonces(&_ZcToken.CallOpts, arg0) +} + +// Symbol is a free data retrieval call binding the contract method 0x95d89b41. +// +// Solidity: function symbol() view returns(string) +func (_ZcToken *ZcTokenCaller) Symbol(opts *bind.CallOpts) (string, error) { + var out []interface{} + err := _ZcToken.contract.Call(opts, &out, "symbol") + + if err != nil { + return *new(string), err + } + + out0 := *abi.ConvertType(out[0], new(string)).(*string) + + return out0, err + +} + +// Symbol is a free data retrieval call binding the contract method 0x95d89b41. +// +// Solidity: function symbol() view returns(string) +func (_ZcToken *ZcTokenSession) Symbol() (string, error) { + return _ZcToken.Contract.Symbol(&_ZcToken.CallOpts) +} + +// Symbol is a free data retrieval call binding the contract method 0x95d89b41. +// +// Solidity: function symbol() view returns(string) +func (_ZcToken *ZcTokenCallerSession) Symbol() (string, error) { + return _ZcToken.Contract.Symbol(&_ZcToken.CallOpts) +} + +// TotalSupply is a free data retrieval call binding the contract method 0x18160ddd. +// +// Solidity: function totalSupply() view returns(uint256) +func (_ZcToken *ZcTokenCaller) TotalSupply(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _ZcToken.contract.Call(opts, &out, "totalSupply") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// TotalSupply is a free data retrieval call binding the contract method 0x18160ddd. +// +// Solidity: function totalSupply() view returns(uint256) +func (_ZcToken *ZcTokenSession) TotalSupply() (*big.Int, error) { + return _ZcToken.Contract.TotalSupply(&_ZcToken.CallOpts) +} + +// TotalSupply is a free data retrieval call binding the contract method 0x18160ddd. +// +// Solidity: function totalSupply() view returns(uint256) +func (_ZcToken *ZcTokenCallerSession) TotalSupply() (*big.Int, error) { + return _ZcToken.Contract.TotalSupply(&_ZcToken.CallOpts) +} + +// Underlying is a free data retrieval call binding the contract method 0x6f307dc3. +// +// Solidity: function underlying() view returns(address) +func (_ZcToken *ZcTokenCaller) Underlying(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _ZcToken.contract.Call(opts, &out, "underlying") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// Underlying is a free data retrieval call binding the contract method 0x6f307dc3. +// +// Solidity: function underlying() view returns(address) +func (_ZcToken *ZcTokenSession) Underlying() (common.Address, error) { + return _ZcToken.Contract.Underlying(&_ZcToken.CallOpts) +} + +// Underlying is a free data retrieval call binding the contract method 0x6f307dc3. +// +// Solidity: function underlying() view returns(address) +func (_ZcToken *ZcTokenCallerSession) Underlying() (common.Address, error) { + return _ZcToken.Contract.Underlying(&_ZcToken.CallOpts) +} + +// Approve is a paid mutator transaction binding the contract method 0x095ea7b3. +// +// Solidity: function approve(address s, uint256 a) returns(bool) +func (_ZcToken *ZcTokenTransactor) Approve(opts *bind.TransactOpts, s common.Address, a *big.Int) (*types.Transaction, error) { + return _ZcToken.contract.Transact(opts, "approve", s, a) +} + +// Approve is a paid mutator transaction binding the contract method 0x095ea7b3. +// +// Solidity: function approve(address s, uint256 a) returns(bool) +func (_ZcToken *ZcTokenSession) Approve(s common.Address, a *big.Int) (*types.Transaction, error) { + return _ZcToken.Contract.Approve(&_ZcToken.TransactOpts, s, a) +} + +// Approve is a paid mutator transaction binding the contract method 0x095ea7b3. +// +// Solidity: function approve(address s, uint256 a) returns(bool) +func (_ZcToken *ZcTokenTransactorSession) Approve(s common.Address, a *big.Int) (*types.Transaction, error) { + return _ZcToken.Contract.Approve(&_ZcToken.TransactOpts, s, a) +} + +// Burn is a paid mutator transaction binding the contract method 0x9dc29fac. +// +// Solidity: function burn(address f, uint256 a) returns(bool) +func (_ZcToken *ZcTokenTransactor) Burn(opts *bind.TransactOpts, f common.Address, a *big.Int) (*types.Transaction, error) { + return _ZcToken.contract.Transact(opts, "burn", f, a) +} + +// Burn is a paid mutator transaction binding the contract method 0x9dc29fac. +// +// Solidity: function burn(address f, uint256 a) returns(bool) +func (_ZcToken *ZcTokenSession) Burn(f common.Address, a *big.Int) (*types.Transaction, error) { + return _ZcToken.Contract.Burn(&_ZcToken.TransactOpts, f, a) +} + +// Burn is a paid mutator transaction binding the contract method 0x9dc29fac. +// +// Solidity: function burn(address f, uint256 a) returns(bool) +func (_ZcToken *ZcTokenTransactorSession) Burn(f common.Address, a *big.Int) (*types.Transaction, error) { + return _ZcToken.Contract.Burn(&_ZcToken.TransactOpts, f, a) +} + +// DecreaseAllowance is a paid mutator transaction binding the contract method 0xa457c2d7. +// +// Solidity: function decreaseAllowance(address s, uint256 a) returns(bool) +func (_ZcToken *ZcTokenTransactor) DecreaseAllowance(opts *bind.TransactOpts, s common.Address, a *big.Int) (*types.Transaction, error) { + return _ZcToken.contract.Transact(opts, "decreaseAllowance", s, a) +} + +// DecreaseAllowance is a paid mutator transaction binding the contract method 0xa457c2d7. +// +// Solidity: function decreaseAllowance(address s, uint256 a) returns(bool) +func (_ZcToken *ZcTokenSession) DecreaseAllowance(s common.Address, a *big.Int) (*types.Transaction, error) { + return _ZcToken.Contract.DecreaseAllowance(&_ZcToken.TransactOpts, s, a) +} + +// DecreaseAllowance is a paid mutator transaction binding the contract method 0xa457c2d7. +// +// Solidity: function decreaseAllowance(address s, uint256 a) returns(bool) +func (_ZcToken *ZcTokenTransactorSession) DecreaseAllowance(s common.Address, a *big.Int) (*types.Transaction, error) { + return _ZcToken.Contract.DecreaseAllowance(&_ZcToken.TransactOpts, s, a) +} + +// IncreaseAllowance is a paid mutator transaction binding the contract method 0x39509351. +// +// Solidity: function increaseAllowance(address s, uint256 a) returns(bool) +func (_ZcToken *ZcTokenTransactor) IncreaseAllowance(opts *bind.TransactOpts, s common.Address, a *big.Int) (*types.Transaction, error) { + return _ZcToken.contract.Transact(opts, "increaseAllowance", s, a) +} + +// IncreaseAllowance is a paid mutator transaction binding the contract method 0x39509351. +// +// Solidity: function increaseAllowance(address s, uint256 a) returns(bool) +func (_ZcToken *ZcTokenSession) IncreaseAllowance(s common.Address, a *big.Int) (*types.Transaction, error) { + return _ZcToken.Contract.IncreaseAllowance(&_ZcToken.TransactOpts, s, a) +} + +// IncreaseAllowance is a paid mutator transaction binding the contract method 0x39509351. +// +// Solidity: function increaseAllowance(address s, uint256 a) returns(bool) +func (_ZcToken *ZcTokenTransactorSession) IncreaseAllowance(s common.Address, a *big.Int) (*types.Transaction, error) { + return _ZcToken.Contract.IncreaseAllowance(&_ZcToken.TransactOpts, s, a) +} + +// Mint is a paid mutator transaction binding the contract method 0x40c10f19. +// +// Solidity: function mint(address t, uint256 a) returns(bool) +func (_ZcToken *ZcTokenTransactor) Mint(opts *bind.TransactOpts, t common.Address, a *big.Int) (*types.Transaction, error) { + return _ZcToken.contract.Transact(opts, "mint", t, a) +} + +// Mint is a paid mutator transaction binding the contract method 0x40c10f19. +// +// Solidity: function mint(address t, uint256 a) returns(bool) +func (_ZcToken *ZcTokenSession) Mint(t common.Address, a *big.Int) (*types.Transaction, error) { + return _ZcToken.Contract.Mint(&_ZcToken.TransactOpts, t, a) +} + +// Mint is a paid mutator transaction binding the contract method 0x40c10f19. +// +// Solidity: function mint(address t, uint256 a) returns(bool) +func (_ZcToken *ZcTokenTransactorSession) Mint(t common.Address, a *big.Int) (*types.Transaction, error) { + return _ZcToken.Contract.Mint(&_ZcToken.TransactOpts, t, a) +} + +// Permit is a paid mutator transaction binding the contract method 0xd505accf. +// +// Solidity: function permit(address o, address spender, uint256 a, uint256 d, uint8 v, bytes32 r, bytes32 s) returns() +func (_ZcToken *ZcTokenTransactor) Permit(opts *bind.TransactOpts, o common.Address, spender common.Address, a *big.Int, d *big.Int, v uint8, r [32]byte, s [32]byte) (*types.Transaction, error) { + return _ZcToken.contract.Transact(opts, "permit", o, spender, a, d, v, r, s) +} + +// Permit is a paid mutator transaction binding the contract method 0xd505accf. +// +// Solidity: function permit(address o, address spender, uint256 a, uint256 d, uint8 v, bytes32 r, bytes32 s) returns() +func (_ZcToken *ZcTokenSession) Permit(o common.Address, spender common.Address, a *big.Int, d *big.Int, v uint8, r [32]byte, s [32]byte) (*types.Transaction, error) { + return _ZcToken.Contract.Permit(&_ZcToken.TransactOpts, o, spender, a, d, v, r, s) +} + +// Permit is a paid mutator transaction binding the contract method 0xd505accf. +// +// Solidity: function permit(address o, address spender, uint256 a, uint256 d, uint8 v, bytes32 r, bytes32 s) returns() +func (_ZcToken *ZcTokenTransactorSession) Permit(o common.Address, spender common.Address, a *big.Int, d *big.Int, v uint8, r [32]byte, s [32]byte) (*types.Transaction, error) { + return _ZcToken.Contract.Permit(&_ZcToken.TransactOpts, o, spender, a, d, v, r, s) +} + +// Transfer is a paid mutator transaction binding the contract method 0xa9059cbb. +// +// Solidity: function transfer(address r, uint256 a) returns(bool) +func (_ZcToken *ZcTokenTransactor) Transfer(opts *bind.TransactOpts, r common.Address, a *big.Int) (*types.Transaction, error) { + return _ZcToken.contract.Transact(opts, "transfer", r, a) +} + +// Transfer is a paid mutator transaction binding the contract method 0xa9059cbb. +// +// Solidity: function transfer(address r, uint256 a) returns(bool) +func (_ZcToken *ZcTokenSession) Transfer(r common.Address, a *big.Int) (*types.Transaction, error) { + return _ZcToken.Contract.Transfer(&_ZcToken.TransactOpts, r, a) +} + +// Transfer is a paid mutator transaction binding the contract method 0xa9059cbb. +// +// Solidity: function transfer(address r, uint256 a) returns(bool) +func (_ZcToken *ZcTokenTransactorSession) Transfer(r common.Address, a *big.Int) (*types.Transaction, error) { + return _ZcToken.Contract.Transfer(&_ZcToken.TransactOpts, r, a) +} + +// TransferFrom is a paid mutator transaction binding the contract method 0x23b872dd. +// +// Solidity: function transferFrom(address s, address r, uint256 a) returns(bool) +func (_ZcToken *ZcTokenTransactor) TransferFrom(opts *bind.TransactOpts, s common.Address, r common.Address, a *big.Int) (*types.Transaction, error) { + return _ZcToken.contract.Transact(opts, "transferFrom", s, r, a) +} + +// TransferFrom is a paid mutator transaction binding the contract method 0x23b872dd. +// +// Solidity: function transferFrom(address s, address r, uint256 a) returns(bool) +func (_ZcToken *ZcTokenSession) TransferFrom(s common.Address, r common.Address, a *big.Int) (*types.Transaction, error) { + return _ZcToken.Contract.TransferFrom(&_ZcToken.TransactOpts, s, r, a) +} + +// TransferFrom is a paid mutator transaction binding the contract method 0x23b872dd. +// +// Solidity: function transferFrom(address s, address r, uint256 a) returns(bool) +func (_ZcToken *ZcTokenTransactorSession) TransferFrom(s common.Address, r common.Address, a *big.Int) (*types.Transaction, error) { + return _ZcToken.Contract.TransferFrom(&_ZcToken.TransactOpts, s, r, a) +} + +// ZcTokenApprovalIterator is returned from FilterApproval and is used to iterate over the raw logs and unpacked data for Approval events raised by the ZcToken contract. +type ZcTokenApprovalIterator struct { + Event *ZcTokenApproval // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *ZcTokenApprovalIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(ZcTokenApproval) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(ZcTokenApproval) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *ZcTokenApprovalIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *ZcTokenApprovalIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// ZcTokenApproval represents a Approval event raised by the ZcToken contract. +type ZcTokenApproval struct { + Owner common.Address + Spender common.Address + Value *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterApproval is a free log retrieval operation binding the contract event 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925. +// +// Solidity: event Approval(address indexed owner, address indexed spender, uint256 value) +func (_ZcToken *ZcTokenFilterer) FilterApproval(opts *bind.FilterOpts, owner []common.Address, spender []common.Address) (*ZcTokenApprovalIterator, error) { + + var ownerRule []interface{} + for _, ownerItem := range owner { + ownerRule = append(ownerRule, ownerItem) + } + var spenderRule []interface{} + for _, spenderItem := range spender { + spenderRule = append(spenderRule, spenderItem) + } + + logs, sub, err := _ZcToken.contract.FilterLogs(opts, "Approval", ownerRule, spenderRule) + if err != nil { + return nil, err + } + return &ZcTokenApprovalIterator{contract: _ZcToken.contract, event: "Approval", logs: logs, sub: sub}, nil +} + +// WatchApproval is a free log subscription operation binding the contract event 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925. +// +// Solidity: event Approval(address indexed owner, address indexed spender, uint256 value) +func (_ZcToken *ZcTokenFilterer) WatchApproval(opts *bind.WatchOpts, sink chan<- *ZcTokenApproval, owner []common.Address, spender []common.Address) (event.Subscription, error) { + + var ownerRule []interface{} + for _, ownerItem := range owner { + ownerRule = append(ownerRule, ownerItem) + } + var spenderRule []interface{} + for _, spenderItem := range spender { + spenderRule = append(spenderRule, spenderItem) + } + + logs, sub, err := _ZcToken.contract.WatchLogs(opts, "Approval", ownerRule, spenderRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(ZcTokenApproval) + if err := _ZcToken.contract.UnpackLog(event, "Approval", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseApproval is a log parse operation binding the contract event 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925. +// +// Solidity: event Approval(address indexed owner, address indexed spender, uint256 value) +func (_ZcToken *ZcTokenFilterer) ParseApproval(log types.Log) (*ZcTokenApproval, error) { + event := new(ZcTokenApproval) + if err := _ZcToken.contract.UnpackLog(event, "Approval", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// ZcTokenTransferIterator is returned from FilterTransfer and is used to iterate over the raw logs and unpacked data for Transfer events raised by the ZcToken contract. +type ZcTokenTransferIterator struct { + Event *ZcTokenTransfer // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *ZcTokenTransferIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(ZcTokenTransfer) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(ZcTokenTransfer) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *ZcTokenTransferIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *ZcTokenTransferIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// ZcTokenTransfer represents a Transfer event raised by the ZcToken contract. +type ZcTokenTransfer struct { + From common.Address + To common.Address + Value *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterTransfer is a free log retrieval operation binding the contract event 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef. +// +// Solidity: event Transfer(address indexed from, address indexed to, uint256 value) +func (_ZcToken *ZcTokenFilterer) FilterTransfer(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*ZcTokenTransferIterator, error) { + + var fromRule []interface{} + for _, fromItem := range from { + fromRule = append(fromRule, fromItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _ZcToken.contract.FilterLogs(opts, "Transfer", fromRule, toRule) + if err != nil { + return nil, err + } + return &ZcTokenTransferIterator{contract: _ZcToken.contract, event: "Transfer", logs: logs, sub: sub}, nil +} + +// WatchTransfer is a free log subscription operation binding the contract event 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef. +// +// Solidity: event Transfer(address indexed from, address indexed to, uint256 value) +func (_ZcToken *ZcTokenFilterer) WatchTransfer(opts *bind.WatchOpts, sink chan<- *ZcTokenTransfer, from []common.Address, to []common.Address) (event.Subscription, error) { + + var fromRule []interface{} + for _, fromItem := range from { + fromRule = append(fromRule, fromItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _ZcToken.contract.WatchLogs(opts, "Transfer", fromRule, toRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(ZcTokenTransfer) + if err := _ZcToken.contract.UnpackLog(event, "Transfer", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseTransfer is a log parse operation binding the contract event 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef. +// +// Solidity: event Transfer(address indexed from, address indexed to, uint256 value) +func (_ZcToken *ZcTokenFilterer) ParseTransfer(log types.Log) (*ZcTokenTransfer, error) { + event := new(ZcTokenTransfer) + if err := _ZcToken.contract.UnpackLog(event, "Transfer", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} diff --git a/gost/test/vaulttracker/Abstracts.sol b/gost/test/vaulttracker/Abstracts.sol new file mode 100644 index 0000000..0773314 --- /dev/null +++ b/gost/test/vaulttracker/Abstracts.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: UNLICENSED + +pragma solidity 0.8.4; + +abstract contract Erc20 { + function approve(address, uint256) virtual external returns (bool); + function transfer(address, uint256) virtual external returns (bool); + function balanceOf(address) virtual external returns (uint256); + function transferFrom(address, address, uint256) virtual public returns (bool); +} + +abstract contract CErc20 is Erc20 { + function mint(uint256) virtual external returns (uint256); + function redeem(uint256) virtual external returns (uint256); + function redeemUnderlying(uint256) virtual external returns (uint256); + function exchangeRateCurrent() virtual external returns (uint256); +} diff --git a/gost/test/vaulttracker/CErc20.abi b/gost/test/vaulttracker/CErc20.abi new file mode 100644 index 0000000..03e1ca1 --- /dev/null +++ b/gost/test/vaulttracker/CErc20.abi @@ -0,0 +1 @@ +[{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"exchangeRateCurrent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"mint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"redeem","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"redeemUnderlying","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file diff --git a/gost/test/vaulttracker/CErc20.bin b/gost/test/vaulttracker/CErc20.bin new file mode 100644 index 0000000..e69de29 diff --git a/gost/test/vaulttracker/Erc20.abi b/gost/test/vaulttracker/Erc20.abi new file mode 100644 index 0000000..88abe05 --- /dev/null +++ b/gost/test/vaulttracker/Erc20.abi @@ -0,0 +1 @@ +[{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file diff --git a/gost/test/vaulttracker/Erc20.bin b/gost/test/vaulttracker/Erc20.bin new file mode 100644 index 0000000..e69de29 diff --git a/gost/test/vaulttracker/VaultTracker.abi b/gost/test/vaulttracker/VaultTracker.abi new file mode 100644 index 0000000..3fe5f20 --- /dev/null +++ b/gost/test/vaulttracker/VaultTracker.abi @@ -0,0 +1 @@ +[{"inputs":[{"internalType":"uint256","name":"m","type":"uint256"},{"internalType":"address","name":"c","type":"address"},{"internalType":"address","name":"s","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"o","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"addNotional","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"admin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"o","type":"address"}],"name":"balancesOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cTokenAddr","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"matureVault","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"matured","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maturity","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maturityRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"o","type":"address"}],"name":"redeemInterest","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"o","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"removeNotional","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"swivel","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"f","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"transferNotionalFee","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"f","type":"address"},{"internalType":"address","name":"t","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"transferNotionalFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"vaults","outputs":[{"internalType":"uint256","name":"notional","type":"uint256"},{"internalType":"uint256","name":"redeemable","type":"uint256"},{"internalType":"uint256","name":"exchangeRate","type":"uint256"}],"stateMutability":"view","type":"function"}] \ No newline at end of file diff --git a/gost/test/vaulttracker/VaultTracker.bin b/gost/test/vaulttracker/VaultTracker.bin new file mode 100644 index 0000000..0ce68a8 --- /dev/null +++ b/gost/test/vaulttracker/VaultTracker.bin @@ -0,0 +1 @@ +6101006040523480156200001257600080fd5b50604051620022723803806200227283398181016040528101906200003891906200011c565b3373ffffffffffffffffffffffffffffffffffffffff1660808173ffffffffffffffffffffffffffffffffffffffff1660601b815250508260e081815250508173ffffffffffffffffffffffffffffffffffffffff1660a08173ffffffffffffffffffffffffffffffffffffffff1660601b815250508073ffffffffffffffffffffffffffffffffffffffff1660c08173ffffffffffffffffffffffffffffffffffffffff1660601b81525050505050620001e4565b600081519050620000ff81620001b0565b92915050565b6000815190506200011681620001ca565b92915050565b6000806000606084860312156200013257600080fd5b6000620001428682870162000105565b93505060206200015586828701620000ee565b92505060406200016886828701620000ee565b9150509250925092565b60006200017f8262000186565b9050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b620001bb8162000172565b8114620001c757600080fd5b50565b620001d581620001a6565b8114620001e157600080fd5b50565b60805160601c60a05160601c60c05160601c60e051611fe26200029060003960008181610b8a01526110880152600081816103160152818161160a015261186a0152600081816104f30152818161099901528181610d090152818161110501528181611246015281816116ab01526119560152600081816103420152818161089101528181610bc301528181610fa9015281816111b50152818161150b015261197a0152611fe26000f3fe608060405234801561001057600080fd5b50600436106100ea5760003560e01c80636392a51f1161008c578063a622ee7c11610066578063a622ee7c14610276578063b326258d146102a8578063b7dd3483146102d8578063f851a440146102f6576100ea565b80636392a51f146101f75780636b868d5114610228578063a01cfffb14610246576100ea565b806319caf46c116100c857806319caf46c1461015b578063204f83f91461018b578063454c87b3146101a9578063613a28d1146101c7576100ea565b8063012b264a146100ef57806311554c431461010d578063177946731461012b575b600080fd5b6100f7610314565b6040516101049190611b94565b60405180910390f35b610115610338565b6040516101229190611c6a565b60405180910390f35b61014560048036038101906101409190611a04565b61033e565b6040516101529190611baf565b60405180910390f35b610175600480360381019061017091906119db565b61088d565b6040516101829190611c6a565b60405180910390f35b610193610b88565b6040516101a09190611c6a565b60405180910390f35b6101b1610bac565b6040516101be9190611baf565b60405180910390f35b6101e160048036038101906101dc9190611a53565b610bbf565b6040516101ee9190611baf565b60405180910390f35b610211600480360381019061020c91906119db565b610f15565b60405161021f929190611c85565b60405180910390f35b610230610fa5565b60405161023d9190611baf565b60405180910390f35b610260600480360381019061025b9190611a53565b6111b1565b60405161026d9190611baf565b60405180910390f35b610290600480360381019061028b91906119db565b6114dd565b60405161029f93929190611cae565b60405180910390f35b6102c260048036038101906102bd9190611a53565b611507565b6040516102cf9190611baf565b60405180910390f35b6102e0611954565b6040516102ed9190611b94565b60405180910390f35b6102fe611978565b60405161030b9190611b94565b60405180910390f35b7f000000000000000000000000000000000000000000000000000000000000000081565b60025481565b60007f00000000000000000000000000000000000000000000000000000000000000008073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146103cf576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016103c690611bea565b60405180910390fd5b60008060008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206040518060600160405290816000820154815260200160018201548152602001600282015481525050905060008060008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206040518060600160405290816000820154815260200160018201548152602001600282015481525050905084826000015110156104ec576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016104e390611c0a565b60405180910390fd5b60008060007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663bd6d894d6040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561055957600080fd5b505af115801561056d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105919190611a8f565b9050600160009054906101000a900460ff16156105ed576a52b7d2dcc80cd2e400000085604001516a52b7d2dcc80cd2e40000006002546105d29190611d7d565b6105dc9190611d4c565b6105e69190611dd7565b925061062c565b6a52b7d2dcc80cd2e400000085604001516a52b7d2dcc80cd2e4000000836106159190611d7d565b61061f9190611d4c565b6106299190611dd7565b92505b6a52b7d2dcc80cd2e40000008560000151846106489190611d7d565b6106529190611d4c565b915081856020018181516106669190611cf6565b91508181525050878560000181815161067f9190611dd7565b9150818152505080856040018181525050846000808c73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000820151816000015560208201518160010155604082015181600201559050506000846000015111156107f8576000600160009054906101000a900460ff1615610759576a52b7d2dcc80cd2e400000085604001516a52b7d2dcc80cd2e400000060025461073e9190611d7d565b6107489190611d4c565b6107529190611dd7565b9350610798565b6a52b7d2dcc80cd2e400000085604001516a52b7d2dcc80cd2e4000000846107819190611d7d565b61078b9190611d4c565b6107959190611dd7565b93505b6a52b7d2dcc80cd2e40000008560000151856107b49190611d7d565b6107be9190611d4c565b905080856020018181516107d29190611cf6565b9150818152505088856000018181516107eb9190611cf6565b9150818152505050610812565b878460000181815161080a9190611cf6565b915081815250505b80846040018181525050836000808b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082015181600001556020820151816001015560408201518160020155905050600196505050505050509392505050565b60007f00000000000000000000000000000000000000000000000000000000000000008073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461091e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161091590611bea565b60405180910390fd5b60008060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206040518060600160405290816000820154815260200160018201548152602001600282015481525050905060008160200151905060008060007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663bd6d894d6040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156109ff57600080fd5b505af1158015610a13573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a379190611a8f565b9050600160009054906101000a900460ff1615610a93576a52b7d2dcc80cd2e400000085604001516a52b7d2dcc80cd2e4000000600254610a789190611d7d565b610a829190611d4c565b610a8c9190611dd7565b9250610ad2565b6a52b7d2dcc80cd2e400000085604001516a52b7d2dcc80cd2e400000083610abb9190611d7d565b610ac59190611d4c565b610acf9190611dd7565b92505b6a52b7d2dcc80cd2e4000000856000015184610aee9190611d7d565b610af89190611d4c565b9150808560400181815250506000856020018181525050846000808a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000820151816000015560208201518160010155604082015181600201559050508184610b7b9190611cf6565b9650505050505050919050565b7f000000000000000000000000000000000000000000000000000000000000000081565b600160009054906101000a900460ff1681565b60007f00000000000000000000000000000000000000000000000000000000000000008073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610c50576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c4790611bea565b60405180910390fd5b60008060008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020604051806060016040529081600082015481526020016001820154815260200160028201548152505090508381600001511015610d02576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610cf990611c4a565b60405180910390fd5b60008060007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663bd6d894d6040518163ffffffff1660e01b8152600401602060405180830381600087803b158015610d6f57600080fd5b505af1158015610d83573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610da79190611a8f565b9050600160009054906101000a900460ff1615610e03576a52b7d2dcc80cd2e400000084604001516a52b7d2dcc80cd2e4000000600254610de89190611d7d565b610df29190611d4c565b610dfc9190611dd7565b9250610e42565b6a52b7d2dcc80cd2e400000084604001516a52b7d2dcc80cd2e400000083610e2b9190611d7d565b610e359190611d4c565b610e3f9190611dd7565b92505b6a52b7d2dcc80cd2e4000000846000015184610e5e9190611d7d565b610e689190611d4c565b91508184602001818151610e7c9190611cf6565b915081815250508684600001818151610e959190611dd7565b9150818152505080846040018181525050836000808a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008201518160000155602082015181600101556040820151816002015590505060019550505050505092915050565b6000806000808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600001546000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206001015491509150915091565b60007f00000000000000000000000000000000000000000000000000000000000000008073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611036576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161102d90611bea565b60405180910390fd5b600160009054906101000a900460ff1615611086576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161107d90611c2a565b60405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000004210156110e9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016110e090611bca565b60405180910390fd5b60018060006101000a81548160ff0219169083151502179055507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663bd6d894d6040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561116b57600080fd5b505af115801561117f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111a39190611a8f565b600281905550600191505090565b60007f00000000000000000000000000000000000000000000000000000000000000008073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611242576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161123990611bea565b60405180910390fd5b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663bd6d894d6040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156112ac57600080fd5b505af11580156112c0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112e49190611a8f565b905060008060008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206040518060600160405290816000820154815260200160018201548152602001600282015481525050905060008160000151111561145b57600080600160009054906101000a900460ff16156113bb576a52b7d2dcc80cd2e400000083604001516a52b7d2dcc80cd2e40000006002546113a09190611d7d565b6113aa9190611d4c565b6113b49190611dd7565b91506113fa565b6a52b7d2dcc80cd2e400000083604001516a52b7d2dcc80cd2e4000000866113e39190611d7d565b6113ed9190611d4c565b6113f79190611dd7565b91505b6a52b7d2dcc80cd2e40000008360000151836114169190611d7d565b6114209190611d4c565b905080836020018181516114349190611cf6565b91508181525050868360000181815161144d9190611cf6565b915081815250505050611466565b848160000181815250505b81816040018181525050806000808873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000820151816000015560208201518160010155604082015181600201559050506001935050505092915050565b60006020528060005260406000206000915090508060000154908060010154908060020154905083565b60007f00000000000000000000000000000000000000000000000000000000000000008073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611598576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161158f90611bea565b60405180910390fd5b60008060008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206040518060600160405290816000820154815260200160018201548152602001600282015481525050905060008060007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206040518060600160405290816000820154815260200160018201548152602001600282015481525050905084826000018181516116a09190611dd7565b9150818152505060007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663bd6d894d6040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561171157600080fd5b505af1158015611725573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117499190611a8f565b90506000808284604001511461184b57600084604001511461184057600160009054906101000a900460ff16156117bf576a52b7d2dcc80cd2e400000084604001516a52b7d2dcc80cd2e40000006002546117a49190611d7d565b6117ae9190611d4c565b6117b89190611dd7565b91506117fe565b6a52b7d2dcc80cd2e400000084604001516a52b7d2dcc80cd2e4000000856117e79190611d7d565b6117f19190611d4c565b6117fb9190611dd7565b91505b6a52b7d2dcc80cd2e400000084600001518361181a9190611d7d565b6118249190611d4c565b905080846020018181516118389190611cf6565b915081815250505b828460400181815250505b878460000181815161185d9190611cf6565b91508181525050836000807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082015181600001556020820151816001015560408201518160020155905050846000808b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000820151816000015560208201518160010155604082015181600201559050506001965050505050505092915050565b7f000000000000000000000000000000000000000000000000000000000000000081565b7f000000000000000000000000000000000000000000000000000000000000000081565b6000813590506119ab81611f7e565b92915050565b6000813590506119c081611f95565b92915050565b6000815190506119d581611f95565b92915050565b6000602082840312156119ed57600080fd5b60006119fb8482850161199c565b91505092915050565b600080600060608486031215611a1957600080fd5b6000611a278682870161199c565b9350506020611a388682870161199c565b9250506040611a49868287016119b1565b9150509250925092565b60008060408385031215611a6657600080fd5b6000611a748582860161199c565b9250506020611a85858286016119b1565b9150509250929050565b600060208284031215611aa157600080fd5b6000611aaf848285016119c6565b91505092915050565b611ac181611e0b565b82525050565b611ad081611e1d565b82525050565b6000611ae3601d83611ce5565b9150611aee82611eb1565b602082019050919050565b6000611b06601483611ce5565b9150611b1182611eda565b602082019050919050565b6000611b29602083611ce5565b9150611b3482611f03565b602082019050919050565b6000611b4c600f83611ce5565b9150611b5782611f2c565b602082019050919050565b6000611b6f601c83611ce5565b9150611b7a82611f55565b602082019050919050565b611b8e81611e49565b82525050565b6000602082019050611ba96000830184611ab8565b92915050565b6000602082019050611bc46000830184611ac7565b92915050565b60006020820190508181036000830152611be381611ad6565b9050919050565b60006020820190508181036000830152611c0381611af9565b9050919050565b60006020820190508181036000830152611c2381611b1c565b9050919050565b60006020820190508181036000830152611c4381611b3f565b9050919050565b60006020820190508181036000830152611c6381611b62565b9050919050565b6000602082019050611c7f6000830184611b85565b92915050565b6000604082019050611c9a6000830185611b85565b611ca76020830184611b85565b9392505050565b6000606082019050611cc36000830186611b85565b611cd06020830185611b85565b611cdd6040830184611b85565b949350505050565b600082825260208201905092915050565b6000611d0182611e49565b9150611d0c83611e49565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff03821115611d4157611d40611e53565b5b828201905092915050565b6000611d5782611e49565b9150611d6283611e49565b925082611d7257611d71611e82565b5b828204905092915050565b6000611d8882611e49565b9150611d9383611e49565b9250817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615611dcc57611dcb611e53565b5b828202905092915050565b6000611de282611e49565b9150611ded83611e49565b925082821015611e0057611dff611e53565b5b828203905092915050565b6000611e1682611e29565b9050919050565b60008115159050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b7f6d6174757269747920686173206e6f74206265656e2072656163686564000000600082015250565b7f73656e646572206d7573742062652061646d696e000000000000000000000000600082015250565b7f616d6f756e74206578636565647320617661696c61626c652062616c616e6365600082015250565b7f616c7265616479206d6174757265640000000000000000000000000000000000600082015250565b7f616d6f756e742065786365656473207661756c742062616c616e636500000000600082015250565b611f8781611e0b565b8114611f9257600080fd5b50565b611f9e81611e49565b8114611fa957600080fd5b5056fea2646970667358221220dfb3b8d5f3bf70e0febc8b8acff3431c07144d9e66667cf76c63daba9fc452f064736f6c63430008040033 \ No newline at end of file diff --git a/gost/test/vaulttracker/VaultTracker.sol b/gost/test/vaulttracker/VaultTracker.sol new file mode 100644 index 0000000..8128773 --- /dev/null +++ b/gost/test/vaulttracker/VaultTracker.sol @@ -0,0 +1,251 @@ +// SPDX-License-Identifier: UNLICENSED + +pragma solidity 0.8.4; + +import "./Abstracts.sol"; + +contract VaultTracker { + struct Vault { + uint256 notional; + uint256 redeemable; + uint256 exchangeRate; + } + + mapping(address => Vault) public vaults; + + address public immutable admin; + address public immutable cTokenAddr; + address public immutable swivel; + bool public matured; + uint256 public immutable maturity; + uint256 public maturityRate; + + /// @param m Maturity timestamp of the new market + /// @param c cToken address associated with underlying for the new market + /// @param s address of the deployed swivel contract + constructor(uint256 m, address c, address s) { + admin = msg.sender; + maturity = m; + cTokenAddr = c; + swivel = s; + } + + /// @notice Adds notional (nTokens) to a given user's vault + /// @param o Address that owns a vault + /// @param a Amount of notional added + function addNotional(address o, uint256 a) public onlyAdmin(admin) returns (bool) { + uint256 exchangeRate = CErc20(cTokenAddr).exchangeRateCurrent(); + + Vault memory vlt = vaults[o]; + + if (vlt.notional > 0) { + uint256 yield; + uint256 interest; + + // if market has matured, calculate marginal interest between the maturity rate and previous position exchange rate + // otherwise, calculate marginal exchange rate between current and previous exchange rate. + if (matured) { // Calculate marginal interest + yield = ((maturityRate * 1e26) / vlt.exchangeRate) - 1e26; + } else { + yield = ((exchangeRate * 1e26) / vlt.exchangeRate) - 1e26; + } + + interest = (yield * vlt.notional) / 1e26; + // add interest and amount to position, reset cToken exchange rate + vlt.redeemable += interest; + vlt.notional += a; + } else { + vlt.notional = a; + } + + vlt.exchangeRate = exchangeRate; + vaults[o] = vlt; + + return true; + } + + /// @notice Removes notional (nTokens) from a given user's vault + /// @param o Address that owns a vault + /// @param a Amount of notional to remove + function removeNotional(address o, uint256 a) public onlyAdmin(admin) returns (bool) { + + Vault memory vlt = vaults[o]; + + require(vlt.notional >= a, "amount exceeds vault balance"); + + uint256 yield; + uint256 interest; + uint256 exchangeRate = CErc20(cTokenAddr).exchangeRateCurrent(); + + // if market has matured, calculate marginal interest between the maturity rate and previous position exchange rate + // otherwise, calculate marginal exchange rate between current and previous exchange rate. + if (matured) { // Calculate marginal interest + yield = ((maturityRate * 1e26) / vlt.exchangeRate) - 1e26; + } else { + // calculate marginal interest + yield = ((exchangeRate * 1e26) / vlt.exchangeRate) - 1e26; + } + + interest = (yield * vlt.notional) / 1e26; + // remove amount from position, Add interest to position, reset cToken exchange rate + vlt.redeemable += interest; + vlt.notional -= a; + vlt.exchangeRate = exchangeRate; + + vaults[o] = vlt; + + return true; + } + + /// @notice Redeem's the `redeemable` + marginal interest from a given user's vault + /// @param o Address that owns a vault + function redeemInterest(address o) external onlyAdmin(admin) returns (uint256) { + + Vault memory vlt = vaults[o]; + + uint256 redeemable = vlt.redeemable; + uint256 yield; + uint256 interest; + uint256 exchangeRate = CErc20(cTokenAddr).exchangeRateCurrent(); + + // if market has matured, calculate marginal interest between the maturity rate and previous position exchange rate + // otherwise, calculate marginal exchange rate between current and previous exchange rate. + if (matured) { // Calculate marginal interest + yield = ((maturityRate * 1e26) / vlt.exchangeRate) - 1e26; + } else { + // calculate marginal interest + yield = ((exchangeRate * 1e26) / vlt.exchangeRate) - 1e26; + } + + interest = (yield * vlt.notional) / 1e26; + + vlt.exchangeRate = exchangeRate; + vlt.redeemable = 0; + + vaults[o] = vlt; + + // return adds marginal interest to previously accrued redeemable interest + return (redeemable + interest); + } + + /// @notice Matures the vault and sets the market's maturityRate + function matureVault() external onlyAdmin(admin) returns (bool) { + require(!matured, 'already matured'); + require(block.timestamp >= maturity, 'maturity has not been reached'); + matured = true; + maturityRate = CErc20(cTokenAddr).exchangeRateCurrent(); + return true; + } + + /// @notice Transfers notional (nTokens) from one user to another + /// @param f Owner of the amount + /// @param t Recipient of the amount + /// @param a Amount to transfer + function transferNotionalFrom(address f, address t, uint256 a) external onlyAdmin(admin) returns (bool) { + Vault memory from = vaults[f]; + Vault memory to = vaults[t]; + + require(from.notional >= a, "amount exceeds available balance"); + + uint256 yield; + uint256 interest; + uint256 exchangeRate = CErc20(cTokenAddr).exchangeRateCurrent(); + + // if market has matured, calculate marginal interest between the maturity rate and previous position exchange rate + // otherwise, calculate marginal exchange rate between current and previous exchange rate. + if (matured) { + // calculate marginal interest + yield = ((maturityRate * 1e26) / from.exchangeRate) - 1e26; + } else { + yield = ((exchangeRate * 1e26) / from.exchangeRate) - 1e26; + } + + interest = (yield * from.notional) / 1e26; + // remove amount from position, Add interest to position, reset cToken exchange rate + from.redeemable += interest; + from.notional -= a; + from.exchangeRate = exchangeRate; + + vaults[f] = from; + + // transfer notional to address "t", calculate interest if necessary + if (to.notional > 0) { + uint256 newVaultInterest; + + // if market has matured, calculate marginal interest between the maturity rate and previous position exchange rate + // otherwise, calculate marginal exchange rate between current and previous exchange rate. + if (matured) { + // calculate marginal interest + yield = ((maturityRate * 1e26) / to.exchangeRate) - 1e26; + } else { + yield = ((exchangeRate * 1e26) / to.exchangeRate) - 1e26; + } + + newVaultInterest = (yield * to.notional) / 1e26; + // add interest and amount to position, reset cToken exchange rate + to.redeemable += newVaultInterest; + to.notional += a; + } else { + to.notional += a; + } + + to.exchangeRate = exchangeRate; + vaults[t] = to; + + return true; + } + + /// @notice transfers, in notional, a fee payment to the Swivel contract without recalculating marginal interest for the owner + /// @param f Owner of the amount + /// @param a Amount to transfer + function transferNotionalFee(address f, uint256 a) external onlyAdmin(admin) returns(bool) { + Vault memory oVault = vaults[f]; + Vault memory sVault = vaults[swivel]; + + // remove notional from its owner + oVault.notional -= a; + + uint256 exchangeRate = CErc20(cTokenAddr).exchangeRateCurrent(); + uint256 yield; + uint256 interest; + + // check if exchangeRate has been stored already this block. If not, calculate marginal interest + store exchangeRate + if (sVault.exchangeRate != exchangeRate) { + // the rate will be 0 if swivel did not already have a vault + if (sVault.exchangeRate != 0) { + // if market has matured, calculate marginal interest between the maturity rate and previous position exchange rate + // otherwise, calculate marginal exchange rate between current and previous exchange rate. + if (matured) { + // calculate marginal interest + yield = ((maturityRate * 1e26) / sVault.exchangeRate) - 1e26; + } else { + yield = ((exchangeRate * 1e26) / sVault.exchangeRate) - 1e26; + } + + interest = (yield * sVault.notional) / 1e26; + // add interest and amount, reset cToken exchange rate + sVault.redeemable += interest; + } + sVault.exchangeRate = exchangeRate; + } + + // add notional to swivel's vault + sVault.notional += a; + + // store the adjusted vaults + vaults[swivel] = sVault; + vaults[f] = oVault; + return true; + } + + /// @notice Returns both relevant balances for a given user's vault + /// @param o Address that owns a vault + function balancesOf(address o) public view returns (uint256, uint256) { + return (vaults[o].notional, vaults[o].redeemable); + } + + modifier onlyAdmin(address a) { + require(msg.sender == a, 'sender must be admin'); + _; + } +} diff --git a/gost/test/vaulttracker/vaulttracker.go b/gost/test/vaulttracker/vaulttracker.go new file mode 100644 index 0000000..e8ce862 --- /dev/null +++ b/gost/test/vaulttracker/vaulttracker.go @@ -0,0 +1,583 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package vaulttracker + +import ( + "math/big" + "strings" + + ethereum "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/event" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription +) + +// VaultTrackerABI is the input ABI used to generate the binding from. +const VaultTrackerABI = "[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"m\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"c\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"s\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"o\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"a\",\"type\":\"uint256\"}],\"name\":\"addNotional\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"admin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"o\",\"type\":\"address\"}],\"name\":\"balancesOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"cTokenAddr\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"matureVault\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"matured\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"maturity\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"maturityRate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"o\",\"type\":\"address\"}],\"name\":\"redeemInterest\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"o\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"a\",\"type\":\"uint256\"}],\"name\":\"removeNotional\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"swivel\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"f\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"a\",\"type\":\"uint256\"}],\"name\":\"transferNotionalFee\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"f\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"t\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"a\",\"type\":\"uint256\"}],\"name\":\"transferNotionalFrom\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"vaults\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"notional\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"redeemable\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"exchangeRate\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]" + +// VaultTrackerBin is the compiled bytecode used for deploying new contracts. +var VaultTrackerBin = "0x6101006040523480156200001257600080fd5b50604051620022723803806200227283398181016040528101906200003891906200011c565b3373ffffffffffffffffffffffffffffffffffffffff1660808173ffffffffffffffffffffffffffffffffffffffff1660601b815250508260e081815250508173ffffffffffffffffffffffffffffffffffffffff1660a08173ffffffffffffffffffffffffffffffffffffffff1660601b815250508073ffffffffffffffffffffffffffffffffffffffff1660c08173ffffffffffffffffffffffffffffffffffffffff1660601b81525050505050620001e4565b600081519050620000ff81620001b0565b92915050565b6000815190506200011681620001ca565b92915050565b6000806000606084860312156200013257600080fd5b6000620001428682870162000105565b93505060206200015586828701620000ee565b92505060406200016886828701620000ee565b9150509250925092565b60006200017f8262000186565b9050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b620001bb8162000172565b8114620001c757600080fd5b50565b620001d581620001a6565b8114620001e157600080fd5b50565b60805160601c60a05160601c60c05160601c60e051611fe26200029060003960008181610b8a01526110880152600081816103160152818161160a015261186a0152600081816104f30152818161099901528181610d090152818161110501528181611246015281816116ab01526119560152600081816103420152818161089101528181610bc301528181610fa9015281816111b50152818161150b015261197a0152611fe26000f3fe608060405234801561001057600080fd5b50600436106100ea5760003560e01c80636392a51f1161008c578063a622ee7c11610066578063a622ee7c14610276578063b326258d146102a8578063b7dd3483146102d8578063f851a440146102f6576100ea565b80636392a51f146101f75780636b868d5114610228578063a01cfffb14610246576100ea565b806319caf46c116100c857806319caf46c1461015b578063204f83f91461018b578063454c87b3146101a9578063613a28d1146101c7576100ea565b8063012b264a146100ef57806311554c431461010d578063177946731461012b575b600080fd5b6100f7610314565b6040516101049190611b94565b60405180910390f35b610115610338565b6040516101229190611c6a565b60405180910390f35b61014560048036038101906101409190611a04565b61033e565b6040516101529190611baf565b60405180910390f35b610175600480360381019061017091906119db565b61088d565b6040516101829190611c6a565b60405180910390f35b610193610b88565b6040516101a09190611c6a565b60405180910390f35b6101b1610bac565b6040516101be9190611baf565b60405180910390f35b6101e160048036038101906101dc9190611a53565b610bbf565b6040516101ee9190611baf565b60405180910390f35b610211600480360381019061020c91906119db565b610f15565b60405161021f929190611c85565b60405180910390f35b610230610fa5565b60405161023d9190611baf565b60405180910390f35b610260600480360381019061025b9190611a53565b6111b1565b60405161026d9190611baf565b60405180910390f35b610290600480360381019061028b91906119db565b6114dd565b60405161029f93929190611cae565b60405180910390f35b6102c260048036038101906102bd9190611a53565b611507565b6040516102cf9190611baf565b60405180910390f35b6102e0611954565b6040516102ed9190611b94565b60405180910390f35b6102fe611978565b60405161030b9190611b94565b60405180910390f35b7f000000000000000000000000000000000000000000000000000000000000000081565b60025481565b60007f00000000000000000000000000000000000000000000000000000000000000008073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146103cf576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016103c690611bea565b60405180910390fd5b60008060008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206040518060600160405290816000820154815260200160018201548152602001600282015481525050905060008060008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206040518060600160405290816000820154815260200160018201548152602001600282015481525050905084826000015110156104ec576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016104e390611c0a565b60405180910390fd5b60008060007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663bd6d894d6040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561055957600080fd5b505af115801561056d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105919190611a8f565b9050600160009054906101000a900460ff16156105ed576a52b7d2dcc80cd2e400000085604001516a52b7d2dcc80cd2e40000006002546105d29190611d7d565b6105dc9190611d4c565b6105e69190611dd7565b925061062c565b6a52b7d2dcc80cd2e400000085604001516a52b7d2dcc80cd2e4000000836106159190611d7d565b61061f9190611d4c565b6106299190611dd7565b92505b6a52b7d2dcc80cd2e40000008560000151846106489190611d7d565b6106529190611d4c565b915081856020018181516106669190611cf6565b91508181525050878560000181815161067f9190611dd7565b9150818152505080856040018181525050846000808c73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000820151816000015560208201518160010155604082015181600201559050506000846000015111156107f8576000600160009054906101000a900460ff1615610759576a52b7d2dcc80cd2e400000085604001516a52b7d2dcc80cd2e400000060025461073e9190611d7d565b6107489190611d4c565b6107529190611dd7565b9350610798565b6a52b7d2dcc80cd2e400000085604001516a52b7d2dcc80cd2e4000000846107819190611d7d565b61078b9190611d4c565b6107959190611dd7565b93505b6a52b7d2dcc80cd2e40000008560000151856107b49190611d7d565b6107be9190611d4c565b905080856020018181516107d29190611cf6565b9150818152505088856000018181516107eb9190611cf6565b9150818152505050610812565b878460000181815161080a9190611cf6565b915081815250505b80846040018181525050836000808b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082015181600001556020820151816001015560408201518160020155905050600196505050505050509392505050565b60007f00000000000000000000000000000000000000000000000000000000000000008073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461091e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161091590611bea565b60405180910390fd5b60008060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206040518060600160405290816000820154815260200160018201548152602001600282015481525050905060008160200151905060008060007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663bd6d894d6040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156109ff57600080fd5b505af1158015610a13573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a379190611a8f565b9050600160009054906101000a900460ff1615610a93576a52b7d2dcc80cd2e400000085604001516a52b7d2dcc80cd2e4000000600254610a789190611d7d565b610a829190611d4c565b610a8c9190611dd7565b9250610ad2565b6a52b7d2dcc80cd2e400000085604001516a52b7d2dcc80cd2e400000083610abb9190611d7d565b610ac59190611d4c565b610acf9190611dd7565b92505b6a52b7d2dcc80cd2e4000000856000015184610aee9190611d7d565b610af89190611d4c565b9150808560400181815250506000856020018181525050846000808a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000820151816000015560208201518160010155604082015181600201559050508184610b7b9190611cf6565b9650505050505050919050565b7f000000000000000000000000000000000000000000000000000000000000000081565b600160009054906101000a900460ff1681565b60007f00000000000000000000000000000000000000000000000000000000000000008073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610c50576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c4790611bea565b60405180910390fd5b60008060008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020604051806060016040529081600082015481526020016001820154815260200160028201548152505090508381600001511015610d02576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610cf990611c4a565b60405180910390fd5b60008060007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663bd6d894d6040518163ffffffff1660e01b8152600401602060405180830381600087803b158015610d6f57600080fd5b505af1158015610d83573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610da79190611a8f565b9050600160009054906101000a900460ff1615610e03576a52b7d2dcc80cd2e400000084604001516a52b7d2dcc80cd2e4000000600254610de89190611d7d565b610df29190611d4c565b610dfc9190611dd7565b9250610e42565b6a52b7d2dcc80cd2e400000084604001516a52b7d2dcc80cd2e400000083610e2b9190611d7d565b610e359190611d4c565b610e3f9190611dd7565b92505b6a52b7d2dcc80cd2e4000000846000015184610e5e9190611d7d565b610e689190611d4c565b91508184602001818151610e7c9190611cf6565b915081815250508684600001818151610e959190611dd7565b9150818152505080846040018181525050836000808a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008201518160000155602082015181600101556040820151816002015590505060019550505050505092915050565b6000806000808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600001546000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206001015491509150915091565b60007f00000000000000000000000000000000000000000000000000000000000000008073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611036576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161102d90611bea565b60405180910390fd5b600160009054906101000a900460ff1615611086576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161107d90611c2a565b60405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000004210156110e9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016110e090611bca565b60405180910390fd5b60018060006101000a81548160ff0219169083151502179055507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663bd6d894d6040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561116b57600080fd5b505af115801561117f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111a39190611a8f565b600281905550600191505090565b60007f00000000000000000000000000000000000000000000000000000000000000008073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611242576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161123990611bea565b60405180910390fd5b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663bd6d894d6040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156112ac57600080fd5b505af11580156112c0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112e49190611a8f565b905060008060008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206040518060600160405290816000820154815260200160018201548152602001600282015481525050905060008160000151111561145b57600080600160009054906101000a900460ff16156113bb576a52b7d2dcc80cd2e400000083604001516a52b7d2dcc80cd2e40000006002546113a09190611d7d565b6113aa9190611d4c565b6113b49190611dd7565b91506113fa565b6a52b7d2dcc80cd2e400000083604001516a52b7d2dcc80cd2e4000000866113e39190611d7d565b6113ed9190611d4c565b6113f79190611dd7565b91505b6a52b7d2dcc80cd2e40000008360000151836114169190611d7d565b6114209190611d4c565b905080836020018181516114349190611cf6565b91508181525050868360000181815161144d9190611cf6565b915081815250505050611466565b848160000181815250505b81816040018181525050806000808873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000820151816000015560208201518160010155604082015181600201559050506001935050505092915050565b60006020528060005260406000206000915090508060000154908060010154908060020154905083565b60007f00000000000000000000000000000000000000000000000000000000000000008073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611598576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161158f90611bea565b60405180910390fd5b60008060008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206040518060600160405290816000820154815260200160018201548152602001600282015481525050905060008060007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206040518060600160405290816000820154815260200160018201548152602001600282015481525050905084826000018181516116a09190611dd7565b9150818152505060007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663bd6d894d6040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561171157600080fd5b505af1158015611725573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117499190611a8f565b90506000808284604001511461184b57600084604001511461184057600160009054906101000a900460ff16156117bf576a52b7d2dcc80cd2e400000084604001516a52b7d2dcc80cd2e40000006002546117a49190611d7d565b6117ae9190611d4c565b6117b89190611dd7565b91506117fe565b6a52b7d2dcc80cd2e400000084604001516a52b7d2dcc80cd2e4000000856117e79190611d7d565b6117f19190611d4c565b6117fb9190611dd7565b91505b6a52b7d2dcc80cd2e400000084600001518361181a9190611d7d565b6118249190611d4c565b905080846020018181516118389190611cf6565b915081815250505b828460400181815250505b878460000181815161185d9190611cf6565b91508181525050836000807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082015181600001556020820151816001015560408201518160020155905050846000808b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000820151816000015560208201518160010155604082015181600201559050506001965050505050505092915050565b7f000000000000000000000000000000000000000000000000000000000000000081565b7f000000000000000000000000000000000000000000000000000000000000000081565b6000813590506119ab81611f7e565b92915050565b6000813590506119c081611f95565b92915050565b6000815190506119d581611f95565b92915050565b6000602082840312156119ed57600080fd5b60006119fb8482850161199c565b91505092915050565b600080600060608486031215611a1957600080fd5b6000611a278682870161199c565b9350506020611a388682870161199c565b9250506040611a49868287016119b1565b9150509250925092565b60008060408385031215611a6657600080fd5b6000611a748582860161199c565b9250506020611a85858286016119b1565b9150509250929050565b600060208284031215611aa157600080fd5b6000611aaf848285016119c6565b91505092915050565b611ac181611e0b565b82525050565b611ad081611e1d565b82525050565b6000611ae3601d83611ce5565b9150611aee82611eb1565b602082019050919050565b6000611b06601483611ce5565b9150611b1182611eda565b602082019050919050565b6000611b29602083611ce5565b9150611b3482611f03565b602082019050919050565b6000611b4c600f83611ce5565b9150611b5782611f2c565b602082019050919050565b6000611b6f601c83611ce5565b9150611b7a82611f55565b602082019050919050565b611b8e81611e49565b82525050565b6000602082019050611ba96000830184611ab8565b92915050565b6000602082019050611bc46000830184611ac7565b92915050565b60006020820190508181036000830152611be381611ad6565b9050919050565b60006020820190508181036000830152611c0381611af9565b9050919050565b60006020820190508181036000830152611c2381611b1c565b9050919050565b60006020820190508181036000830152611c4381611b3f565b9050919050565b60006020820190508181036000830152611c6381611b62565b9050919050565b6000602082019050611c7f6000830184611b85565b92915050565b6000604082019050611c9a6000830185611b85565b611ca76020830184611b85565b9392505050565b6000606082019050611cc36000830186611b85565b611cd06020830185611b85565b611cdd6040830184611b85565b949350505050565b600082825260208201905092915050565b6000611d0182611e49565b9150611d0c83611e49565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff03821115611d4157611d40611e53565b5b828201905092915050565b6000611d5782611e49565b9150611d6283611e49565b925082611d7257611d71611e82565b5b828204905092915050565b6000611d8882611e49565b9150611d9383611e49565b9250817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615611dcc57611dcb611e53565b5b828202905092915050565b6000611de282611e49565b9150611ded83611e49565b925082821015611e0057611dff611e53565b5b828203905092915050565b6000611e1682611e29565b9050919050565b60008115159050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b7f6d6174757269747920686173206e6f74206265656e2072656163686564000000600082015250565b7f73656e646572206d7573742062652061646d696e000000000000000000000000600082015250565b7f616d6f756e74206578636565647320617661696c61626c652062616c616e6365600082015250565b7f616c7265616479206d6174757265640000000000000000000000000000000000600082015250565b7f616d6f756e742065786365656473207661756c742062616c616e636500000000600082015250565b611f8781611e0b565b8114611f9257600080fd5b50565b611f9e81611e49565b8114611fa957600080fd5b5056fea2646970667358221220dfb3b8d5f3bf70e0febc8b8acff3431c07144d9e66667cf76c63daba9fc452f064736f6c63430008040033" + +// DeployVaultTracker deploys a new Ethereum contract, binding an instance of VaultTracker to it. +func DeployVaultTracker(auth *bind.TransactOpts, backend bind.ContractBackend, m *big.Int, c common.Address, s common.Address) (common.Address, *types.Transaction, *VaultTracker, error) { + parsed, err := abi.JSON(strings.NewReader(VaultTrackerABI)) + if err != nil { + return common.Address{}, nil, nil, err + } + + address, tx, contract, err := bind.DeployContract(auth, parsed, common.FromHex(VaultTrackerBin), backend, m, c, s) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &VaultTracker{VaultTrackerCaller: VaultTrackerCaller{contract: contract}, VaultTrackerTransactor: VaultTrackerTransactor{contract: contract}, VaultTrackerFilterer: VaultTrackerFilterer{contract: contract}}, nil +} + +// VaultTracker is an auto generated Go binding around an Ethereum contract. +type VaultTracker struct { + VaultTrackerCaller // Read-only binding to the contract + VaultTrackerTransactor // Write-only binding to the contract + VaultTrackerFilterer // Log filterer for contract events +} + +// VaultTrackerCaller is an auto generated read-only Go binding around an Ethereum contract. +type VaultTrackerCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// VaultTrackerTransactor is an auto generated write-only Go binding around an Ethereum contract. +type VaultTrackerTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// VaultTrackerFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type VaultTrackerFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// VaultTrackerSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type VaultTrackerSession struct { + Contract *VaultTracker // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// VaultTrackerCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type VaultTrackerCallerSession struct { + Contract *VaultTrackerCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// VaultTrackerTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type VaultTrackerTransactorSession struct { + Contract *VaultTrackerTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// VaultTrackerRaw is an auto generated low-level Go binding around an Ethereum contract. +type VaultTrackerRaw struct { + Contract *VaultTracker // Generic contract binding to access the raw methods on +} + +// VaultTrackerCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type VaultTrackerCallerRaw struct { + Contract *VaultTrackerCaller // Generic read-only contract binding to access the raw methods on +} + +// VaultTrackerTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type VaultTrackerTransactorRaw struct { + Contract *VaultTrackerTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewVaultTracker creates a new instance of VaultTracker, bound to a specific deployed contract. +func NewVaultTracker(address common.Address, backend bind.ContractBackend) (*VaultTracker, error) { + contract, err := bindVaultTracker(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &VaultTracker{VaultTrackerCaller: VaultTrackerCaller{contract: contract}, VaultTrackerTransactor: VaultTrackerTransactor{contract: contract}, VaultTrackerFilterer: VaultTrackerFilterer{contract: contract}}, nil +} + +// NewVaultTrackerCaller creates a new read-only instance of VaultTracker, bound to a specific deployed contract. +func NewVaultTrackerCaller(address common.Address, caller bind.ContractCaller) (*VaultTrackerCaller, error) { + contract, err := bindVaultTracker(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &VaultTrackerCaller{contract: contract}, nil +} + +// NewVaultTrackerTransactor creates a new write-only instance of VaultTracker, bound to a specific deployed contract. +func NewVaultTrackerTransactor(address common.Address, transactor bind.ContractTransactor) (*VaultTrackerTransactor, error) { + contract, err := bindVaultTracker(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &VaultTrackerTransactor{contract: contract}, nil +} + +// NewVaultTrackerFilterer creates a new log filterer instance of VaultTracker, bound to a specific deployed contract. +func NewVaultTrackerFilterer(address common.Address, filterer bind.ContractFilterer) (*VaultTrackerFilterer, error) { + contract, err := bindVaultTracker(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &VaultTrackerFilterer{contract: contract}, nil +} + +// bindVaultTracker binds a generic wrapper to an already deployed contract. +func bindVaultTracker(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := abi.JSON(strings.NewReader(VaultTrackerABI)) + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_VaultTracker *VaultTrackerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _VaultTracker.Contract.VaultTrackerCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_VaultTracker *VaultTrackerRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _VaultTracker.Contract.VaultTrackerTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_VaultTracker *VaultTrackerRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _VaultTracker.Contract.VaultTrackerTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_VaultTracker *VaultTrackerCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _VaultTracker.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_VaultTracker *VaultTrackerTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _VaultTracker.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_VaultTracker *VaultTrackerTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _VaultTracker.Contract.contract.Transact(opts, method, params...) +} + +// Admin is a free data retrieval call binding the contract method 0xf851a440. +// +// Solidity: function admin() view returns(address) +func (_VaultTracker *VaultTrackerCaller) Admin(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _VaultTracker.contract.Call(opts, &out, "admin") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// Admin is a free data retrieval call binding the contract method 0xf851a440. +// +// Solidity: function admin() view returns(address) +func (_VaultTracker *VaultTrackerSession) Admin() (common.Address, error) { + return _VaultTracker.Contract.Admin(&_VaultTracker.CallOpts) +} + +// Admin is a free data retrieval call binding the contract method 0xf851a440. +// +// Solidity: function admin() view returns(address) +func (_VaultTracker *VaultTrackerCallerSession) Admin() (common.Address, error) { + return _VaultTracker.Contract.Admin(&_VaultTracker.CallOpts) +} + +// BalancesOf is a free data retrieval call binding the contract method 0x6392a51f. +// +// Solidity: function balancesOf(address o) view returns(uint256, uint256) +func (_VaultTracker *VaultTrackerCaller) BalancesOf(opts *bind.CallOpts, o common.Address) (*big.Int, *big.Int, error) { + var out []interface{} + err := _VaultTracker.contract.Call(opts, &out, "balancesOf", o) + + if err != nil { + return *new(*big.Int), *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + out1 := *abi.ConvertType(out[1], new(*big.Int)).(**big.Int) + + return out0, out1, err + +} + +// BalancesOf is a free data retrieval call binding the contract method 0x6392a51f. +// +// Solidity: function balancesOf(address o) view returns(uint256, uint256) +func (_VaultTracker *VaultTrackerSession) BalancesOf(o common.Address) (*big.Int, *big.Int, error) { + return _VaultTracker.Contract.BalancesOf(&_VaultTracker.CallOpts, o) +} + +// BalancesOf is a free data retrieval call binding the contract method 0x6392a51f. +// +// Solidity: function balancesOf(address o) view returns(uint256, uint256) +func (_VaultTracker *VaultTrackerCallerSession) BalancesOf(o common.Address) (*big.Int, *big.Int, error) { + return _VaultTracker.Contract.BalancesOf(&_VaultTracker.CallOpts, o) +} + +// CTokenAddr is a free data retrieval call binding the contract method 0xb7dd3483. +// +// Solidity: function cTokenAddr() view returns(address) +func (_VaultTracker *VaultTrackerCaller) CTokenAddr(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _VaultTracker.contract.Call(opts, &out, "cTokenAddr") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// CTokenAddr is a free data retrieval call binding the contract method 0xb7dd3483. +// +// Solidity: function cTokenAddr() view returns(address) +func (_VaultTracker *VaultTrackerSession) CTokenAddr() (common.Address, error) { + return _VaultTracker.Contract.CTokenAddr(&_VaultTracker.CallOpts) +} + +// CTokenAddr is a free data retrieval call binding the contract method 0xb7dd3483. +// +// Solidity: function cTokenAddr() view returns(address) +func (_VaultTracker *VaultTrackerCallerSession) CTokenAddr() (common.Address, error) { + return _VaultTracker.Contract.CTokenAddr(&_VaultTracker.CallOpts) +} + +// Matured is a free data retrieval call binding the contract method 0x454c87b3. +// +// Solidity: function matured() view returns(bool) +func (_VaultTracker *VaultTrackerCaller) Matured(opts *bind.CallOpts) (bool, error) { + var out []interface{} + err := _VaultTracker.contract.Call(opts, &out, "matured") + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// Matured is a free data retrieval call binding the contract method 0x454c87b3. +// +// Solidity: function matured() view returns(bool) +func (_VaultTracker *VaultTrackerSession) Matured() (bool, error) { + return _VaultTracker.Contract.Matured(&_VaultTracker.CallOpts) +} + +// Matured is a free data retrieval call binding the contract method 0x454c87b3. +// +// Solidity: function matured() view returns(bool) +func (_VaultTracker *VaultTrackerCallerSession) Matured() (bool, error) { + return _VaultTracker.Contract.Matured(&_VaultTracker.CallOpts) +} + +// Maturity is a free data retrieval call binding the contract method 0x204f83f9. +// +// Solidity: function maturity() view returns(uint256) +func (_VaultTracker *VaultTrackerCaller) Maturity(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _VaultTracker.contract.Call(opts, &out, "maturity") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// Maturity is a free data retrieval call binding the contract method 0x204f83f9. +// +// Solidity: function maturity() view returns(uint256) +func (_VaultTracker *VaultTrackerSession) Maturity() (*big.Int, error) { + return _VaultTracker.Contract.Maturity(&_VaultTracker.CallOpts) +} + +// Maturity is a free data retrieval call binding the contract method 0x204f83f9. +// +// Solidity: function maturity() view returns(uint256) +func (_VaultTracker *VaultTrackerCallerSession) Maturity() (*big.Int, error) { + return _VaultTracker.Contract.Maturity(&_VaultTracker.CallOpts) +} + +// MaturityRate is a free data retrieval call binding the contract method 0x11554c43. +// +// Solidity: function maturityRate() view returns(uint256) +func (_VaultTracker *VaultTrackerCaller) MaturityRate(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _VaultTracker.contract.Call(opts, &out, "maturityRate") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// MaturityRate is a free data retrieval call binding the contract method 0x11554c43. +// +// Solidity: function maturityRate() view returns(uint256) +func (_VaultTracker *VaultTrackerSession) MaturityRate() (*big.Int, error) { + return _VaultTracker.Contract.MaturityRate(&_VaultTracker.CallOpts) +} + +// MaturityRate is a free data retrieval call binding the contract method 0x11554c43. +// +// Solidity: function maturityRate() view returns(uint256) +func (_VaultTracker *VaultTrackerCallerSession) MaturityRate() (*big.Int, error) { + return _VaultTracker.Contract.MaturityRate(&_VaultTracker.CallOpts) +} + +// Swivel is a free data retrieval call binding the contract method 0x012b264a. +// +// Solidity: function swivel() view returns(address) +func (_VaultTracker *VaultTrackerCaller) Swivel(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _VaultTracker.contract.Call(opts, &out, "swivel") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// Swivel is a free data retrieval call binding the contract method 0x012b264a. +// +// Solidity: function swivel() view returns(address) +func (_VaultTracker *VaultTrackerSession) Swivel() (common.Address, error) { + return _VaultTracker.Contract.Swivel(&_VaultTracker.CallOpts) +} + +// Swivel is a free data retrieval call binding the contract method 0x012b264a. +// +// Solidity: function swivel() view returns(address) +func (_VaultTracker *VaultTrackerCallerSession) Swivel() (common.Address, error) { + return _VaultTracker.Contract.Swivel(&_VaultTracker.CallOpts) +} + +// Vaults is a free data retrieval call binding the contract method 0xa622ee7c. +// +// Solidity: function vaults(address ) view returns(uint256 notional, uint256 redeemable, uint256 exchangeRate) +func (_VaultTracker *VaultTrackerCaller) Vaults(opts *bind.CallOpts, arg0 common.Address) (struct { + Notional *big.Int + Redeemable *big.Int + ExchangeRate *big.Int +}, error) { + var out []interface{} + err := _VaultTracker.contract.Call(opts, &out, "vaults", arg0) + + outstruct := new(struct { + Notional *big.Int + Redeemable *big.Int + ExchangeRate *big.Int + }) + if err != nil { + return *outstruct, err + } + + outstruct.Notional = out[0].(*big.Int) + outstruct.Redeemable = out[1].(*big.Int) + outstruct.ExchangeRate = out[2].(*big.Int) + + return *outstruct, err + +} + +// Vaults is a free data retrieval call binding the contract method 0xa622ee7c. +// +// Solidity: function vaults(address ) view returns(uint256 notional, uint256 redeemable, uint256 exchangeRate) +func (_VaultTracker *VaultTrackerSession) Vaults(arg0 common.Address) (struct { + Notional *big.Int + Redeemable *big.Int + ExchangeRate *big.Int +}, error) { + return _VaultTracker.Contract.Vaults(&_VaultTracker.CallOpts, arg0) +} + +// Vaults is a free data retrieval call binding the contract method 0xa622ee7c. +// +// Solidity: function vaults(address ) view returns(uint256 notional, uint256 redeemable, uint256 exchangeRate) +func (_VaultTracker *VaultTrackerCallerSession) Vaults(arg0 common.Address) (struct { + Notional *big.Int + Redeemable *big.Int + ExchangeRate *big.Int +}, error) { + return _VaultTracker.Contract.Vaults(&_VaultTracker.CallOpts, arg0) +} + +// AddNotional is a paid mutator transaction binding the contract method 0xa01cfffb. +// +// Solidity: function addNotional(address o, uint256 a) returns(bool) +func (_VaultTracker *VaultTrackerTransactor) AddNotional(opts *bind.TransactOpts, o common.Address, a *big.Int) (*types.Transaction, error) { + return _VaultTracker.contract.Transact(opts, "addNotional", o, a) +} + +// AddNotional is a paid mutator transaction binding the contract method 0xa01cfffb. +// +// Solidity: function addNotional(address o, uint256 a) returns(bool) +func (_VaultTracker *VaultTrackerSession) AddNotional(o common.Address, a *big.Int) (*types.Transaction, error) { + return _VaultTracker.Contract.AddNotional(&_VaultTracker.TransactOpts, o, a) +} + +// AddNotional is a paid mutator transaction binding the contract method 0xa01cfffb. +// +// Solidity: function addNotional(address o, uint256 a) returns(bool) +func (_VaultTracker *VaultTrackerTransactorSession) AddNotional(o common.Address, a *big.Int) (*types.Transaction, error) { + return _VaultTracker.Contract.AddNotional(&_VaultTracker.TransactOpts, o, a) +} + +// MatureVault is a paid mutator transaction binding the contract method 0x6b868d51. +// +// Solidity: function matureVault() returns(bool) +func (_VaultTracker *VaultTrackerTransactor) MatureVault(opts *bind.TransactOpts) (*types.Transaction, error) { + return _VaultTracker.contract.Transact(opts, "matureVault") +} + +// MatureVault is a paid mutator transaction binding the contract method 0x6b868d51. +// +// Solidity: function matureVault() returns(bool) +func (_VaultTracker *VaultTrackerSession) MatureVault() (*types.Transaction, error) { + return _VaultTracker.Contract.MatureVault(&_VaultTracker.TransactOpts) +} + +// MatureVault is a paid mutator transaction binding the contract method 0x6b868d51. +// +// Solidity: function matureVault() returns(bool) +func (_VaultTracker *VaultTrackerTransactorSession) MatureVault() (*types.Transaction, error) { + return _VaultTracker.Contract.MatureVault(&_VaultTracker.TransactOpts) +} + +// RedeemInterest is a paid mutator transaction binding the contract method 0x19caf46c. +// +// Solidity: function redeemInterest(address o) returns(uint256) +func (_VaultTracker *VaultTrackerTransactor) RedeemInterest(opts *bind.TransactOpts, o common.Address) (*types.Transaction, error) { + return _VaultTracker.contract.Transact(opts, "redeemInterest", o) +} + +// RedeemInterest is a paid mutator transaction binding the contract method 0x19caf46c. +// +// Solidity: function redeemInterest(address o) returns(uint256) +func (_VaultTracker *VaultTrackerSession) RedeemInterest(o common.Address) (*types.Transaction, error) { + return _VaultTracker.Contract.RedeemInterest(&_VaultTracker.TransactOpts, o) +} + +// RedeemInterest is a paid mutator transaction binding the contract method 0x19caf46c. +// +// Solidity: function redeemInterest(address o) returns(uint256) +func (_VaultTracker *VaultTrackerTransactorSession) RedeemInterest(o common.Address) (*types.Transaction, error) { + return _VaultTracker.Contract.RedeemInterest(&_VaultTracker.TransactOpts, o) +} + +// RemoveNotional is a paid mutator transaction binding the contract method 0x613a28d1. +// +// Solidity: function removeNotional(address o, uint256 a) returns(bool) +func (_VaultTracker *VaultTrackerTransactor) RemoveNotional(opts *bind.TransactOpts, o common.Address, a *big.Int) (*types.Transaction, error) { + return _VaultTracker.contract.Transact(opts, "removeNotional", o, a) +} + +// RemoveNotional is a paid mutator transaction binding the contract method 0x613a28d1. +// +// Solidity: function removeNotional(address o, uint256 a) returns(bool) +func (_VaultTracker *VaultTrackerSession) RemoveNotional(o common.Address, a *big.Int) (*types.Transaction, error) { + return _VaultTracker.Contract.RemoveNotional(&_VaultTracker.TransactOpts, o, a) +} + +// RemoveNotional is a paid mutator transaction binding the contract method 0x613a28d1. +// +// Solidity: function removeNotional(address o, uint256 a) returns(bool) +func (_VaultTracker *VaultTrackerTransactorSession) RemoveNotional(o common.Address, a *big.Int) (*types.Transaction, error) { + return _VaultTracker.Contract.RemoveNotional(&_VaultTracker.TransactOpts, o, a) +} + +// TransferNotionalFee is a paid mutator transaction binding the contract method 0xb326258d. +// +// Solidity: function transferNotionalFee(address f, uint256 a) returns(bool) +func (_VaultTracker *VaultTrackerTransactor) TransferNotionalFee(opts *bind.TransactOpts, f common.Address, a *big.Int) (*types.Transaction, error) { + return _VaultTracker.contract.Transact(opts, "transferNotionalFee", f, a) +} + +// TransferNotionalFee is a paid mutator transaction binding the contract method 0xb326258d. +// +// Solidity: function transferNotionalFee(address f, uint256 a) returns(bool) +func (_VaultTracker *VaultTrackerSession) TransferNotionalFee(f common.Address, a *big.Int) (*types.Transaction, error) { + return _VaultTracker.Contract.TransferNotionalFee(&_VaultTracker.TransactOpts, f, a) +} + +// TransferNotionalFee is a paid mutator transaction binding the contract method 0xb326258d. +// +// Solidity: function transferNotionalFee(address f, uint256 a) returns(bool) +func (_VaultTracker *VaultTrackerTransactorSession) TransferNotionalFee(f common.Address, a *big.Int) (*types.Transaction, error) { + return _VaultTracker.Contract.TransferNotionalFee(&_VaultTracker.TransactOpts, f, a) +} + +// TransferNotionalFrom is a paid mutator transaction binding the contract method 0x17794673. +// +// Solidity: function transferNotionalFrom(address f, address t, uint256 a) returns(bool) +func (_VaultTracker *VaultTrackerTransactor) TransferNotionalFrom(opts *bind.TransactOpts, f common.Address, t common.Address, a *big.Int) (*types.Transaction, error) { + return _VaultTracker.contract.Transact(opts, "transferNotionalFrom", f, t, a) +} + +// TransferNotionalFrom is a paid mutator transaction binding the contract method 0x17794673. +// +// Solidity: function transferNotionalFrom(address f, address t, uint256 a) returns(bool) +func (_VaultTracker *VaultTrackerSession) TransferNotionalFrom(f common.Address, t common.Address, a *big.Int) (*types.Transaction, error) { + return _VaultTracker.Contract.TransferNotionalFrom(&_VaultTracker.TransactOpts, f, t, a) +} + +// TransferNotionalFrom is a paid mutator transaction binding the contract method 0x17794673. +// +// Solidity: function transferNotionalFrom(address f, address t, uint256 a) returns(bool) +func (_VaultTracker *VaultTrackerTransactorSession) TransferNotionalFrom(f common.Address, t common.Address, a *big.Int) (*types.Transaction, error) { + return _VaultTracker.Contract.TransferNotionalFrom(&_VaultTracker.TransactOpts, f, t, a) +}