diff --git a/.github/workflows/eth-test.yml b/.github/workflows/eth-test.yml index 23b904a8..ee695f39 100644 --- a/.github/workflows/eth-test.yml +++ b/.github/workflows/eth-test.yml @@ -4,6 +4,7 @@ on: push: branches: - main + - develop pull_request: types: [opened, synchronize, reopened] diff --git a/.github/workflows/integration-test.yml b/.github/workflows/integration-test.yml index 849d839f..f278142d 100644 --- a/.github/workflows/integration-test.yml +++ b/.github/workflows/integration-test.yml @@ -3,6 +3,7 @@ on: push: branches: - main + - develop pull_request: types: [opened, synchronize, reopened] workflow_dispatch: @@ -149,7 +150,7 @@ jobs: run: | make starknet-build - # Deploy PaymentRegistry, Escrow, set escrow, set claimPayment selector and test complete flow + # Deploy PaymentRegistry, Escrow, set escrow, and test complete flow - name: Deploy and test complete flow run: | export ETHEREUM_RPC=${{vars.ETHEREUM_RPC}} @@ -158,15 +159,20 @@ jobs: export STARKNET_MESSAGING_ADDRESS=${{vars.STARKNET_MESSAGING_ADDRESS}} export MM_ETHEREUM_WALLET_ADDRESS=${{vars.MM_ETHEREUM_WALLET_ADDRESS}} export ZKSYNC_DIAMOND_PROXY_ADDRESS=${{vars.ZKSYNC_DIAMOND_PROXY_ADDRESS}} + export STARKNET_CHAIN_ID=${{vars.STARKNET_CHAIN_ID}} + export ZKSYNC_CHAIN_ID=${{vars.ZKSYNC_CHAIN_ID}} + export STARKNET_CLAIM_PAYMENT_SELECTOR=${{vars.STARKNET_CLAIM_PAYMENT_SELECTOR}} + export STARKNET_CLAIM_PAYMENT_BATCH_SELECTOR=${{vars.STARKNET_CLAIM_PAYMENT_BATCH_SELECTOR}} + export ZKSYNC_CLAIM_PAYMENT_SELECTOR=${{vars.ZKSYNC_CLAIM_PAYMENT_SELECTOR}} + export ZKSYNC_CLAIM_PAYMENT_BATCH_SELECTOR=${{vars.ZKSYNC_CLAIM_PAYMENT_BATCH_SELECTOR}} export SKIP_VERIFY=true . ./contracts/ethereum/deploy.sh export STARKNET_RPC=${{vars.STARKNET_RPC}} source ./contracts/starknet/.env.test - . ./contracts/starknet/deploy.sh + . ./contracts/starknet/scripts/deploy.sh . ./contracts/ethereum/set_starknet_escrow.sh - . ./contracts/ethereum/set_starknet_claim_payment_selector.sh export AMOUNT=1000000000000000000 . ./.github/workflows/scripts/set_order.sh diff --git a/.github/workflows/katana/katana.env b/.github/workflows/katana/katana.env index 45876495..11bce30c 100644 --- a/.github/workflows/katana/katana.env +++ b/.github/workflows/katana/katana.env @@ -3,4 +3,4 @@ ACCOUNT_ADDRESS=0x517ececd29116499f4a1b64b094da79ba08dfd54a3edaa316134c41f8160973 ACCOUNT_PRIVATE_KEY=0x1800000000300000180000000000030000000000003006001800006600 ACCOUNT_SRC=/home/runner/.config/.starkli/account_katana.json -RPC_URL=http://0.0.0.0:5050 \ No newline at end of file +RPC_URL=http://0.0.0.0:5050 diff --git a/.github/workflows/scripts/claim_payment.sh b/.github/workflows/scripts/claim_payment.sh index ef69b779..bf66cf07 100755 --- a/.github/workflows/scripts/claim_payment.sh +++ b/.github/workflows/scripts/claim_payment.sh @@ -4,7 +4,7 @@ DESTINATION_ADDRESS=0x70997970C51812dc3A010C7d01b50e0d17dc79C8 -echo -e "${GREEN}\n=> [SN] Making ClaimPayment${COLOR_RESET}" # 0x70997970C51812dc3A010C7d01b50e0d17dc79C8 -> 642829559307850963015472508762062935916233390536 +echo -e "${GREEN}\n=> [SN] Making ClaimPaymentStarknet${COLOR_RESET}" # 0x70997970C51812dc3A010C7d01b50e0d17dc79C8 -> 642829559307850963015472508762062935916233390536 ESCROW_INITIAL_BALANCE=$(starkli balance $ESCROW_CONTRACT_ADDRESS) MM_INITIAL_BALANCE=$(starkli balance $MM_STARKNET_WALLET_ADDRESS) @@ -13,7 +13,7 @@ echo "Initial MM balance: $MM_INITIAL_BALANCE" echo "Withdrawing $AMOUNT" cast send --rpc-url $ETHEREUM_RPC --private-key $ETHEREUM_PRIVATE_KEY \ - $PAYMENT_REGISTRY_PROXY_ADDRESS "claimPayment(uint256, uint256, uint256)" \ + $PAYMENT_REGISTRY_PROXY_ADDRESS "claimPaymentStarknet(uint256, address, uint256)" \ "0" $DESTINATION_ADDRESS "$AMOUNT" \ --value $AMOUNT >> /dev/null diff --git a/.github/workflows/scripts/transfer.sh b/.github/workflows/scripts/transfer.sh index 72276148..82412d2e 100755 --- a/.github/workflows/scripts/transfer.sh +++ b/.github/workflows/scripts/transfer.sh @@ -3,7 +3,6 @@ . contracts/utils/colors.sh #for ANSI colors DESTINATION_ADDRESS=0x70997970C51812dc3A010C7d01b50e0d17dc79C8 -STARKNET_CHAIN_ID="0" echo -e "${GREEN}\n=> [SN] Making transfer to Destination account${COLOR_RESET}" # 0x70997970C51812dc3A010C7d01b50e0d17dc79C8 -> 642829559307850963015472508762062935916233390536 @@ -14,7 +13,7 @@ echo "Initial Destination balance: $DESTINATION_INITIAL_BALANCE" echo "Transferring $AMOUNT to $DESTINATION_ADDRESS" cast send --rpc-url $ETHEREUM_RPC --private-key $ETHEREUM_PRIVATE_KEY \ - $PAYMENT_REGISTRY_PROXY_ADDRESS "transfer(uint256, uint256, uint8)" \ + $PAYMENT_REGISTRY_PROXY_ADDRESS "transfer(uint256, address, uint128)" \ "0" $DESTINATION_ADDRESS $STARKNET_CHAIN_ID \ --value $AMOUNT >> /dev/null diff --git a/.github/workflows/sn-test.yml b/.github/workflows/sn-test.yml index 2d153ba1..61bb11de 100644 --- a/.github/workflows/sn-test.yml +++ b/.github/workflows/sn-test.yml @@ -4,6 +4,7 @@ on: push: branches: - main + - develop pull_request: types: [opened, synchronize, reopened] diff --git a/.github/workflows/zksync-integration-test.yml b/.github/workflows/zksync-integration-test.yml new file mode 100644 index 00000000..7f82456d --- /dev/null +++ b/.github/workflows/zksync-integration-test.yml @@ -0,0 +1,97 @@ +name: ZKSync Integration Test +on: + push: + branches: + - main + - develop + pull_request: + types: [opened, synchronize, reopened] + workflow_dispatch: + +defaults: + run: + shell: bash + +jobs: + Test: + runs-on: ubuntu-latest + environment: Test + + steps: + - uses: actions/checkout@v4 + + # Run Dockerized L1-L2, goes first because it takes a lot of time + - name: Setup Dockerized L1-L2 + run: | + export ETHERSCAN_API_KEY=${{vars.ETHERSCAN_API_KEY}} + git clone https://github.com/uri-99/zksync-local-setup.git + + echo git cloned + cd zksync-local-setup + + echo starting Dockerized L1-L2 + touch ../docker_output.log + ./start.sh &> ../docker_output.log & + + # Ethereum Setup + - name: Install Foundry + uses: foundry-rs/foundry-toolchain@v1 + + - name: Install Forge + run: | + cd contracts/ethereum + forge install + + # ZKSync Setup + - name: Install ZKSync libraries + run: | + cd ./contracts/zksync/ && yarn install + + - name: Setup Node + uses: actions/setup-node@v2 + with: + node-version: '20.11.1' + cache: 'npm' + cache-dependency-path: '**/.github/workflows/*.yml' + + - name: Download zksync-cli + run: | + npx zksync-cli --version + + # Build Ethereum Contract + - name: Build Ethereum Contract + run: | + make ethereum-build + + # Build ZKSync Contract + - name: Build ZKSync Contract + run: | + make zksync-build + + # Run Dockerized L1-L2 + - name: Running integration test + run: | + export ETHERSCAN_API_KEY=${{vars.ETHERSCAN_API_KEY}} + + export STARKNET_MESSAGING_ADDRESS=${{vars.STARKNET_MESSAGING_ADDRESS}} + export STARKNET_CLAIM_PAYMENT_SELECTOR=${{vars.STARKNET_CLAIM_PAYMENT_SELECTOR}} + export STARKNET_CLAIM_PAYMENT_BATCH_SELECTOR=${{vars.STARKNET_CLAIM_PAYMENT_BATCH_SELECTOR}} + export ZKSYNC_CLAIM_PAYMENT_SELECTOR=${{vars.ZKSYNC_CLAIM_PAYMENT_SELECTOR}} + export ZKSYNC_CLAIM_PAYMENT_BATCH_SELECTOR=${{vars.ZKSYNC_CLAIM_PAYMENT_BATCH_SELECTOR}} + export STARKNET_CHAIN_ID=${{vars.STARKNET_CHAIN_ID}} + export ZKSYNC_CHAIN_ID=${{vars.ZKSYNC_CHAIN_ID}} + + export MM_ETHEREUM_WALLET_ADDRESS=${{vars.MM_ETHEREUM_WALLET_ADDRESS}} + export TEST=true + + echo sleeping 250 to wait for ./start to setup + sleep 250 + + export ZKSYNC_DIAMOND_PROXY_ADDRESS=$(cat docker_output.log | sed -n 's/.*CONTRACTS_DIAMOND_PROXY_ADDR=\(0x[a-fA-F0-9]*\).*/\1/p') + echo stored ZKSYNC_DIAMOND_PROXY_ADDRESS variable: + echo $ZKSYNC_DIAMOND_PROXY_ADDRESS + + echo running make-test-integration-ci + make zksync-test-integration-ci + + exit 0 diff --git a/.github/workflows/zksync-scripts/assert.sh b/.github/workflows/zksync-scripts/assert.sh new file mode 100755 index 00000000..464e4b3d --- /dev/null +++ b/.github/workflows/zksync-scripts/assert.sh @@ -0,0 +1,29 @@ +#!/bin/bash + +. contracts/utils/colors.sh #for ANSI colors + +echo "\n" +FAILED=false + +assert() { + #Usage: assert + if [ $2 = $3 ] ; then + printf "${GREEN}✓ $1 passed.${RESET}\n" + else + printf "${RED}x $1 assertion failed: Obtained value: $2, Expected value: $3.${RESET}\n" + FAILED=true + fi +} + +assert "Escrow balance after SetOrder" $BALANCE_ESCROW_L2_AFTER_SETORDER_WEI $VALUE_WEI #2000000000000000000 +assert "Escrow balance after Claim Payment" $BALANCE_ESCROW_L2_AFTER_CLAIMPAYMENT_WEI 0 + +assert "User balance" $BALANCE_USER_L1_AFTER_TRANSFER_WEI $BRIDGE_AMOUNT_WEI #1990000000000000000 + +assert "MM balance" $(($BALANCE_MM_L2_AFTER_CLAIMPAYMENT_WEI)) $(($BALANCE_MM_L2_BEFORE_CLAIMPAYMENT_WEI + $VALUE_WEI)) + +if $FAILED; then + echo "One of the previous tests failed, all should pass for Integration Test to be successful" + exit 1 +fi +exit 0 diff --git a/.github/workflows/zksync-scripts/ci.env.test b/.github/workflows/zksync-scripts/ci.env.test new file mode 100644 index 00000000..bbfeedc4 --- /dev/null +++ b/.github/workflows/zksync-scripts/ci.env.test @@ -0,0 +1,36 @@ +## ETH.env +SKIP_VERIFY=true #cant verify on local devnet + +ETHEREUM_RPC=http://localhost:8545 #local devnet L1 rpc url + +ETHEREUM_PRIVATE_KEY=0x7726827caac94a7f9e1b160f7ea819f172f7b6f9d2a97f992c38edeab82d4110 #prefunded 0 + +MM_ETHEREUM_PRIVATE_KEY=0xd293c684d884d56f8d6abd64fc76757d3664904e309a0645baf8522ab6366d9e #prefunded 2 +MM_ETHEREUM_WALLET_ADDRESS=0x0D43eB5B8a47bA8900d84AA36656c92024e9772e #prefunded 2 + +USER_ETHEREUM_PUBLIC_ADDRESS=0xCEEe57f2B700c2f37D1476A7974965E149Fce2D4 #random address with no funds + +ZKSYNC_CLAIM_PAYMENT_SELECTOR=0xa5168739 +ZKSYNC_CLAIM_PAYMENT_BATCH_SELECTOR=0x156be1ae +ZKSYNC_CHAIN_ID=300 + + +# These SN variables don't affect this test, but are necessary for deploy +STARKNET_CLAIM_PAYMENT_SELECTOR=0x03636c566f6409560d55d5f6d1eb4ee163b096b4698c503e69e210be79de2afa +STARKNET_CLAIM_PAYMENT_BATCH_SELECTOR=0x0354a01e49fe07e43306a97ed84dbd5de8238c7d8ff616caa3444630cfc559e6 +STARKNET_MESSAGING_ADDRESS=0xE2Bb56ee936fd6433DC0F6e7e3b8365C906AA057 +STARKNET_CHAIN_ID=0x534e5f5345504f4c4941 + + +## ZKSYNC.env +TEST=true + +WALLET_PRIVATE_KEY=0x7726827caac94a7f9e1b160f7ea819f172f7b6f9d2a97f992c38edeab82d4110 #prefunded 0 +MM_ZKSYNC_WALLET=0xbE85c9531BE760B6964cdA4A8826b9Cb0391E32C #random address with no funds + +NATIVE_TOKEN_ETH_IN_ZKSYNC=0x000000000000000000000000000000000000800A + +USER_ZKSYNC_PRIVATE_ADDRESS=0xf12e28c0eb1ef4ff90478f6805b68d63737b7f33abfa091601140805da450d93 #prefunded 4 +USER_ZKSYNC_PUBLIC_ADDRESS=0x8002cD98Cfb563492A6fB3E7C8243b7B9Ad4cc92 #prefunded 4 + + diff --git a/.github/workflows/zksync-scripts/claim_payment.sh b/.github/workflows/zksync-scripts/claim_payment.sh new file mode 100755 index 00000000..696a916a --- /dev/null +++ b/.github/workflows/zksync-scripts/claim_payment.sh @@ -0,0 +1,26 @@ +#!/bin/bash + +. contracts/utils/colors.sh #for ANSI colors + +printf "${GREEN}\n=> [ETH] Making Claim Payment${COLOR_RESET}\n" + +BALANCE_ESCROW_L2_BEFORE_CLAIMPAYMENT=$(cast balance --rpc-url http://localhost:3050 $ZKSYNC_ESCROW_CONTRACT_ADDRESS) +echo "Initial Escrow balance: $BALANCE_ESCROW_L2_BEFORE_CLAIMPAYMENT" + +BALANCE_MM_L2_BEFORE_CLAIMPAYMENT_WEI=$(cast balance --rpc-url http://localhost:3050 $MM_ZKSYNC_WALLET) #for assert.sh +BALANCE_MM_L2_BEFORE_CLAIMPAYMENT=$(cast balance --rpc-url http://localhost:3050 --ether $MM_ZKSYNC_WALLET) #for logging +echo "Initial MM balance: $BALANCE_MM_L2_BEFORE_CLAIMPAYMENT" + +echo "Withdrawing $BRIDGE_AMOUNT_ETH ETH" # == $BRIDGE_AMOUNT_WEI WEI" +cast send --rpc-url $ETHEREUM_RPC --private-key $ETHEREUM_PRIVATE_KEY --gas-price 2000000000 \ + $PAYMENT_REGISTRY_PROXY_ADDRESS "claimPaymentZKSync(uint256, address, uint256, uint256, uint256)" \ + "0" $USER_ETHEREUM_PUBLIC_ADDRESS $BRIDGE_AMOUNT_WEI 2000000 800 \ + --value 5000000000000000000 > /dev/null + +BALANCE_ESCROW_L2_AFTER_CLAIMPAYMENT_WEI=$(cast balance --rpc-url http://localhost:3050 $ZKSYNC_ESCROW_CONTRACT_ADDRESS) #for assert.sh +BALANCE_ESCROW_L2_AFTER_CLAIMPAYMENT=$(cast balance --rpc-url http://localhost:3050 --ether $ZKSYNC_ESCROW_CONTRACT_ADDRESS) #for logging +echo "Final Escrow balance: $BALANCE_ESCROW_L2_AFTER_CLAIMPAYMENT" + +BALANCE_MM_L2_AFTER_CLAIMPAYMENT_WEI=$(cast balance --rpc-url http://localhost:3050 $MM_ZKSYNC_WALLET) #for assert.sh +BALANCE_MM_L2_AFTER_CLAIMPAYMENT=$(cast balance --rpc-url http://localhost:3050 --ether $MM_ZKSYNC_WALLET) #for logging +echo "Final MM balance:$BALANCE_MM_L2_AFTER_CLAIMPAYMENT" diff --git a/.github/workflows/zksync-scripts/set_order.sh b/.github/workflows/zksync-scripts/set_order.sh new file mode 100755 index 00000000..436bfa6c --- /dev/null +++ b/.github/workflows/zksync-scripts/set_order.sh @@ -0,0 +1,33 @@ +#!/bin/bash + +. contracts/utils/colors.sh #for ANSI colors + +FEE=10000000000000000 #in WEI +VALUE=2 #in ETH +VALUE_WEI=$(echo "scale=0; $VALUE * 10^18" | bc) +BRIDGE_AMOUNT_WEI=$(echo "scale=0; $VALUE_WEI - $FEE" | bc) +BRIDGE_AMOUNT_ETH=$(echo "scale=18; $BRIDGE_AMOUNT_WEI / 10^18" | bc) + +echo USER_ZKSYNC_PUBLIC_ADDRESS +echo $USER_ZKSYNC_PUBLIC_ADDRESS +echo ZKSYNC_ESCROW_CONTRACT_ADDRESS +echo $ZKSYNC_ESCROW_CONTRACT_ADDRESS + +printf "${GREEN}\n=> [SN] Making Set Order on Escrow${COLOR_RESET}\n" +echo "$ZKSYNC_ESCROW_CONTRACT_ADDRESS\n" + +BALANCE_USER_L2_BEFORE_SETORDER=$(cast balance --rpc-url http://localhost:3050 $USER_ZKSYNC_PUBLIC_ADDRESS) +echo "Initial User funds: $BALANCE_USER_L2_BEFORE_SETORDER" + +BALANCE_ESCROW_L2_BEFORE_SETORDER=$(cast balance --rpc-url http://localhost:3050 $ZKSYNC_ESCROW_CONTRACT_ADDRESS) +echo "Initial Escrow funds: $BALANCE_ESCROW_L2_BEFORE_SETORDER" + +npx zksync-cli contract write --private-key $USER_ZKSYNC_PRIVATE_ADDRESS --rpc http://localhost:3050 --contract "$ZKSYNC_ESCROW_CONTRACT_ADDRESS" --method "set_order(address recipient_address, uint256 fee)" --args "$USER_ETHEREUM_PUBLIC_ADDRESS" "$FEE" --value "$VALUE" >> /dev/null + +BALANCE_USER_L2_AFTER_SETORDER=$(cast balance --rpc-url http://localhost:3050 $USER_ZKSYNC_PUBLIC_ADDRESS) +echo "Final User funds: $BALANCE_USER_L2_AFTER_SETORDER" + + +BALANCE_ESCROW_L2_AFTER_SETORDER_WEI=$(cast balance --rpc-url http://localhost:3050 $ZKSYNC_ESCROW_CONTRACT_ADDRESS) #for assert.sh +BALANCE_ESCROW_L2_AFTER_SETORDER=$(cast balance --rpc-url http://localhost:3050 $ZKSYNC_ESCROW_CONTRACT_ADDRESS) #for logging +echo "Final Escrow funds:$BALANCE_ESCROW_L2_AFTER_SETORDER" diff --git a/.github/workflows/zksync-scripts/transfer.sh b/.github/workflows/zksync-scripts/transfer.sh new file mode 100755 index 00000000..102389de --- /dev/null +++ b/.github/workflows/zksync-scripts/transfer.sh @@ -0,0 +1,24 @@ +#!/bin/bash + +. contracts/utils/colors.sh #for ANSI colors + +printf "${GREEN}\n=> [ETH] Making transfer to Destination account${COLOR_RESET}\n" + +BALANCE_MM_L1_BEFORE_TRANSFER=$(cast balance --rpc-url $ETHEREUM_RPC $MM_ETHEREUM_WALLET_ADDRESS) +echo "Initial MM Balance: $BALANCE_MM_L1_BEFORE_TRANSFER" + +BALANCE_USER_L1_BEFORE_TRANSFER=$(cast balance --rpc-url $ETHEREUM_RPC $USER_ETHEREUM_PUBLIC_ADDRESS) +echo "Initial User Balance: $BALANCE_USER_L1_BEFORE_TRANSFER" + +echo "Transferring $BRIDGE_AMOUNT_ETH ETH to $USER_ETHEREUM_PUBLIC_ADDRESS" +cast send --rpc-url $ETHEREUM_RPC --private-key $MM_ETHEREUM_PRIVATE_KEY --gas-price 2000000000 \ + $PAYMENT_REGISTRY_PROXY_ADDRESS "transfer(uint256, address, uint128)" \ + "0" $USER_ETHEREUM_PUBLIC_ADDRESS $ZKSYNC_CHAIN_ID \ + --value $BRIDGE_AMOUNT_WEI >> /dev/null + +BALANCE_MM_L1_AFTER_TRANSFER=$(cast balance --rpc-url $ETHEREUM_RPC $MM_ETHEREUM_WALLET_ADDRESS) +echo "Final MM Balance: $BALANCE_MM_L1_AFTER_TRANSFER" + +BALANCE_USER_L1_AFTER_TRANSFER_WEI=$(cast balance --rpc-url $ETHEREUM_RPC $USER_ETHEREUM_PUBLIC_ADDRESS) #for assert.sh +BALANCE_USER_L1_AFTER_TRANSFER=$(cast balance --rpc-url $ETHEREUM_RPC --ether $USER_ETHEREUM_PUBLIC_ADDRESS) #for logging +echo "Final User Balance: $BALANCE_USER_L1_AFTER_TRANSFER" diff --git a/.github/workflows/zksync-test.yml b/.github/workflows/zksync-test.yml new file mode 100644 index 00000000..74abaca1 --- /dev/null +++ b/.github/workflows/zksync-test.yml @@ -0,0 +1,46 @@ +name: ZKSync Escrow Tests + +on: + push: + branches: + - main + - develop + pull_request: + types: [opened, synchronize, reopened] + +jobs: + test-ZKSync: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + # ZKSync Setup + - name: Install ZKSync libraries + run: | + cd ./contracts/zksync/ && yarn install + + - name: Setup Node + uses: actions/setup-node@v2 + with: + node-version: '20.11.1' + cache: 'npm' + cache-dependency-path: '**/.github/workflows/*.yml' + + - name: Download zksync-cli + run: | + npx zksync-cli --version + + # Build ZKSync Contract + - name: Build ZKSync Contract + run: | + make zksync-build + + - name: Run make zksync-test + run: | + echo "Starting ZKSync in-memory node" + npx zksync-cli dev start + echo sleeping 30 for in-memory-node setup + sleep 30 + make zksync-test-in-memory + + exit 0 diff --git a/Makefile b/Makefile index c05fbdea..432e7920 100644 --- a/Makefile +++ b/Makefile @@ -42,9 +42,6 @@ ethereum-upgrade: ethereum-build ethereum-set-escrow: @. ./contracts/ethereum/.env && . ./contracts/ethereum/set_starknet_escrow.sh -ethereum-set-claim-payment-selector: - @. ./contracts/ethereum/.env && . ./contracts/starknet/.env && . ./contracts/ethereum/set_starknet_claim_payment_selector.sh - ### STARKNET ### @@ -58,22 +55,25 @@ starknet-test: starknet-clean @cd ./contracts/starknet/ && snforge test starknet-deploy: starknet-build - @. ./contracts/starknet/.env && . ./contracts/starknet/deploy.sh + @. ./contracts/starknet/.env && . ./contracts/starknet/scripts/deploy.sh + +starknet-connect: + @. ./contracts/ethereum/.env && . ./contracts/starknet/.env && \ + . ./contracts/ethereum/set_starknet_escrow.sh starknet-deploy-and-connect: starknet-build @. ./contracts/ethereum/.env && . ./contracts/starknet/.env && \ - . ./contracts/starknet/deploy.sh && \ - . ./contracts/ethereum/set_starknet_escrow.sh && \ - . ./contracts/ethereum/set_starknet_claim_payment_selector.sh + . ./contracts/starknet/scripts/deploy.sh && \ + . ./contracts/ethereum/set_starknet_escrow.sh starknet-upgrade: starknet-build - @. ./contracts/starknet/.env && . ./contracts/starknet/upgrade.sh + @. ./contracts/starknet/.env && . ./contracts/starknet/scripts/upgrade.sh starknet-pause: - @. ./contracts/starknet/.env && ./contracts/starknet/change_pause_state.sh pause + @. ./contracts/starknet/.env && . ./contracts/starknet/scripts/change_pause_state.sh pause starknet-unpause: - @. ./contracts/starknet/.env && ./contracts/starknet/change_pause_state.sh unpause + @. ./contracts/starknet/.env && . ./contracts/starknet/scripts/change_pause_state.sh unpause ### ZKSYNC ### @@ -96,20 +96,32 @@ zksync-deploy-and-connect: zksync-build . ./contracts/zksync/deploy.sh && \ . ./contracts/ethereum/set_zksync_escrow.sh - zksync-test: zksync-build @cd ./contracts/zksync/ && yarn test -#wip: -zksync-test-integration: +zksync-test-in-memory: zksync-build + @cd ./contracts/zksync/ && yarn test-in-memory + +zksync-test-integration-ci: + @. ./.github/workflows/zksync-scripts/ci.env.test && \ + . ./contracts/ethereum/deploy.sh && \ + . ./contracts/zksync/deploy.sh && \ + . ./contracts/ethereum/set_zksync_escrow.sh && \ + . ./.github/workflows/zksync-scripts/set_order.sh && \ + . ./.github/workflows/zksync-scripts/transfer.sh && \ + . ./.github/workflows/zksync-scripts/claim_payment.sh && \ + . ./.github/workflows/zksync-scripts/assert.sh + +zksync-test-integration-local: @make ethereum-build && make zksync-build && \ . ./contracts/ethereum/test/.env.test && . ./contracts/zksync/test/.env.test && \ . ./contracts/ethereum/deploy.sh && \ . ./contracts/zksync/deploy.sh && \ . ./contracts/ethereum/set_zksync_escrow.sh && \ - . ./contracts/zksync/test/set_order.sh && \ - . ./contracts/zksync/test/transfer.sh && \ - . ./contracts/zksync/test/claim_payment.sh + . ./.github/workflows/zksync-scripts/set_order.sh && \ + . ./.github/workflows/zksync-scripts/transfer.sh && \ + . ./.github/workflows/zksync-scripts/claim_payment.sh && \ + . ./.github/workflows/zksync-scripts/assert.sh # zksync-upgrade: WIP @@ -132,9 +144,8 @@ ethereum-and-starknet-deploy: make ethereum-build && \ make starknet-build && \ . ./contracts/ethereum/deploy.sh && \ - . ./contracts/starknet/deploy.sh && \ + . ./contracts/starknet/scripts/deploy.sh && \ . ./contracts/ethereum/set_starknet_escrow.sh && \ - . ./contracts/ethereum/set_starknet_claim_payment_selector.sh && \ . ./contracts/utils/display_info.sh deploy-all: @@ -142,9 +153,8 @@ deploy-all: make ethereum-build && \ . ./contracts/ethereum/deploy.sh && \ make starknet-build && \ - . ./contracts/starknet/deploy.sh && \ + . ./contracts/starknet/scripts/deploy.sh && \ . ./contracts/ethereum/set_starknet_escrow.sh && \ - . ./contracts/ethereum/set_starknet_claim_payment_selector.sh && \ . ./contracts/utils/display_info.sh && \ make zksync-build && \ . ./contracts/zksync/deploy.sh && \ diff --git a/contracts/ethereum/.env.example b/contracts/ethereum/.env.example index 8ff777c0..fb4e644c 100644 --- a/contracts/ethereum/.env.example +++ b/contracts/ethereum/.env.example @@ -7,3 +7,11 @@ STARKNET_MESSAGING_ADDRESS=<0xde29d060D45901Fb19ED6C6e959EB22d8626708e|0xE2Bb56e MM_ETHEREUM_WALLET_ADDRESS= #in hexa with the 0x prefix ZKSYNC_DIAMOND_PROXY_ADDRESS=<0x9A6DE0f62Aa270A8bCB1e2610078650D539B1Ef9> # Sepolia + +STARKNET_CLAIM_PAYMENT_SELECTOR=<0x03636c566f6409560d55d5f6d1eb4ee163b096b4698c503e69e210be79de2afa> #hex value of starknet's claim_payment selector +STARKNET_CLAIM_PAYMENT_BATCH_SELECTOR=<0x0354a01e49fe07e43306a97ed84dbd5de8238c7d8ff616caa3444630cfc559e6> #hex value of starknet's claim_payment_batch selector +ZKSYNC_CLAIM_PAYMENT_SELECTOR=<0xa5168739> #hex value of ZKSync's claim_payment selctor +ZKSYNC_CLAIM_PAYMENT_BATCH_SELECTOR=<0x156be1ae> #hex value of ZKSync's claim_payment_batch selctor + +STARKNET_CHAIN_ID=<0x534e5f5345504f4c4941|0x534e5f4d41494e> #Sepolia | Mainnet +ZKSYNC_CHAIN_ID=<300|324> # Sepolia | Mainnet diff --git a/contracts/ethereum/.env.test b/contracts/ethereum/.env.test index a2b5647e..42e5dd41 100644 --- a/contracts/ethereum/.env.test +++ b/contracts/ethereum/.env.test @@ -4,3 +4,9 @@ ETHEREUM_PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf STARKNET_MESSAGING_ADDRESS=0x5FbDB2315678afecb367f032d93F642f64180aa3 MM_ETHEREUM_ADDRESS=0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 SKIP_VERIFY=true +STARKNET_CLAIM_PAYMENT_SELECTOR=0x03636c566f6409560d55d5f6d1eb4ee163b096b4698c503e69e210be79de2afa +STARKNET_CLAIM_PAYMENT_BATCH_SELECTOR=0x0354a01e49fe07e43306a97ed84dbd5de8238c7d8ff616caa3444630cfc559e6 +ZKSYNC_CLAIM_PAYMENT_SELECTOR=0xa5168739 +ZKSYNC_CLAIM_PAYMENT_BATCH_SELECTOR=0x156be1ae +STARKNET_CHAIN_ID=0x534e5f5345504f4c4941 +ZKSYNC_CHAIN_ID=300 diff --git a/contracts/ethereum/deploy.sh b/contracts/ethereum/deploy.sh index cf5c4184..6031543e 100755 --- a/contracts/ethereum/deploy.sh +++ b/contracts/ethereum/deploy.sh @@ -5,12 +5,12 @@ cd contracts/ethereum printf "${GREEN}\n=> [ETH] Deploying ERC1967Proxy & PaymentRegistry ${COLOR_RESET}\n" - export ETHEREUM_PRIVATE_KEY=$ETHEREUM_PRIVATE_KEY RESULT_LOG=$(forge script ./script/Deploy.s.sol --rpc-url $ETHEREUM_RPC --broadcast ${SKIP_VERIFY:---verify}) # echo "$RESULT_LOG" #uncomment this line for debugging in detail + # Getting result addresses PAYMENT_REGISTRY_PROXY_ADDRESS=$(echo "$RESULT_LOG" | grep -Eo '0: address ([^\n]+)' | awk '{print $NF}') PAYMENT_REGISTRY_ADDRESS=$(echo "$RESULT_LOG" | grep -Eo '1: address ([^\n]+)' | awk '{print $NF}') diff --git a/contracts/ethereum/script/Deploy.s.sol b/contracts/ethereum/script/Deploy.s.sol index 890622a8..4aa4958e 100644 --- a/contracts/ethereum/script/Deploy.s.sol +++ b/contracts/ethereum/script/Deploy.s.sol @@ -10,15 +10,30 @@ contract Deploy is Script { uint256 deployerPrivateKey = vm.envUint("ETHEREUM_PRIVATE_KEY"); vm.startBroadcast(deployerPrivateKey); - address snMessagingAddress = vm.envAddress("STARKNET_MESSAGING_ADDRESS"); - uint256 snEscrowAddress = 0x0; // this value is set in a call to the smart contract, once deployed - uint256 snClaimPaymentSelector = 0x0; // this value is set in a call to the smart contract, once deployed - address marketMaker = vm.envAddress("MM_ETHEREUM_WALLET_ADDRESS"); + address STARKNET_MESSAGING_ADDRESS = vm.envAddress("STARKNET_MESSAGING_ADDRESS"); + uint256 STARKNET_CLAIM_PAYMENT_SELECTOR = vm.envUint("STARKNET_CLAIM_PAYMENT_SELECTOR"); + uint256 STARKNET_CLAIM_PAYMENT_BATCH_SELECTOR = vm.envUint("STARKNET_CLAIM_PAYMENT_BATCH_SELECTOR"); + address MM_ETHEREUM_WALLET_ADDRESS = vm.envAddress("MM_ETHEREUM_WALLET_ADDRESS"); address ZKSYNC_DIAMOND_PROXY_ADDRESS = vm.envAddress("ZKSYNC_DIAMOND_PROXY_ADDRESS"); + bytes4 ZKSYNC_CLAIM_PAYMENT_SELECTOR = bytes4(vm.envBytes("ZKSYNC_CLAIM_PAYMENT_SELECTOR")); + bytes4 ZKSYNC_CLAIM_PAYMENT_BATCH_SELECTOR = bytes4(vm.envBytes("ZKSYNC_CLAIM_PAYMENT_BATCH_SELECTOR")); + + uint128 STARKNET_CHAIN_ID = uint128(vm.envUint("STARKNET_CHAIN_ID")); + uint128 ZKSYNC_CHAIN_ID = uint128(vm.envUint("ZKSYNC_CHAIN_ID")); PaymentRegistry yab = new PaymentRegistry(); ERC1967Proxy proxy = new ERC1967Proxy(address(yab), ""); - PaymentRegistry(address(proxy)).initialize(snMessagingAddress, snEscrowAddress, snClaimPaymentSelector, marketMaker, ZKSYNC_DIAMOND_PROXY_ADDRESS); + PaymentRegistry(address(proxy)).initialize( + STARKNET_MESSAGING_ADDRESS, + STARKNET_CLAIM_PAYMENT_SELECTOR, + STARKNET_CLAIM_PAYMENT_BATCH_SELECTOR, + MM_ETHEREUM_WALLET_ADDRESS, + ZKSYNC_DIAMOND_PROXY_ADDRESS, + ZKSYNC_CLAIM_PAYMENT_SELECTOR, + ZKSYNC_CLAIM_PAYMENT_BATCH_SELECTOR, + STARKNET_CHAIN_ID, + ZKSYNC_CHAIN_ID + ); vm.stopBroadcast(); diff --git a/contracts/ethereum/set_starknet_claim_payment_selector.sh b/contracts/ethereum/set_starknet_claim_payment_selector.sh deleted file mode 100755 index 968ffe1b..00000000 --- a/contracts/ethereum/set_starknet_claim_payment_selector.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/bash -. contracts/utils/colors.sh #for ANSI colors - -if [ -z "$PAYMENT_REGISTRY_PROXY_ADDRESS" ]; then - printf "\n${RED}ERROR:${COLOR_RESET}\n" - echo "PAYMENT_REGISTRY_PROXY_ADDRESS Variable is empty. Aborting execution.\n" - exit 1 -fi -if [ -z "$CLAIM_PAYMENT_NAME" ]; then - printf "\n${RED}ERROR:${COLOR_RESET}\n" - echo "CLAIM_PAYMENT_NAME Variable is empty. Aborting execution.\n" - exit 1 -fi - -printf "${GREEN}\n=> [ETH] Setting Starknet ClaimPayment Selector on ETH Smart Contract${COLOR_RESET}\n" -echo "Smart contract being modified:" $PAYMENT_REGISTRY_PROXY_ADDRESS - -CLAIM_PAYMENT_SELECTOR=$(starkli selector $CLAIM_PAYMENT_NAME) -echo "New ClaimPayment Selector: ${CLAIM_PAYMENT_SELECTOR}" - -cast send --rpc-url $ETHEREUM_RPC --private-key $ETHEREUM_PRIVATE_KEY $PAYMENT_REGISTRY_PROXY_ADDRESS "setStarknetClaimPaymentSelector(uint256)" "${CLAIM_PAYMENT_SELECTOR}" | grep "transactionHash" -echo "Done setting ClaimPayment selector" diff --git a/contracts/ethereum/src/PaymentRegistry.sol b/contracts/ethereum/src/PaymentRegistry.sol index 65be1f7c..1f7302e1 100644 --- a/contracts/ethereum/src/PaymentRegistry.sol +++ b/contracts/ethereum/src/PaymentRegistry.sol @@ -9,29 +9,33 @@ import {IZkSync} from "@matterlabs/interfaces/IZkSync.sol"; contract PaymentRegistry is Initializable, OwnableUpgradeable, UUPSUpgradeable { - enum Chain { Starknet, ZKSync } //todo add canonic chainID + event Transfer(uint256 indexed orderId, address srcAddress, address destAddress, uint256 amount, uint128 chainId); + event ClaimPayment(uint256 indexed orderId, address destAddress, uint256 amount, uint128 chainId); + event ClaimPaymentBatch(uint256[] orderIds, address[] destAddresses, uint256[] amounts, uint128 chainId); - struct TransferInfo { - uint256 destAddress; //TODO THIS SHOULD BE TYPE ADDRESS, destAddress is always an L1 address - uint256 amount; - bool isUsed; - Chain chainId; - } - - event Transfer(uint256 indexed orderId, address srcAddress, TransferInfo transferInfo); event ModifiedZKSyncEscrowAddress(address newEscrowAddress); event ModifiedStarknetEscrowAddress(uint256 newEscrowAddress); event ModifiedStarknetClaimPaymentSelector(uint256 newEscrowClaimPaymentSelector); - event ClaimPayment(TransferInfo transferInfo); + event ModifiedStarknetClaimPaymentBatchSelector(uint256 newEscrowClaimPaymentBatchSelector); + event ModifiedZKSyncClaimPaymentSelector(bytes4 newZKSyncEscrowClaimPaymentSelector); + event ModifiedZKSyncClaimPaymentBatchSelector(bytes4 newZKSyncEscrowClaimPaymentBatchSelector); - mapping(bytes32 => TransferInfo) public transfers; + mapping(bytes32 => bool) public transfers; address public marketMaker; uint256 public StarknetEscrowAddress; address public ZKSyncEscrowAddress; uint256 public StarknetEscrowClaimPaymentSelector; - IZkSync private _ZKSyncDiamondProxy; + uint256 public StarknetEscrowClaimPaymentBatchSelector; + bytes4 public ZKSyncEscrowClaimPaymentSelector; + bytes4 public ZKSyncEscrowClaimPaymentBatchSelector; + + IZkSync private _ZKSyncDiamondProxy; IStarknetMessaging private _snMessaging; + //According to EIP-155, ChainIds are uint32, but as Starknet decided to not follow this EIP, we must store them as uint128. + uint128 public StarknetChainId; + uint128 public ZKSyncChainId; + constructor() { _disableInitializers(); } @@ -39,77 +43,150 @@ contract PaymentRegistry is Initializable, OwnableUpgradeable, UUPSUpgradeable { // no constructors can be used in upgradeable contracts. function initialize( address snMessaging, - uint256 StarknetEscrowAddress_, uint256 StarknetEscrowClaimPaymentSelector_, + uint256 StarknetEscrowClaimPaymentBatchSelector_, address marketMaker_, - address ZKSyncDiamondProxyAddress) public initializer { + address ZKSyncDiamondProxyAddress, + bytes4 ZKSyncEscrowClaimPaymentSelector_, + bytes4 ZKSyncEscrowClaimPaymentBatchSelector_, + uint128 StarknetChainId_, + uint128 ZKSyncChainId_) public initializer { __Ownable_init(msg.sender); __UUPSUpgradeable_init(); _snMessaging = IStarknetMessaging(snMessaging); _ZKSyncDiamondProxy = IZkSync(ZKSyncDiamondProxyAddress); - StarknetEscrowAddress = StarknetEscrowAddress_; - StarknetEscrowClaimPaymentSelector = StarknetEscrowClaimPaymentSelector_; // TODO remove this or set the correct value in init + StarknetEscrowClaimPaymentSelector = StarknetEscrowClaimPaymentSelector_; + StarknetEscrowClaimPaymentBatchSelector = StarknetEscrowClaimPaymentBatchSelector_; + ZKSyncEscrowClaimPaymentSelector = ZKSyncEscrowClaimPaymentSelector_; + ZKSyncEscrowClaimPaymentBatchSelector = ZKSyncEscrowClaimPaymentBatchSelector_; + + StarknetChainId = StarknetChainId_; + ZKSyncChainId = ZKSyncChainId_; + marketMaker = marketMaker_; } -//TODO: change orderID to uint32 -//TODO remove amount parameter, it is unnecesarry, only reading msg,value is enough - function transfer(uint256 orderId, uint256 destAddress, Chain chainId) external payable onlyOwnerOrMM { - require(destAddress != 0, "Invalid destination address."); + function transfer(uint256 orderId, address destAddress, uint128 chainId) external payable onlyOwnerOrMM { require(msg.value > 0, "Invalid amount, should be higher than 0."); - bytes32 index = keccak256(abi.encodePacked(orderId, destAddress, msg.value, chainId)); //200 gas - require(transfers[index].isUsed == false, "Transfer already processed."); //3000 gas - - transfers[index] = TransferInfo({destAddress: destAddress, amount: msg.value, isUsed: true, chainId: chainId}); + bytes32 index = keccak256(abi.encodePacked(orderId, destAddress, msg.value, chainId)); + require(transfers[index] == false, "Transfer already processed."); + transfers[index] = true; //now this transfer is in progress - (bool success,) = payable(address(uint160(destAddress))).call{value: msg.value}(""); //34000 gas - // (bool success,) = payable(marketMaker).call{value: msg.value}(""); //32000 gas //to implement this, address must be changed to from uint256 to addr + (bool success,) = payable(destAddress).call{value: msg.value}(""); //34000 gas require(success, "Transfer failed."); - emit Transfer(orderId, msg.sender, transfers[index]); //3000 gas + emit Transfer(orderId, msg.sender, destAddress, msg.value, chainId); //2400 gas } -//TODO change name to claimPaymentStarknet - function claimPayment(uint256 orderId, uint256 destAddress, uint256 amount) external payable onlyOwnerOrMM { - bytes32 index = keccak256(abi.encodePacked(orderId, destAddress, amount, Chain.Starknet)); - TransferInfo storage transferInfo = transfers[index]; - require(transferInfo.isUsed == true, "Transfer not found."); + function claimPaymentStarknet(uint256 orderId, address destAddress, uint256 amount) external payable onlyOwnerOrMM { + _verifyTransferExistsStarknet(orderId, destAddress, amount); - uint256[] memory payload = new uint256[](5); //TODO why array of 256 if then filled with 128? + uint256[] memory payload = new uint256[](5); //this is not an array of u128 because sendMessageToL2 takes an array of uint256 payload[0] = uint128(orderId); // low payload[1] = uint128(orderId >> 128); // high - payload[2] = transferInfo.destAddress; + payload[2] = uint256(uint160(destAddress)); payload[3] = uint128(amount); // low payload[4] = uint128(amount >> 128); // high - + + //10k gas: _snMessaging.sendMessageToL2{value: msg.value}( StarknetEscrowAddress, StarknetEscrowClaimPaymentSelector, payload); - emit ClaimPayment(transferInfo); + emit ClaimPayment(orderId, destAddress, amount, StarknetChainId); + } + + function claimPaymentBatchStarknet( + uint256[] calldata orderIds, + address[] calldata destAddresses, + uint256[] calldata amounts + ) external payable onlyOwnerOrMM() { + require(orderIds.length == destAddresses.length, "Invalid lengths."); + require(orderIds.length == amounts.length, "Invalid lengths."); + + uint256[] memory payload = new uint256[](5 * orderIds.length + 1); + + payload[0] = orderIds.length; + + for (uint32 idx = 0; idx < orderIds.length; idx++) { + uint256 orderId = orderIds[idx]; + address destAddress = destAddresses[idx]; + uint256 amount = amounts[idx]; + + _verifyTransferExistsStarknet(orderId, destAddress, amount); + + uint32 base_idx = 1 + 5 * idx; + payload[base_idx] = uint128(orderId); // low + payload[base_idx + 1] = uint128(orderId >> 128); // high + payload[base_idx + 2] = uint256(uint160(destAddress)); + payload[base_idx + 3] = uint128(amount); // low + payload[base_idx + 4] = uint128(amount >> 128); // high + } + + _snMessaging.sendMessageToL2{value: msg.value}( + StarknetEscrowAddress, + StarknetEscrowClaimPaymentBatchSelector, + payload); + + emit ClaimPaymentBatch(orderIds, destAddresses, amounts, StarknetChainId); + } + + function _verifyTransferExistsStarknet(uint256 orderId, address destAddress, uint256 amount) internal view { + bytes32 index = keccak256(abi.encodePacked(orderId, destAddress, amount, StarknetChainId)); + require(transfers[index] == true, "Transfer not found."); } function claimPaymentZKSync( - uint256 orderId, uint256 destAddress, uint256 amount, + uint256 orderId, address destAddress, uint256 amount, uint256 gasLimit, uint256 gasPerPubdataByteLimit ) external payable onlyOwnerOrMM { - bytes32 index = keccak256(abi.encodePacked(orderId, destAddress, amount, Chain.ZKSync)); - TransferInfo storage transferInfo = transfers[index]; - require(transferInfo.isUsed == true, "Transfer not found."); + _verifyTransferExistsZKSync(orderId, destAddress, amount); - //todo change place of this var - bytes4 selector = 0xa5168739; //claim_payment selector in ZKSync //todo add in init, same as in SN bytes memory messageToL2 = abi.encodeWithSelector( - selector, + ZKSyncEscrowClaimPaymentSelector, orderId, - transferInfo.destAddress, - transferInfo.amount + destAddress, + amount + ); + + _ZKSyncDiamondProxy.requestL2Transaction{value: msg.value}( + ZKSyncEscrowAddress, //L2 contract called + 0, //msg.value + messageToL2, //msg.calldata + gasLimit, + gasPerPubdataByteLimit, + new bytes[](0), //factory dependencies + msg.sender //refund recipient + ); + + emit ClaimPayment(orderId, destAddress, amount, ZKSyncChainId); //2100 gas + } + + function claimPaymentBatchZKSync( + uint256[] calldata orderIds, + address[] calldata destAddresses, + uint256[] calldata amounts, + uint256 gasLimit, + uint256 gasPerPubdataByteLimit + ) external payable onlyOwnerOrMM { + require(orderIds.length == destAddresses.length, "Invalid lengths."); + require(orderIds.length == amounts.length, "Invalid lengths."); + + for (uint32 idx = 0; idx < orderIds.length; idx++) { + _verifyTransferExistsZKSync(orderIds[idx], destAddresses[idx], amounts[idx]); + } + + bytes memory messageToL2 = abi.encodeWithSelector( + ZKSyncEscrowClaimPaymentBatchSelector, + orderIds, + destAddresses, + amounts ); _ZKSyncDiamondProxy.requestL2Transaction{value: msg.value}( @@ -122,7 +199,12 @@ contract PaymentRegistry is Initializable, OwnableUpgradeable, UUPSUpgradeable { msg.sender //refund recipient ); - emit ClaimPayment(transferInfo); + emit ClaimPaymentBatch(orderIds, destAddresses, amounts, ZKSyncChainId); + } + + function _verifyTransferExistsZKSync(uint256 orderId, address destAddress, uint256 amount) internal view { + bytes32 index = keccak256(abi.encodePacked(orderId, destAddress, amount, ZKSyncChainId)); + require(transfers[index] == true, "Transfer not found."); //if this is claimed twice, Escrow will know } function setStarknetEscrowAddress(uint256 newStarknetEscrowAddress) external onlyOwner { @@ -135,13 +217,26 @@ contract PaymentRegistry is Initializable, OwnableUpgradeable, UUPSUpgradeable { emit ModifiedZKSyncEscrowAddress(newZKSyncEscrowAddress); } - //todo change name to something more starknet-ish - //this todo applies for this whole contract, but in a future change because MM-bot would need a refactor. function setStarknetClaimPaymentSelector(uint256 NewStarknetEscrowClaimPaymentSelector) external onlyOwner { StarknetEscrowClaimPaymentSelector = NewStarknetEscrowClaimPaymentSelector; emit ModifiedStarknetClaimPaymentSelector(StarknetEscrowClaimPaymentSelector); } - + + function setStarknetClaimPaymentBatchSelector(uint256 NewStarknetEscrowClaimPaymentBatchSelector) external onlyOwner { + StarknetEscrowClaimPaymentBatchSelector = NewStarknetEscrowClaimPaymentBatchSelector; + emit ModifiedStarknetClaimPaymentBatchSelector(StarknetEscrowClaimPaymentBatchSelector); + } + + function setZKSyncEscrowClaimPaymentSelector(bytes4 NewZKSyncEscrowClaimPaymentSelector) external onlyOwner { + ZKSyncEscrowClaimPaymentSelector = NewZKSyncEscrowClaimPaymentSelector; + emit ModifiedZKSyncClaimPaymentSelector(ZKSyncEscrowClaimPaymentSelector); + } + + function setZKSyncEscrowClaimPaymentBatchSelector(bytes4 NewZKSyncEscrowClaimPaymentBatchSelector) external onlyOwner { + ZKSyncEscrowClaimPaymentBatchSelector = NewZKSyncEscrowClaimPaymentBatchSelector; + emit ModifiedZKSyncClaimPaymentBatchSelector(ZKSyncEscrowClaimPaymentBatchSelector); + } + //// MM ACL: diff --git a/contracts/ethereum/test/.env.test b/contracts/ethereum/test/.env.test index eabdc287..c7471239 100644 --- a/contracts/ethereum/test/.env.test +++ b/contracts/ethereum/test/.env.test @@ -2,13 +2,30 @@ SKIP_VERIFY=true #cant verify on local devnet ETHEREUM_RPC=http://localhost:8545 #local devnet L1 rpc url -ZKSYNC_DIAMOND_PROXY_ADDRESS=0x97589bcE7727f5D0C8082440681DB6092b6Dda1a +ZKSYNC_DIAMOND_PROXY_ADDRESS=0xdA7aA6e28eD3164bF5383eCe38868ADc7686A2F0 ETHEREUM_PRIVATE_KEY=0x7726827caac94a7f9e1b160f7ea819f172f7b6f9d2a97f992c38edeab82d4110 #prefunded 0 -MM_ETHEREUM_PRIVATE_KEY=0x7726827caac94a7f9e1b160f7ea819f172f7b6f9d2a97f992c38edeab82d4110 #prefunded 0 -MM_ETHEREUM_PUBLIC_ADDRESS=0x36615Cf349d7F6344891B1e7CA7C72883F5dc049 #prefunded 0 +MM_ETHEREUM_PRIVATE_KEY=0xd293c684d884d56f8d6abd64fc76757d3664904e309a0645baf8522ab6366d9e #prefunded 2 +MM_ETHEREUM_WALLET_ADDRESS=0x0D43eB5B8a47bA8900d84AA36656c92024e9772e #prefunded 2 + +USER_ETHEREUM_PUBLIC_ADDRESS=0xCEEe57f2B700c2f37D1476A7974965E149Fce2D4 #random address with no funds + +ETHERSCAN_API_KEY=0x1 + +ZKSYNC_CLAIM_PAYMENT_SELECTOR=0xa5168739 +ZKSYNC_CLAIM_PAYMENT_BATCH_SELECTOR=0x156be1ae +ZKSYNC_CHAIN_ID=300 + + +#irrelevant SN variables +STARKNET_CLAIM_PAYMENT_SELECTOR=0x03636c566f6409560d55d5f6d1eb4ee163b096b4698c503e69e210be79de2afa +STARKNET_CLAIM_PAYMENT_BATCH_SELECTOR=0x0354a01e49fe07e43306a97ed84dbd5de8238c7d8ff616caa3444630cfc559e6 +STARKNET_MESSAGING_ADDRESS=0xE2Bb56ee936fd6433DC0F6e7e3b8365C906AA057 +STARKNET_CHAIN_ID=0x534e5f5345504f4c4941 + + + + -USER_ETHEREUM_PUBLIC_ADDRESS=0xceee57f2b700c2f37d1476a7974965e149fce2d4 #random address with no funds -USER_ETHEREUM_PUBLIC_ADDRESS_UINT=1181367337507422765615536123397692015769584198356 diff --git a/contracts/ethereum/test/ACL.t.sol b/contracts/ethereum/test/ACL.t.sol index 10e36a50..62d4e665 100644 --- a/contracts/ethereum/test/ACL.t.sol +++ b/contracts/ethereum/test/ACL.t.sol @@ -7,16 +7,21 @@ import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.s contract TransferTest is Test { address public deployer = makeAddr('deployer'); - address public marketMaker = makeAddr('marketMaker'); - uint256 public snEscrowAddress = 0x0; + address public MM_ETHEREUM_WALLET_ADDRESS = makeAddr('marketMaker'); PaymentRegistry public yab; ERC1967Proxy public proxy; PaymentRegistry public yab_caller; - address SN_MESSAGING_ADDRESS = 0xde29d060D45901Fb19ED6C6e959EB22d8626708e; - uint256 SN_ESCROW_CLAIM_PAYMENT_SELECTOR = 0x15511cc3694f64379908437d6d64458dc76d02482052bfb8a5b33a72c054c77; + address STARKNET_MESSAGING_ADDRESS = 0xde29d060D45901Fb19ED6C6e959EB22d8626708e; + uint256 STARKNET_CLAIM_PAYMENT_SELECTOR = 0x15511cc3694f64379908437d6d64458dc76d02482052bfb8a5b33a72c054c77; + uint256 STARKNET_CLAIM_PAYMENT_BATCH_SELECTOR = 0x0354a01e49fe07e43306a97ed84dbd5de8238c7d8ff616caa3444630cfc559e6; address ZKSYNC_DIAMOND_PROXY_ADDRESS = 0x2eD8eF54a16bBF721a318bd5a5C0F39Be70eaa65; + bytes4 ZKSYNC_CLAIM_PAYMENT_SELECTOR = 0xa5168739; + bytes4 ZKSYNC_CLAIM_PAYMENT_BATCH_SELECTOR = 0x156be1ae; + + uint128 STARKNET_CHAIN_ID = 0x534e5f5345504f4c4941; + uint128 ZKSYNC_CHAIN_ID = 300; function setUp() public { vm.startPrank(deployer); @@ -24,14 +29,14 @@ contract TransferTest is Test { yab = new PaymentRegistry(); proxy = new ERC1967Proxy(address(yab), ""); yab_caller = PaymentRegistry(address(proxy)); - yab_caller.initialize(SN_MESSAGING_ADDRESS, snEscrowAddress, SN_ESCROW_CLAIM_PAYMENT_SELECTOR, marketMaker, ZKSYNC_DIAMOND_PROXY_ADDRESS); + yab_caller.initialize(STARKNET_MESSAGING_ADDRESS, STARKNET_CLAIM_PAYMENT_SELECTOR, STARKNET_CLAIM_PAYMENT_BATCH_SELECTOR, MM_ETHEREUM_WALLET_ADDRESS, ZKSYNC_DIAMOND_PROXY_ADDRESS, ZKSYNC_CLAIM_PAYMENT_SELECTOR, ZKSYNC_CLAIM_PAYMENT_BATCH_SELECTOR, STARKNET_CHAIN_ID, ZKSYNC_CHAIN_ID); vm.stopPrank(); } function test_getMarketMaker() public { address mmAddress = yab_caller.marketMaker(); - assertEq(mmAddress, marketMaker); + assertEq(mmAddress, MM_ETHEREUM_WALLET_ADDRESS); } function test_set_and_get_MMAddress_deployer() public { @@ -56,25 +61,25 @@ contract TransferTest is Test { function test_transfer_sn_fail_notOwnerOrMM() public { hoax(makeAddr("bob"), 100 wei); vm.expectRevert("Only Owner or MM can call this function"); - yab_caller.transfer{value: 100}(1, 0x1, PaymentRegistry.Chain.Starknet); + yab_caller.transfer{value: 100}(1, address(0x1), STARKNET_CHAIN_ID); } function test_claimPayment_sn_fail_notOwnerOrMM() public { hoax(makeAddr("bob"), 100 wei); vm.expectRevert("Only Owner or MM can call this function"); - yab_caller.claimPayment{value: 100}(1, 0x1, 100); + yab_caller.claimPaymentStarknet{value: 100}(1, address(0x1), 100); } function test_transfer_zk_fail_notOwnerOrMM() public { hoax(makeAddr("bob"), 100 wei); vm.expectRevert("Only Owner or MM can call this function"); - yab_caller.transfer{value: 100}(1, 0x1, PaymentRegistry.Chain.ZKSync); + yab_caller.transfer{value: 100}(1, address(0x1), ZKSYNC_CHAIN_ID); } function test_claimPayment_zk_fail_notOwnerOrMM() public { hoax(makeAddr("bob"), 100 wei); vm.expectRevert("Only Owner or MM can call this function"); - yab_caller.claimPaymentZKSync{value: 100}(1, 0x1, 100, 1, 1); + yab_caller.claimPaymentZKSync{value: 100}(1, address(0x1), 100, 1, 1); } function test_setStarknetClaimPaymentSelector() public { diff --git a/contracts/ethereum/test/Transfer_Claim_SN.t.sol b/contracts/ethereum/test/Transfer_Claim_SN.t.sol index 3872ad2d..20bab404 100644 --- a/contracts/ethereum/test/Transfer_Claim_SN.t.sol +++ b/contracts/ethereum/test/Transfer_Claim_SN.t.sol @@ -6,18 +6,24 @@ import "../src/PaymentRegistry.sol"; import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; contract TransferTest is Test { + event ClaimPaymentBatch(uint256[] orderIds, address[] destAddresses, uint256[] amounts, uint128 chainId); address public deployer = makeAddr('deployer'); - address public marketMaker = makeAddr("marketMaker"); - uint256 public snEscrowAddress = 0x0; + address public MM_ETHEREUM_WALLET_ADDRESS = makeAddr("marketMaker"); PaymentRegistry public yab; ERC1967Proxy public proxy; PaymentRegistry public yab_caller; address STARKNET_MESSAGING_ADDRESS = 0xde29d060D45901Fb19ED6C6e959EB22d8626708e; - uint256 SN_ESCROW_CLAIM_PAYMENT_SELECTOR = 0x15511cc3694f64379908437d6d64458dc76d02482052bfb8a5b33a72c054c77; + uint256 STARKNET_CLAIM_PAYMENT_SELECTOR = 0x15511cc3694f64379908437d6d64458dc76d02482052bfb8a5b33a72c054c77; + uint256 STARKNET_CLAIM_PAYMENT_BATCH_SELECTOR = 0x0354a01e49fe07e43306a97ed84dbd5de8238c7d8ff616caa3444630cfc559e6; address ZKSYNC_DIAMOND_PROXY_ADDRESS = 0x2eD8eF54a16bBF721a318bd5a5C0F39Be70eaa65; + bytes4 ZKSYNC_CLAIM_PAYMENT_SELECTOR = 0xa5168739; + bytes4 ZKSYNC_CLAIM_PAYMENT_BATCH_SELECTOR = 0x156be1ae; + + uint128 STARKNET_CHAIN_ID = 0x534e5f5345504f4c4941; + uint128 ZKSYNC_CHAIN_ID = 300; function setUp() public { vm.startPrank(deployer); @@ -25,8 +31,7 @@ contract TransferTest is Test { yab = new PaymentRegistry(); proxy = new ERC1967Proxy(address(yab), ""); yab_caller = PaymentRegistry(address(proxy)); - yab_caller.initialize(STARKNET_MESSAGING_ADDRESS, snEscrowAddress, SN_ESCROW_CLAIM_PAYMENT_SELECTOR, marketMaker, ZKSYNC_DIAMOND_PROXY_ADDRESS); - + yab_caller.initialize(STARKNET_MESSAGING_ADDRESS, STARKNET_CLAIM_PAYMENT_SELECTOR, STARKNET_CLAIM_PAYMENT_BATCH_SELECTOR, MM_ETHEREUM_WALLET_ADDRESS, ZKSYNC_DIAMOND_PROXY_ADDRESS, ZKSYNC_CLAIM_PAYMENT_SELECTOR, ZKSYNC_CLAIM_PAYMENT_BATCH_SELECTOR, STARKNET_CHAIN_ID, ZKSYNC_CHAIN_ID); // Mock calls to Starknet Messaging contract vm.mockCall( STARKNET_MESSAGING_ADDRESS, @@ -37,56 +42,172 @@ contract TransferTest is Test { } function test_transfer_sn() public { - hoax(marketMaker, 100 wei); - yab_caller.transfer{value: 100}(1, 0x1, PaymentRegistry.Chain.Starknet); + hoax(MM_ETHEREUM_WALLET_ADDRESS, 100 wei); + yab_caller.transfer{value: 100}(1, address(0x1), STARKNET_CHAIN_ID); assertEq(address(0x1).balance, 100); } + function test_transfer_sn_fail_already_transferred() public { + hoax(MM_ETHEREUM_WALLET_ADDRESS, 100 wei); + yab_caller.transfer{value: 100}(1, address(0x1), STARKNET_CHAIN_ID); + hoax(MM_ETHEREUM_WALLET_ADDRESS, 100 wei); + vm.expectRevert("Transfer already processed."); + yab_caller.transfer{value: 100}(1, address(0x1), STARKNET_CHAIN_ID); + } + function test_claimPayment_sn_fail_noOrderId() public { - hoax(marketMaker, 100 wei); + hoax(MM_ETHEREUM_WALLET_ADDRESS, 100 wei); vm.expectRevert("Transfer not found."); //Won't match to a random transfer number - yab_caller.claimPayment{value: 100}(1, 0x1, 100); + yab_caller.claimPaymentStarknet{value: 100}(1, address(0x1), 100); } function test_claimPayment_sn_fail_wrongOrderId() public { - hoax(marketMaker, 100 wei); - yab_caller.transfer{value: 100}(1, 0x1, PaymentRegistry.Chain.Starknet); - hoax(marketMaker, 100 wei); + hoax(MM_ETHEREUM_WALLET_ADDRESS, 100 wei); + yab_caller.transfer{value: 100}(1, address(0x1), STARKNET_CHAIN_ID); + hoax(MM_ETHEREUM_WALLET_ADDRESS, 100 wei); vm.expectRevert("Transfer not found."); //Won't match to a wrong transfer number - yab_caller.claimPayment(2, 0x1, 100); + yab_caller.claimPaymentStarknet(2, address(0x1), 100); } function test_claimPayment_sn() public { - hoax(marketMaker, 100 wei); - yab_caller.transfer{value: 100}(1, 0x1, PaymentRegistry.Chain.Starknet); - hoax(marketMaker, 100 wei); - yab_caller.claimPayment(1, 0x1, 100); - assertEq(address(marketMaker).balance, 100); + hoax(MM_ETHEREUM_WALLET_ADDRESS, 100 wei); + yab_caller.transfer{value: 100}(1, address(0x1), STARKNET_CHAIN_ID); + hoax(MM_ETHEREUM_WALLET_ADDRESS, 100 wei); + yab_caller.claimPaymentStarknet(1, address(0x1), 100); + assertEq(address(MM_ETHEREUM_WALLET_ADDRESS).balance, 100); } function test_claimPayment_sn_maxInt() public { uint256 maxInt = type(uint256).max; - vm.deal(marketMaker, maxInt); - vm.startPrank(marketMaker); + vm.deal(MM_ETHEREUM_WALLET_ADDRESS, maxInt); + vm.startPrank(MM_ETHEREUM_WALLET_ADDRESS); - yab_caller.transfer{value: maxInt}(1, 0x1, PaymentRegistry.Chain.Starknet); - yab_caller.claimPayment(1, 0x1, maxInt); + yab_caller.transfer{value: maxInt}(1, address(0x1), STARKNET_CHAIN_ID); + yab_caller.claimPaymentStarknet(1, address(0x1), maxInt); vm.stopPrank(); } function test_claimPayment_sn_minInt() public { - hoax(marketMaker, 1 wei); - yab_caller.transfer{value: 1}(1, 0x1, PaymentRegistry.Chain.Starknet); - hoax(marketMaker, 1 wei); - yab_caller.claimPayment(1, 0x1, 1); + hoax(MM_ETHEREUM_WALLET_ADDRESS, 1 wei); + yab_caller.transfer{value: 1}(1, address(0x1), STARKNET_CHAIN_ID); + hoax(MM_ETHEREUM_WALLET_ADDRESS, 1 wei); + yab_caller.claimPaymentStarknet(1, address(0x1), 1); + } + + function testClaimPaymentBatch_sn() public { + hoax(MM_ETHEREUM_WALLET_ADDRESS, 3 wei); + yab_caller.transfer{value: 3}(1,address(0x1), STARKNET_CHAIN_ID); + hoax(MM_ETHEREUM_WALLET_ADDRESS, 2 wei); + yab_caller.transfer{value: 2}(2, address(0x3), STARKNET_CHAIN_ID); + hoax(MM_ETHEREUM_WALLET_ADDRESS, 1 wei); + yab_caller.transfer{value: 1}(3, address(0x5), STARKNET_CHAIN_ID); + + uint256[] memory orderIds = new uint256[](3); + address[] memory destAddresses = new address[](3); + uint256[] memory amounts = new uint256[](3); + + orderIds[0] = 1; + orderIds[1] = 2; + orderIds[2] = 3; + + destAddresses[0] = address(0x1); + destAddresses[1] = address(0x3); + destAddresses[2] = address(0x5); + + amounts[0] = 3; + amounts[1] = 2; + amounts[2] = 1; + + hoax(MM_ETHEREUM_WALLET_ADDRESS); + vm.expectEmit(true, true, true, true); + emit ClaimPaymentBatch(orderIds, destAddresses, amounts, STARKNET_CHAIN_ID); + yab_caller.claimPaymentBatchStarknet(orderIds, destAddresses, amounts); + + assertEq(address(0x1).balance, 3); + assertEq(address(0x3).balance, 2); + assertEq(address(0x5).balance, 1); + } + + function testClaimPaymentBatchPartial_sn() public { + hoax(MM_ETHEREUM_WALLET_ADDRESS, 3 wei); + yab_caller.transfer{value: 3}(1, address(0x1), STARKNET_CHAIN_ID); + hoax(MM_ETHEREUM_WALLET_ADDRESS, 2 wei); + yab_caller.transfer{value: 2}(2, address(0x3), STARKNET_CHAIN_ID); + hoax(MM_ETHEREUM_WALLET_ADDRESS, 1 wei); + yab_caller.transfer{value: 1}(3, address(0x5), STARKNET_CHAIN_ID); + + uint256[] memory orderIds = new uint256[](2); + address[] memory destAddresses = new address[](2); + uint256[] memory amounts = new uint256[](2); + + orderIds[0] = 1; + orderIds[1] = 2; + + destAddresses[0] = address(0x1); + destAddresses[1] = address(0x3); + + amounts[0] = 3; + amounts[1] = 2; + + hoax(MM_ETHEREUM_WALLET_ADDRESS); + yab_caller.claimPaymentBatchStarknet(orderIds, destAddresses, amounts); + + assertEq(address(0x1).balance, 3); + assertEq(address(0x3).balance, 2); + } + + function testClaimPaymentBatch_fail_MissingTransfer() public { + hoax(MM_ETHEREUM_WALLET_ADDRESS, 3 wei); + yab_caller.transfer{value: 3}(1, address(0x1), STARKNET_CHAIN_ID); + hoax(MM_ETHEREUM_WALLET_ADDRESS, 2 wei); + yab_caller.transfer{value: 2}(2, address(0x3), STARKNET_CHAIN_ID); + + uint256[] memory orderIds = new uint256[](3); + address[] memory destAddresses = new address[](3); + uint256[] memory amounts = new uint256[](3); + + orderIds[0] = 1; + orderIds[1] = 2; + orderIds[2] = 3; + + destAddresses[0] = address(0x1); + destAddresses[1] = address(0x3); + destAddresses[2] = address(0x5); + + amounts[0] = 3; + amounts[1] = 2; + amounts[2] = 1; + + vm.expectRevert("Transfer not found."); + hoax(MM_ETHEREUM_WALLET_ADDRESS); + yab_caller.claimPaymentBatchStarknet(orderIds, destAddresses, amounts); + } + + function testClaimPaymentBatch_fail_notOwnerOrMM() public { + hoax(MM_ETHEREUM_WALLET_ADDRESS, 3 wei); + yab_caller.transfer{value: 3}(1, address(0x1), STARKNET_CHAIN_ID); + + uint256[] memory orderIds = new uint256[](1); + address[] memory destAddresses = new address[](1); + uint256[] memory amounts = new uint256[](1); + + orderIds[0] = 1; + + destAddresses[0] = address(0x1); + + amounts[0] = 3; + + hoax(makeAddr("bob"), 100 wei); + vm.expectRevert("Only Owner or MM can call this function"); + yab_caller.claimPaymentBatchStarknet(orderIds, destAddresses, amounts); } function test_claimPayment_fail_wrongChain() public { - hoax(marketMaker, 1 wei); - yab_caller.transfer{value: 1}(1, 0x1, PaymentRegistry.Chain.Starknet); - hoax(marketMaker, 1 wei); + hoax(MM_ETHEREUM_WALLET_ADDRESS, 1 wei); + yab_caller.transfer{value: 1}(1, address(0x1), STARKNET_CHAIN_ID); + hoax(MM_ETHEREUM_WALLET_ADDRESS, 1 wei); vm.expectRevert("Transfer not found."); //Won't match to a transfer made on the other chain - yab_caller.claimPaymentZKSync(1, 0x1, 1, 1 ,1); + yab_caller.claimPaymentZKSync(1, address(0x1), 1, 1 ,1); } } diff --git a/contracts/ethereum/test/Transfer_Claim_ZKSync.t.sol b/contracts/ethereum/test/Transfer_Claim_ZKSync.t.sol index e9bf3e7b..0d412eb5 100644 --- a/contracts/ethereum/test/Transfer_Claim_ZKSync.t.sol +++ b/contracts/ethereum/test/Transfer_Claim_ZKSync.t.sol @@ -8,16 +8,21 @@ import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.s contract TransferTest is Test { address public deployer = makeAddr('deployer'); - address public marketMaker = makeAddr("marketMaker"); - uint256 public snEscrowAddress = 0x0; + address public MM_ETHEREUM_WALLET_ADDRESS = makeAddr("marketMaker"); PaymentRegistry public yab; ERC1967Proxy public proxy; PaymentRegistry public yab_caller; - address SN_MESSAGING_ADDRESS = 0xde29d060D45901Fb19ED6C6e959EB22d8626708e; - uint256 SN_ESCROW_CLAIM_PAYMENT_SELECTOR = 0x15511cc3694f64379908437d6d64458dc76d02482052bfb8a5b33a72c054c77; + address STARKNET_MESSAGING_ADDRESS = 0xde29d060D45901Fb19ED6C6e959EB22d8626708e; + uint256 STARKNET_CLAIM_PAYMENT_SELECTOR = 0x15511cc3694f64379908437d6d64458dc76d02482052bfb8a5b33a72c054c77; + uint256 STARKNET_CLAIM_PAYMENT_BATCH_SELECTOR = 0x0354a01e49fe07e43306a97ed84dbd5de8238c7d8ff616caa3444630cfc559e6; address ZKSYNC_DIAMOND_PROXY_ADDRESS = 0x2eD8eF54a16bBF721a318bd5a5C0F39Be70eaa65; + bytes4 ZKSYNC_CLAIM_PAYMENT_SELECTOR = 0xa5168739; + bytes4 ZKSYNC_CLAIM_PAYMENT_BATCH_SELECTOR = 0x156be1ae; + + uint128 STARKNET_CHAIN_ID = 0x534e5f5345504f4c4941; + uint128 ZKSYNC_CHAIN_ID = 300; function setUp() public { vm.startPrank(deployer); @@ -25,8 +30,7 @@ contract TransferTest is Test { yab = new PaymentRegistry(); proxy = new ERC1967Proxy(address(yab), ""); yab_caller = PaymentRegistry(address(proxy)); - yab_caller.initialize(SN_MESSAGING_ADDRESS, snEscrowAddress, SN_ESCROW_CLAIM_PAYMENT_SELECTOR, marketMaker, ZKSYNC_DIAMOND_PROXY_ADDRESS); - + yab_caller.initialize(STARKNET_MESSAGING_ADDRESS, STARKNET_CLAIM_PAYMENT_SELECTOR, STARKNET_CLAIM_PAYMENT_BATCH_SELECTOR, MM_ETHEREUM_WALLET_ADDRESS, ZKSYNC_DIAMOND_PROXY_ADDRESS, ZKSYNC_CLAIM_PAYMENT_SELECTOR, ZKSYNC_CLAIM_PAYMENT_BATCH_SELECTOR, STARKNET_CHAIN_ID, ZKSYNC_CHAIN_ID); //Mock calls to ZKSync Mailbox contract vm.mockCall( ZKSYNC_DIAMOND_PROXY_ADDRESS, @@ -38,56 +42,129 @@ contract TransferTest is Test { } function test_transfer_zk() public { - hoax(marketMaker, 100 wei); - yab_caller.transfer{value: 100}(1, 0x1, PaymentRegistry.Chain.ZKSync); + hoax(MM_ETHEREUM_WALLET_ADDRESS, 100 wei); + yab_caller.transfer{value: 100}(1, address(0x1), ZKSYNC_CHAIN_ID); assertEq(address(0x1).balance, 100); } + function test_transfer_zk_fail_already_transferred() public { + hoax(MM_ETHEREUM_WALLET_ADDRESS, 100 wei); + yab_caller.transfer{value: 100}(1, address(0x1), ZKSYNC_CHAIN_ID); + hoax(MM_ETHEREUM_WALLET_ADDRESS, 100 wei); + vm.expectRevert("Transfer already processed."); + yab_caller.transfer{value: 100}(1, address(0x1), ZKSYNC_CHAIN_ID); + } + function test_claimPayment_zk_fail_noOrderId() public { - hoax(marketMaker, 100 wei); + hoax(MM_ETHEREUM_WALLET_ADDRESS, 100 wei); vm.expectRevert("Transfer not found."); //Won't match to a random transfer number - yab_caller.claimPaymentZKSync(1, 0x1, 100, 1, 1); + yab_caller.claimPaymentZKSync(1, address(0x1), 100, 1, 1); } function test_claimPayment_zk_fail_wrongOrderId() public { - hoax(marketMaker, 100 wei); - yab_caller.transfer{value: 100}(1, 0x1, PaymentRegistry.Chain.ZKSync); - hoax(marketMaker, 100 wei); + hoax(MM_ETHEREUM_WALLET_ADDRESS, 100 wei); + yab_caller.transfer{value: 100}(1, address(0x1), ZKSYNC_CHAIN_ID); + hoax(MM_ETHEREUM_WALLET_ADDRESS, 100 wei); vm.expectRevert("Transfer not found."); //Won't match to a wrong transfer number - yab_caller.claimPaymentZKSync(2, 0x1, 100, 1, 1); + yab_caller.claimPaymentZKSync(2, address(0x1), 100, 1, 1); } function test_claimPayment_zk() public { - hoax(marketMaker, 100 wei); - yab_caller.transfer{value: 100}(1, 0x1, PaymentRegistry.Chain.ZKSync); - hoax(marketMaker, 100 wei); - yab_caller.claimPaymentZKSync(1, 0x1, 100, 1, 1); - assertEq(address(marketMaker).balance, 100); + hoax(MM_ETHEREUM_WALLET_ADDRESS, 100 wei); + yab_caller.transfer{value: 100}(1, address(0x1), ZKSYNC_CHAIN_ID); + hoax(MM_ETHEREUM_WALLET_ADDRESS, 100 wei); + yab_caller.claimPaymentZKSync(1, address(0x1), 100, 1, 1); + assertEq(address(MM_ETHEREUM_WALLET_ADDRESS).balance, 100); + } + + function test_claimPaymentBatch_zk() public { + hoax(MM_ETHEREUM_WALLET_ADDRESS, 100 wei); + yab_caller.transfer{value: 100}(1, address(0x1), ZKSYNC_CHAIN_ID); + hoax(MM_ETHEREUM_WALLET_ADDRESS, 101 wei); + yab_caller.transfer{value: 100}(2, address(0x1), ZKSYNC_CHAIN_ID); + + uint256[] memory orderIds = new uint256[](2); + address[] memory destAddresses = new address[](2); + uint256[] memory amounts = new uint256[](2); + + orderIds[0] = 1; + orderIds[1] = 2; + destAddresses[0] = address(0x1); + destAddresses[1] = address(0x1); + amounts[0] = 100; + amounts[1] = 100; + + vm.mockCall( + ZKSYNC_DIAMOND_PROXY_ADDRESS, + abi.encodeWithSelector(0x156be1ae, 0), //TODO add selector + abi.encode(0x12345678901234567890123456789012) //TODO add return data + ); + hoax(MM_ETHEREUM_WALLET_ADDRESS); + yab_caller.claimPaymentBatchZKSync(orderIds, destAddresses, amounts, 1, 1); + } + + function test_claimPaymentBatch_zk_fail_MissingTransfer() public { + hoax(MM_ETHEREUM_WALLET_ADDRESS, 100 wei); + yab_caller.transfer{value: 100}(1, address(0x1), ZKSYNC_CHAIN_ID); + + uint256[] memory orderIds = new uint256[](2); + address[] memory destAddresses = new address[](2); + uint256[] memory amounts = new uint256[](2); + + orderIds[0] = 1; + orderIds[1] = 2; + destAddresses[0] = address(0x1); + destAddresses[1] = address(0x1); + amounts[0] = 100; + amounts[1] = 100; + + vm.expectRevert("Transfer not found."); + hoax(MM_ETHEREUM_WALLET_ADDRESS); + yab_caller.claimPaymentBatchZKSync(orderIds, destAddresses, amounts, 1, 1); + } + + function test_claimPaymentBatch_zk_fail_notOwnerOrMM() public { + hoax(MM_ETHEREUM_WALLET_ADDRESS, 100 wei); + yab_caller.transfer{value: 100}(1, address(0x1), ZKSYNC_CHAIN_ID); + + uint256[] memory orderIds = new uint256[](2); + address[] memory destAddresses = new address[](2); + uint256[] memory amounts = new uint256[](2); + + orderIds[0] = 1; + orderIds[1] = 2; + destAddresses[0] = address(0x1); + destAddresses[1] = address(0x1); + amounts[0] = 100; + amounts[1] = 100; + + vm.expectRevert("Only Owner or MM can call this function"); + yab_caller.claimPaymentBatchZKSync(orderIds, destAddresses, amounts, 0, 1); } function test_claimPayment_zk_maxInt() public { uint256 maxInt = type(uint256).max; - vm.deal(marketMaker, maxInt); - vm.startPrank(marketMaker); + vm.deal(MM_ETHEREUM_WALLET_ADDRESS, maxInt); + vm.startPrank(MM_ETHEREUM_WALLET_ADDRESS); - yab_caller.transfer{value: maxInt}(1, 0x1, PaymentRegistry.Chain.ZKSync); - yab_caller.claimPaymentZKSync(1, 0x1, maxInt, 1, 1); + yab_caller.transfer{value: maxInt}(1, address(0x1), ZKSYNC_CHAIN_ID); + yab_caller.claimPaymentZKSync(1, address(0x1), maxInt, 1, 1); vm.stopPrank(); } function test_claimPayment_zk_minInt() public { - hoax(marketMaker, 1 wei); - yab_caller.transfer{value: 1}(1, 0x1, PaymentRegistry.Chain.ZKSync); - hoax(marketMaker, 1 wei); - yab_caller.claimPaymentZKSync(1, 0x1, 1, 1, 1); + hoax(MM_ETHEREUM_WALLET_ADDRESS, 1 wei); + yab_caller.transfer{value: 1}(1, address(0x1), ZKSYNC_CHAIN_ID); + hoax(MM_ETHEREUM_WALLET_ADDRESS, 1 wei); + yab_caller.claimPaymentZKSync(1, address(0x1), 1, 1, 1); } function test_claimPayment_fail_wrongChain() public { - hoax(marketMaker, 1 wei); - yab_caller.transfer{value: 1}(1, 0x1, PaymentRegistry.Chain.ZKSync); - hoax(marketMaker, 1 wei); + hoax(MM_ETHEREUM_WALLET_ADDRESS, 1 wei); + yab_caller.transfer{value: 1}(1, address(0x1), ZKSYNC_CHAIN_ID); + hoax(MM_ETHEREUM_WALLET_ADDRESS, 1 wei); vm.expectRevert("Transfer not found."); //Won't match to a transfer made on the other chain - yab_caller.claimPayment(1, 0x1, 1); + yab_caller.claimPaymentStarknet(1, address(0x1), 1); } } diff --git a/contracts/starknet/.env.example b/contracts/starknet/.env.example index 6b058d1f..3260783e 100644 --- a/contracts/starknet/.env.example +++ b/contracts/starknet/.env.example @@ -6,6 +6,5 @@ STARKNET_RPC= ## Required for Escrow Contract STARKNET_ESCROW_OWNER= #in lowercase hexa with the 0x prefix MM_STARKNET_WALLET_ADDRESS= #in lowercase hexa with the 0x prefix -CLAIM_PAYMENT_NAME= #must match the exact name of the function to claim the payment from the starknet smart contract MM_ETHEREUM_WALLET_ADDRESS= #in lowercase hexa with the 0x prefix NATIVE_TOKEN_ETH_STARKNET= #in lowercase hexa with the 0x prefix diff --git a/contracts/starknet/.env.test b/contracts/starknet/.env.test index 6dba7cfe..0d47a161 100644 --- a/contracts/starknet/.env.test +++ b/contracts/starknet/.env.test @@ -4,6 +4,5 @@ STARKNET_PRIVATE_KEY=0x180000000030000018000000000003000000000000300600180000660 STARKNET_RPC=http://0.0.0.0:5050 STARKNET_ESCROW_OWNER=0x517ececd29116499f4a1b64b094da79ba08dfd54a3edaa316134c41f8160973 MM_STARKNET_WALLET_ADDRESS=0x5686a647a9cdd63ade617e0baf3b364856b813b508f03903eb58a7e622d5855 -CLAIM_PAYMENT_NAME=claim_payment MM_ETHEREUM_WALLET_ADDRESS=0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 NATIVE_TOKEN_ETH_STARKNET=0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7 diff --git a/contracts/starknet/change_pause_state.sh b/contracts/starknet/scripts/change_pause_state.sh similarity index 89% rename from contracts/starknet/change_pause_state.sh rename to contracts/starknet/scripts/change_pause_state.sh index 44176c38..37de0287 100755 --- a/contracts/starknet/change_pause_state.sh +++ b/contracts/starknet/scripts/change_pause_state.sh @@ -1,5 +1,6 @@ #!/bin/bash + if [ -z "$STARKNET_ACCOUNT" ]; then echo "\n${RED}ERROR:${COLOR_RESET}" echo "STARKNET_ACCOUNT Variable is empty. Aborting execution.\n" @@ -15,7 +16,7 @@ fi # we avoid adding flags such as --account, --keystore, and --rpc. export STARKNET_ACCOUNT=$STARKNET_ACCOUNT export STARKNET_KEYSTORE=$STARKNET_KEYSTORE -# export STARKNET_RPC=$STARKNET_RPC #todo: this must remain commented until we find a reliable and compatible rpc +export STARKNET_RPC=$STARKNET_RPC if [ -z "$ESCROW_CONTRACT_ADDRESS" ]; then printf "\n${RED}ERROR:${COLOR_RESET}\n" diff --git a/contracts/starknet/deploy.sh b/contracts/starknet/scripts/deploy.sh similarity index 98% rename from contracts/starknet/deploy.sh rename to contracts/starknet/scripts/deploy.sh index 5cedaa36..7080c8ff 100755 --- a/contracts/starknet/deploy.sh +++ b/contracts/starknet/scripts/deploy.sh @@ -85,4 +85,3 @@ echo "\nIf you now wish to finish the configuration of this deploy, you will nee echo "export PAYMENT_REGISTRY_PROXY_ADDRESS=$PAYMENT_REGISTRY_PROXY_ADDRESS" echo "export ESCROW_CONTRACT_ADDRESS=$ESCROW_CONTRACT_ADDRESS" echo "make ethereum-set-escrow" -echo "make ethereum-set-claim-payment-selector" diff --git a/contracts/starknet/upgrade.sh b/contracts/starknet/scripts/upgrade.sh similarity index 90% rename from contracts/starknet/upgrade.sh rename to contracts/starknet/scripts/upgrade.sh index e255dbd7..9a2ddc2e 100755 --- a/contracts/starknet/upgrade.sh +++ b/contracts/starknet/scripts/upgrade.sh @@ -5,7 +5,7 @@ # we avoid adding flags such as --account, --keystore, and --rpc. export STARKNET_ACCOUNT=$STARKNET_ACCOUNT export STARKNET_KEYSTORE=$STARKNET_KEYSTORE -# export STARKNET_RPC=$STARKNET_RPC #todo: this must remain commented until we find a reliable and compatible rpc +export STARKNET_RPC=$STARKNET_RPC if [ -z "$ESCROW_CONTRACT_ADDRESS" ]; then printf "\n${RED}ERROR:${COLOR_RESET}\n" diff --git a/contracts/starknet/src/escrow.cairo b/contracts/starknet/src/escrow.cairo index d59af39f..60cdf1c4 100644 --- a/contracts/starknet/src/escrow.cairo +++ b/contracts/starknet/src/escrow.cairo @@ -31,7 +31,8 @@ trait IEscrow { #[starknet::contract] mod Escrow { - use super::{IEscrow, Order}; + use core::traits::Into; +use super::{IEscrow, Order}; use openzeppelin::{ access::ownable::OwnableComponent, @@ -243,18 +244,54 @@ mod Escrow { self.pausable.assert_not_paused(); let eth_transfer_contract_felt: felt252 = self.eth_transfer_contract.read().into(); assert(from_address == eth_transfer_contract_felt, 'Only PAYMENT_REGISTRY_CONTRACT'); - assert(self.orders_pending.read(order_id), 'Order claimed or nonexistent'); - let order = self.orders.read(order_id); - assert(order.recipient_address == recipient_address, 'recipient_address not match L1'); - assert(order.amount == amount, 'amount not match L1'); + _claim_payment(ref self, from_address, order_id, recipient_address, amount); + } + + #[l1_handler] + fn claim_payment_batch( + ref self: ContractState, + from_address: felt252, + orders: Array<(u256, EthAddress, u256)> + ) { + let eth_transfer_contract_felt: felt252 = self.eth_transfer_contract.read().into(); + assert(from_address == eth_transfer_contract_felt, 'Only PAYMENT_REGISTRY_CONTRACT'); + + let mut idx = 0; + + loop { + if idx >= orders.len() { + break; + } - self.orders_pending.write(order_id, false); - let payment_amount = order.amount + order.fee; + let (order_id, recipient_address, amount) = *orders.at(idx); - IERC20Dispatcher { contract_address: self.native_token_eth_starknet.read() } - .transfer(self.mm_starknet_wallet.read(), payment_amount); + _claim_payment(ref self, from_address, order_id, recipient_address, amount); - self.emit(ClaimPayment { order_id, address: self.mm_starknet_wallet.read(), amount }); + idx += 1; + }; } + + fn _claim_payment( + ref self: ContractState, + from_address: felt252, + order_id: u256, + recipient_address: EthAddress, + amount: u256 + ) { + assert(self.orders_pending.read(order_id), 'Order withdrew or nonexistent'); + + let order = self.orders.read(order_id); + assert(order.recipient_address == recipient_address, 'recipient_address not match L1'); + assert(order.amount == amount, 'amount not match L1'); + + self.orders_pending.write(order_id, false); + let payment_amount = order.amount + order.fee; + + // TODO: Might be best to transfer all at once + IERC20Dispatcher { contract_address: self.native_token_eth_starknet.read() } + .transfer(self.mm_starknet_wallet.read(), payment_amount); + + self.emit(ClaimPayment { order_id, address: self.mm_starknet_wallet.read(), amount }); + } } diff --git a/contracts/starknet/src/lib.cairo b/contracts/starknet/src/lib.cairo index 87cce74f..2e0fd740 100644 --- a/contracts/starknet/src/lib.cairo +++ b/contracts/starknet/src/lib.cairo @@ -10,7 +10,6 @@ mod mocks { mod mock_EVMFactsRegistry; mod mock_Escrow_changed_functions; mod mock_pausableEscrow; - } #[cfg(test)] @@ -19,6 +18,8 @@ mod tests { mod test_escrow_pause; mod test_escrow_upgrade; mod test_escrow_ownable; + mod test_escrow_claim; + mod utils { mod constants; } diff --git a/contracts/starknet/src/tests/test_escrow_allowance.cairo b/contracts/starknet/src/tests/test_escrow_allowance.cairo index f4febc7e..7b9e0b37 100644 --- a/contracts/starknet/src/tests/test_escrow_allowance.cairo +++ b/contracts/starknet/src/tests/test_escrow_allowance.cairo @@ -172,27 +172,4 @@ mod Escrow { let order_id = escrow.set_order(order); stop_prank(CheatTarget::One(escrow.contract_address)); } - - #[test] - fn test_fail_random_eth_user_calls_l1_handler() { - let (escrow, _) = setup(); - let data: Array = array![1, MM_ETHEREUM().into(), 3, 4]; - let mut payload_buffer: Array = ArrayTrait::new(); - data.serialize(ref payload_buffer); - let mut l1_handler = L1HandlerTrait::new( - contract_address: escrow.contract_address, - function_name: 'claim_payment', - ); - l1_handler.from_address = ETH_USER().into(); - - l1_handler.payload = payload_buffer.span(); - - // same as "Should Panic" but for the L1 handler function - match l1_handler.execute() { - Result::Ok(_) => panic_with_felt252('shouldve panicked'), - Result::Err(RevertedTransaction) => { - assert(*RevertedTransaction.panic_data.at(0) == 'Only PAYMENT_REGISTRY_CONTRACT', *RevertedTransaction.panic_data.at(0)); - } - } - } } diff --git a/contracts/starknet/src/tests/test_escrow_claim.cairo b/contracts/starknet/src/tests/test_escrow_claim.cairo new file mode 100644 index 00000000..485ebe60 --- /dev/null +++ b/contracts/starknet/src/tests/test_escrow_claim.cairo @@ -0,0 +1,331 @@ +mod Escrow { + use core::array::ArrayTrait; + use core::to_byte_array::FormatAsByteArray; + use core::serde::Serde; + use core::traits::Into; + use starknet::{EthAddress, ContractAddress}; + use integer::BoundedInt; + + use snforge_std::{declare, ContractClassTrait, L1Handler, L1HandlerTrait}; + use snforge_std::{CheatTarget, start_prank, stop_prank, start_warp, stop_warp}; + + use yab::mocks::mock_Escrow_changed_functions::{IEscrow_mock_changed_functionsDispatcher, IEscrow_mock_changed_functionsDispatcherTrait}; + use yab::mocks::mock_pausableEscrow::{IEscrow_mockPausableDispatcher, IEscrow_mockPausableDispatcherTrait}; + use yab::interfaces::IERC20::{IERC20Dispatcher, IERC20DispatcherTrait}; + use yab::escrow::{IEscrowDispatcher, IEscrowDispatcherTrait, Order}; + use yab::interfaces::IEVMFactsRegistry::{ + IEVMFactsRegistryDispatcher, IEVMFactsRegistryDispatcherTrait + }; + + use yab::tests::utils::{ + constants::EscrowConstants::{ + USER, OWNER, MM_STARKNET, MM_ETHEREUM, ETH_TRANSFER_CONTRACT, ETH_USER, ETH_USER_2, ETH_USER_3 + }, + }; + + use openzeppelin::{ + upgrades::{ + UpgradeableComponent, + interface::{IUpgradeable, IUpgradeableDispatcher, IUpgradeableDispatcherTrait} + }, + }; + + fn setup() -> (IEscrowDispatcher, IERC20Dispatcher) { + setup_general(BoundedInt::max(), BoundedInt::max()) + } + + fn setup_general(balance: u256, approved: u256) -> (IEscrowDispatcher, IERC20Dispatcher){ + let eth_token = deploy_erc20('ETH', '$ETH', BoundedInt::max(), OWNER()); + let escrow = deploy_escrow( + OWNER(), + ETH_TRANSFER_CONTRACT(), + MM_ETHEREUM(), + MM_STARKNET(), + eth_token.contract_address + ); + + start_prank(CheatTarget::One(eth_token.contract_address), OWNER()); + eth_token.transfer(USER(), balance); + stop_prank(CheatTarget::One(eth_token.contract_address)); + + start_prank(CheatTarget::One(eth_token.contract_address), USER()); + eth_token.approve(escrow.contract_address, approved); + stop_prank(CheatTarget::One(eth_token.contract_address)); + + (escrow, eth_token) + } + + fn deploy_escrow( + escrow_owner: ContractAddress, + eth_transfer_contract: EthAddress, + mm_ethereum_contract: EthAddress, + mm_starknet_contract: ContractAddress, + native_token_eth_starknet: ContractAddress + ) -> IEscrowDispatcher { + let escrow = declare('Escrow'); + let mut calldata: Array = ArrayTrait::new(); + calldata.append(escrow_owner.into()); + calldata.append(eth_transfer_contract.into()); + calldata.append(mm_ethereum_contract.into()); + calldata.append(mm_starknet_contract.into()); + calldata.append(native_token_eth_starknet.into()); + let address = escrow.deploy(@calldata).unwrap(); + return IEscrowDispatcher { contract_address: address }; + } + + fn deploy_erc20( + name: felt252, symbol: felt252, initial_supply: u256, recipent: ContractAddress + ) -> IERC20Dispatcher { + let erc20 = declare('ERC20'); + let mut calldata = array![name, symbol]; + Serde::serialize(@initial_supply, ref calldata); + calldata.append(recipent.into()); + let address = erc20.deploy(@calldata).unwrap(); + return IERC20Dispatcher { contract_address: address }; + } + + #[test] + fn test_claim_payment() { + let (escrow, eth_token) = setup(); + + // check balance + assert(eth_token.balanceOf(escrow.contract_address) == 0, 'init: wrong balance'); + assert(eth_token.balanceOf(MM_STARKNET()) == 0, 'init: wrong balance'); + + start_prank(CheatTarget::One(escrow.contract_address), USER()); + let order = Order { recipient_address: ETH_USER(), amount: 500, fee: 0 }; + let order_id = escrow.set_order(order); + stop_prank(CheatTarget::One(escrow.contract_address)); + + // check balance + assert(eth_token.balanceOf(escrow.contract_address) == 500, 'set_order: wrong balance '); + assert(eth_token.balanceOf(MM_STARKNET()) == 0, 'set_order: wrong balance'); + + // check Order + assert(order_id == 0, 'wrong order_id'); + let order_save = escrow.get_order(order_id); + assert(order.recipient_address == order_save.recipient_address, 'wrong recipient_address'); + assert(order.amount == order_save.amount, 'wrong amount'); + assert(escrow.get_order_pending(order_id), 'wrong order used'); + + let mut l1_handler = L1HandlerTrait::new( + contract_address: escrow.contract_address, + function_name: 'claim_payment' + ); + + let mut payload_buffer: Array = ArrayTrait::new(); + Serde::serialize(@order_id, ref payload_buffer); + Serde::serialize(@order.recipient_address, ref payload_buffer); + Serde::serialize(@order.amount, ref payload_buffer); + + l1_handler.from_address = ETH_TRANSFER_CONTRACT().into(); + l1_handler.payload = payload_buffer.span(); + + l1_handler.execute().expect('Failed to execute l1_handler'); + + // check Order + assert(!escrow.get_order_pending(order_id), 'wrong order used'); + // check balance + assert(eth_token.balanceOf(escrow.contract_address) == 0, 'withdraw: wrong balance'); + assert(eth_token.balanceOf(MM_STARKNET()) == 500, 'withdraw: wrong balance'); + } + + #[test] + fn test_claim_payment_batch() { + let (escrow, eth_token) = setup(); + + // check balance + assert(eth_token.balanceOf(escrow.contract_address) == 0, 'init: wrong balance'); + assert(eth_token.balanceOf(MM_STARKNET()) == 0, 'init: wrong balance'); + + let recipient_addresses = array![ETH_USER(), ETH_USER_2(), ETH_USER_3()]; + let amounts = array![500, 501, 502]; + let fees = array![3, 2, 1]; + + let recipient_adresses_clone = recipient_addresses.clone(); + let amounts_clone = amounts.clone(); + + let mut orders = array![]; + + start_prank(CheatTarget::One(escrow.contract_address), USER()); + + let mut idx = 0; + loop { + if idx >= 3 { + break; + } + + let recipient_address = recipient_addresses.at(idx).clone(); + let amount = amounts.at(idx).clone(); + let fee = fees.at(idx).clone(); + + let order_id = _create_order(recipient_address, amount, fee, escrow); + + orders.append((order_id, recipient_address, amount)); + + idx += 1; + }; + + // check balance + assert(eth_token.balanceOf(escrow.contract_address) == 1509, 'set_order: wrong balance '); + assert(eth_token.balanceOf(MM_STARKNET()) == 0, 'set_order: wrong balance'); + + // Call withdraw_batch l1_handler + let mut l1_handler = L1HandlerTrait::new( + contract_address: escrow.contract_address, + function_name: 'claim_payment_batch' + ); + + let mut payload_buffer: Array = ArrayTrait::new(); + Serde::serialize(@orders, ref payload_buffer); + + l1_handler.from_address = ETH_TRANSFER_CONTRACT().into(); + l1_handler.payload = payload_buffer.span(); + + l1_handler.execute().expect('Failed to execute l1_handler'); + + assert(eth_token.balanceOf(escrow.contract_address) == 0, 'withdraw: wrong balance'); + assert(eth_token.balanceOf(MM_STARKNET()) == 1509, 'withdraw: wrong balance'); + + // Check order_ids + let mut idx = 0; + loop { + if idx >= 3 { + break; + } + + let (order_id, _, _) = orders.at(idx).clone(); + assert(!escrow.get_order_pending(order_id), 'Order not used'); + idx += 1; + }; + } + + #[test] + fn test_claim_batch_fail_missing_order_id() { + let (escrow, eth_token) = setup(); + + let mut orders = array![]; + + let amount = 500; + let order_id = _create_order(ETH_USER(), amount, 1, escrow); + + orders.append((order_id, ETH_USER(), amount)); + orders.append((order_id + 1, ETH_USER_2(), amount)); + + // Call withdraw_batch l1_handler + let mut l1_handler = L1HandlerTrait::new( + contract_address: escrow.contract_address, + function_name: 'claim_payment_batch' + ); + + let mut payload_buffer: Array = ArrayTrait::new(); + Serde::serialize(@orders, ref payload_buffer); + + l1_handler.from_address = ETH_TRANSFER_CONTRACT().into(); + l1_handler.payload = payload_buffer.span(); + + // same as "Should Panic" but for the L1 handler function + match l1_handler.execute() { + Result::Ok(_) => panic_with_felt252('shouldve panicked'), + Result::Err(RevertedTransaction) => { + assert(*RevertedTransaction.panic_data.at(0) == 'Order withdrew or nonexistent', *RevertedTransaction.panic_data.at(0)); + } + } + } + + #[test] + fn test_fail_random_eth_user_calls_l1_handler() { + let (escrow, _) = setup(); + let data: Array = array![1, MM_ETHEREUM().into(), 3, 4]; + let mut payload_buffer: Array = ArrayTrait::new(); + data.serialize(ref payload_buffer); + let mut l1_handler = L1HandlerTrait::new( + contract_address: escrow.contract_address, + function_name: 'claim_payment', + ); + l1_handler.from_address = ETH_USER().into(); + + l1_handler.payload = payload_buffer.span(); + + // same as "Should Panic" but for the L1 handler function + match l1_handler.execute() { + Result::Ok(_) => panic_with_felt252('shouldve panicked'), + Result::Err(RevertedTransaction) => { + assert(*RevertedTransaction.panic_data.at(0) == 'Only PAYMENT_REGISTRY_CONTRACT', *RevertedTransaction.panic_data.at(0)); + } + } + } + + #[test] + fn test_fail_random_eth_user_calls_l1_handler_batch() { + let (escrow, eth_token) = setup(); + + assert(eth_token.balanceOf(escrow.contract_address) == 0, 'init: wrong balance'); + assert(eth_token.balanceOf(MM_STARKNET()) == 0, 'init: wrong balance'); + + let recipient_addresses = array![ETH_USER(), ETH_USER_2(), ETH_USER_3()]; + let amounts = array![500, 501, 502]; + let fees = array![3, 2, 1]; + + let recipient_adresses_clone = recipient_addresses.clone(); + let amounts_clone = amounts.clone(); + + let mut orders = array![]; + + start_prank(CheatTarget::One(escrow.contract_address), USER()); + + let mut idx = 0; + loop { + if idx >= 3 { + break; + } + + let recipient_address = recipient_addresses.at(idx).clone(); + let amount = amounts.at(idx).clone(); + let fee = fees.at(idx).clone(); + + let order_id = _create_order(recipient_address, amount, fee, escrow); + + orders.append((order_id, recipient_address, amount)); + + idx += 1; + }; + + // check balance + assert(eth_token.balanceOf(escrow.contract_address) == 1509, 'set_order: wrong balance '); + assert(eth_token.balanceOf(MM_STARKNET()) == 0, 'set_order: wrong balance'); + + // Call withdraw_batch l1_handler + let mut l1_handler = L1HandlerTrait::new( + contract_address: escrow.contract_address, + function_name: 'claim_payment_batch' + ); + + let mut payload_buffer: Array = ArrayTrait::new(); + Serde::serialize(@orders, ref payload_buffer); + + l1_handler.payload = payload_buffer.span(); + l1_handler.from_address = ETH_USER().into(); + + // same as "Should Panic" but for the L1 handler function + match l1_handler.execute() { + Result::Ok(_) => panic_with_felt252('shouldve panicked'), + Result::Err(RevertedTransaction) => { + assert(*RevertedTransaction.panic_data.at(0) == 'Only PAYMENT_REGISTRY_CONTRACT', *RevertedTransaction.panic_data.at(0)); + } + } + } + + fn _create_order( + recipient_address: EthAddress, + amount: u256, + fee: u256, + escrow: IEscrowDispatcher, + ) -> u256 { + start_prank(CheatTarget::One(escrow.contract_address), USER()); + let order = Order { recipient_address: recipient_address.try_into().unwrap(), amount: amount, fee: fee }; + let order_id = escrow.set_order(order); + stop_prank(CheatTarget::One(escrow.contract_address)); + return order_id; + } +} diff --git a/contracts/starknet/src/tests/utils/constants.cairo b/contracts/starknet/src/tests/utils/constants.cairo index 02729ee5..7e9c638a 100644 --- a/contracts/starknet/src/tests/utils/constants.cairo +++ b/contracts/starknet/src/tests/utils/constants.cairo @@ -24,4 +24,12 @@ mod EscrowConstants { fn ETH_USER() -> EthAddress { 99.try_into().unwrap() } + + fn ETH_USER_2() -> EthAddress { + 100.try_into().unwrap() + } + + fn ETH_USER_3() -> EthAddress { + 101.try_into().unwrap() + } } diff --git a/contracts/starknet_wallet_setup.md b/contracts/starknet/starknet_wallet_setup.md similarity index 89% rename from contracts/starknet_wallet_setup.md rename to contracts/starknet/starknet_wallet_setup.md index 5bb7e516..3dbfffc9 100644 --- a/contracts/starknet_wallet_setup.md +++ b/contracts/starknet/starknet_wallet_setup.md @@ -1,15 +1,14 @@ # Setting up a Starknet Testnet Wallet -**This guide will help you declare and deploy contracts on a testnet. Please -note that you won't be able to use the commands in the Makefile unless you -follow these instructions.** +Accounts on Starknet are not like in Ethereum. Instead, they are a smart contract that act as a wallet for the user (commonly referred as a Smart Wallet). -A smart wallet consists of two parts: a Signer and an Account Descriptor. The -Signer is a smart contract capable of signing transactions (for which we need -its private key). The Account Descriptor is a JSON file containing information +A smart wallet consists of two parts: a Signer and an Account Descriptor: +- The Signer is a smart contract capable of signing transactions (for which we need +its private key). +- The Account Descriptor is a JSON file containing information about the smart wallet, such as its address and public key. -Follow the steps below to set up a smart wallet using `starkli`: +## Follow the steps below to set up a smart wallet using `starkli`: 1. **Connect to a Provider**: to interact with the network you need an RPC Provider. For our project we will be using Alchemy's free tier in Goerli diff --git a/contracts/zksync/.gitignore b/contracts/zksync/.gitignore index 6144bb56..f690d704 100644 --- a/contracts/zksync/.gitignore +++ b/contracts/zksync/.gitignore @@ -79,7 +79,6 @@ typings/ # dotenv environment variables file .env -.env.test # parcel-bundler cache (https://parceljs.org/) .cache diff --git a/contracts/zksync/contracts/escrow.sol b/contracts/zksync/contracts/escrow.sol index 2df3e8c5..00e4a4c3 100644 --- a/contracts/zksync/contracts/escrow.sol +++ b/contracts/zksync/contracts/escrow.sol @@ -40,7 +40,6 @@ contract Escrow is Initializable, OwnableUpgradeable, PausableUpgradeable { //}, __Ownable_init(); // __UUPSUpgradeable_init(); - _current_order_id = 0; ethereum_payment_registry = ethereum_payment_registry_; mm_zksync_wallet = mm_zksync_wallet_; } @@ -93,6 +92,38 @@ contract Escrow is Initializable, OwnableUpgradeable, PausableUpgradeable { //}, emit ClaimPayment(order_id, mm_zksync_wallet, amount); } + // l1 handler + function claim_payment_batch( + uint256[] calldata order_ids, + address[] calldata recipient_addresses, + uint256[] calldata amounts + ) public whenNotPaused { + require(msg.sender == ethereum_payment_registry, 'Only PAYMENT_REGISTRY can call'); + require(order_ids.length == recipient_addresses.length, 'Invalid lengths'); + require(order_ids.length == amounts.length, 'Invalid lengths'); + + for (uint32 idx = 0; idx < order_ids.length; idx++) { + uint256 order_id = order_ids[idx]; + address recipient_address = recipient_addresses[idx]; + uint256 amount = amounts[idx]; + + require(_orders_pending[order_id], 'Order claimed or nonexistent'); + + Order memory current_order = _orders[order_id]; //TODO check if order is memory or calldata + require(current_order.recipient_address == recipient_address, 'recipient_address not match L1'); + require(current_order.amount == amount, 'amount not match L1'); + + _orders_pending[order_id] = false; + uint256 payment_amount = current_order.amount + current_order.fee; // TODO check overflow + + // TODO: Might be best to do only one transfer + (bool success,) = payable(address(uint160(mm_zksync_wallet))).call{value: payment_amount}(""); + require(success, "Transfer failed."); + + emit ClaimPayment(order_id, mm_zksync_wallet, amount); + } + } + function is_order_pending(uint256 order_id) public view returns (bool) { return _orders_pending[order_id]; } diff --git a/contracts/zksync/deploy.sh b/contracts/zksync/deploy.sh index 246c9ac8..6f5a6666 100755 --- a/contracts/zksync/deploy.sh +++ b/contracts/zksync/deploy.sh @@ -10,7 +10,7 @@ if [ -z "$PAYMENT_REGISTRY_PROXY_ADDRESS" ]; then fi DEPLOY="deploy" -if [ "$TEST" == true ]; then +if [ "$TEST" = true ]; then DEPLOY="deploy-devnet" fi @@ -18,7 +18,9 @@ export WALLET_PRIVATE_KEY=$WALLET_PRIVATE_KEY export PAYMENT_REGISTRY_PROXY_ADDRESS=$PAYMENT_REGISTRY_PROXY_ADDRESS export MM_ZKSYNC_WALLET=$MM_ZKSYNC_WALLET -ZKSYNC_ESCROW_CONTRACT_ADDRESS=$(yarn $DEPLOY | grep "Contract address:" | egrep -i -o '0x[a-zA-Z0-9]{40}') +RESULT_LOG=$(yarn $DEPLOY) +# echo $RESULT_LOG #uncomment this line for debugging +ZKSYNC_ESCROW_CONTRACT_ADDRESS=$(echo "$RESULT_LOG" | grep "Contract address:" | egrep -i -o '0x[a-zA-Z0-9]{40}') if [ -z "$ZKSYNC_ESCROW_CONTRACT_ADDRESS" ]; then printf "\n${RED}ERROR:${COLOR_RESET}\n" diff --git a/contracts/zksync/deploy/deploy.ts b/contracts/zksync/deploy/deploy.ts index 2ecd0726..3f7c505d 100644 --- a/contracts/zksync/deploy/deploy.ts +++ b/contracts/zksync/deploy/deploy.ts @@ -29,5 +29,5 @@ export default async function () { const initResult = await escrow.initialize(PaymentRegistryL2Alias, mm_zksync_wallet); - // console.log("Initialization result:", initResult); + console.log("Initialization result:", initResult); } diff --git a/contracts/zksync/deploy/utils.ts b/contracts/zksync/deploy/utils.ts index bffc4f1c..f63e2715 100644 --- a/contracts/zksync/deploy/utils.ts +++ b/contracts/zksync/deploy/utils.ts @@ -15,7 +15,7 @@ export const getProvider = () => { if (!rpcUrl) throw `⛔️ RPC URL wasn't found in "${hre.network.name}"! Please add a "url" field to the network config in hardhat.config.ts`; // Initialize zkSync Provider - const provider = new Provider(rpcUrl); + const provider = new Provider(rpcUrl, undefined, {cacheTimeout: -1}); return provider; } diff --git a/contracts/zksync/hardhat.config.ts b/contracts/zksync/hardhat.config.ts index 60d1be41..a40bf3d8 100644 --- a/contracts/zksync/hardhat.config.ts +++ b/contracts/zksync/hardhat.config.ts @@ -8,7 +8,7 @@ import "@matterlabs/hardhat-zksync-upgradable"; import "@nomicfoundation/hardhat-chai-matchers"; const config: HardhatUserConfig = { - defaultNetwork: "dockerizedNode", + defaultNetwork: "inMemoryNode", // defaultNetwork: "zkSyncSepoliaTestnet", networks: { zkSyncSepoliaTestnet: { @@ -35,7 +35,7 @@ const config: HardhatUserConfig = { zksync: true, }, inMemoryNode: { - url: "http://127.0.0.1:8011", + url: "http://localhost:8011", ethNetwork: "", // in-memory node doesn't support eth node; removing this line will cause an error zksync: true, }, diff --git a/contracts/zksync/package.json b/contracts/zksync/package.json index 5dd5554d..5648a349 100644 --- a/contracts/zksync/package.json +++ b/contracts/zksync/package.json @@ -7,7 +7,8 @@ "deploy-devnet": "hardhat deploy-zksync --network dockerizedNode --script deploy.ts", "compile": "hardhat compile", "clean": "hardhat clean", - "test": "hardhat test --network dockerizedNode --parallel --show-stack-traces" + "test": "hardhat test --network dockerizedNode --show-stack-traces", + "test-in-memory": "hardhat test --network inMemoryNode --show-stack-traces" }, "devDependencies": { "@matterlabs/hardhat-zksync-deploy": "^1.1.2", diff --git a/contracts/zksync/test/.env.test b/contracts/zksync/test/.env.test new file mode 100644 index 00000000..28afb666 --- /dev/null +++ b/contracts/zksync/test/.env.test @@ -0,0 +1,10 @@ +TEST=true + + +WALLET_PRIVATE_KEY=0x7726827caac94a7f9e1b160f7ea819f172f7b6f9d2a97f992c38edeab82d4110 #prefunded 0 +MM_ZKSYNC_WALLET=0xbE85c9531BE760B6964cdA4A8826b9Cb0391E32C #random address with no funds + +NATIVE_TOKEN_ETH_IN_ZKSYNC=0x000000000000000000000000000000000000800A + +USER_ZKSYNC_PRIVATE_ADDRESS=0xf12e28c0eb1ef4ff90478f6805b68d63737b7f33abfa091601140805da450d93 #prefunded 4 +USER_ZKSYNC_PUBLIC_ADDRESS=0x8002cD98Cfb563492A6fB3E7C8243b7B9Ad4cc92 #prefunded 4 diff --git a/contracts/zksync/test/claim_payment.sh b/contracts/zksync/test/claim_payment.sh deleted file mode 100755 index 5719557f..00000000 --- a/contracts/zksync/test/claim_payment.sh +++ /dev/null @@ -1,52 +0,0 @@ -#!/bin/bash - -. contracts/utils/colors.sh #for ANSI colors - -printf "${GREEN}\n=> [ETH] Making Claim Payment${COLOR_RESET}\n" - -MM_INITIAL_BALANCE_L1=$(cast balance --rpc-url $ETHEREUM_RPC --ether $MM_ETHEREUM_PUBLIC_ADDRESS) -echo "Initial MM balance L1:" -echo "$MM_INITIAL_BALANCE_L1" - -echo "Initial MM balance L2:" -npx zksync-cli wallet balance --chain "dockerized-node" --address "$MM_ZKSYNC_WALLET" | grep -E -o "\d+(\.\d+)? ETH" - -echo "Initial Escrow balance:" -npx zksync-cli wallet balance --chain "dockerized-node" --address "$ZKSYNC_ESCROW_CONTRACT_ADDRESS" | grep -E -o "\d+(\.\d+)? ETH" - - -echo "Withdrawing $BRIDGE_AMOUNT_ETH ETH" -echo "Withdrawing $BRIDGE_AMOUNT_WEI WEI" - -cast send --rpc-url $ETHEREUM_RPC --private-key $ETHEREUM_PRIVATE_KEY \ - $PAYMENT_REGISTRY_PROXY_ADDRESS "claimPaymentZKSync(uint256, uint256, uint256, uint256, uint256)" \ - "0" "$USER_ETHEREUM_PUBLIC_ADDRESS_UINT" "$BRIDGE_AMOUNT_WEI" "2000000000" "800"\ - --value 5000000000000000000 - -#ele pe eme -#me revertea con info: None -#no estoy seguro si existe un diamond proxy en la dada address. - - - -sleep 15 - - -MM_INITIAL_BALANCE_L1=$(cast balance --rpc-url $ETHEREUM_RPC --ether $MM_ETHEREUM_PUBLIC_ADDRESS) -echo "After MM balance L1:" -echo "$MM_INITIAL_BALANCE_L1" - -echo "After MM balance L2:" -npx zksync-cli wallet balance --chain "dockerized-node" --address "$MM_ZKSYNC_WALLET" | grep -E -o "\d+(\.\d+)? ETH" - -echo "After Escrow balance:" -npx zksync-cli wallet balance --chain "dockerized-node" --address "$ZKSYNC_ESCROW_CONTRACT_ADDRESS" | grep -E -o "\d+(\.\d+)? ETH" - - - -# starkli call $ESCROW_CONTRACT_ADDRESS get_order_pending u256:0 - -# ESCROW_FINAL_BALANCE=$(starkli balance $ESCROW_CONTRACT_ADDRESS) -# MM_FINAL_BALANCE=$(starkli balance $MM_SN_WALLET_ADDR) -# echo "Final Escrow balance: $ESCROW_FINAL_BALANCE" -# echo "Final MM balance: $MM_FINAL_BALANCE" diff --git a/contracts/zksync/test/main.test.ts b/contracts/zksync/test/main.test.ts index fff4259f..2f4007f1 100644 --- a/contracts/zksync/test/main.test.ts +++ b/contracts/zksync/test/main.test.ts @@ -1,9 +1,12 @@ import { expect } from 'chai'; import { deployAndInit } from './utils'; -import { Contract, Fragment, Wallet } from 'ethers'; -import { getWallet, deployContract, LOCAL_RICH_WALLETS } from '../deploy/utils'; +import { Contract, Fragment, Wallet, Provider } from 'ethers'; +import { getWallet, deployContract, LOCAL_RICH_WALLETS, getProvider } from '../deploy/utils'; +let provider: Provider; let escrow: Contract; +let paymentRegistry: Wallet = getWallet(LOCAL_RICH_WALLETS[3].privateKey); //its Wallet data type because I will mock calls from this addr + let deployer: Wallet = getWallet(LOCAL_RICH_WALLETS[0].privateKey); let user_zk: Wallet = getWallet(LOCAL_RICH_WALLETS[1].privateKey); let user_zk2: Wallet = getWallet(LOCAL_RICH_WALLETS[2].privateKey); @@ -11,17 +14,17 @@ let user_eth: Wallet = getWallet(LOCAL_RICH_WALLETS[1].privateKey); let user_eth2: Wallet = getWallet(LOCAL_RICH_WALLETS[2].privateKey); + const fee = 1; //TODO check, maybe make fuzz const value = 10; //TODO check, maybe make fuzz beforeEach( async () => { escrow = await deployAndInit(); + provider = getProvider(); }); -// /* -// working::: -describe('Pause tests', function () { +describe('Pause tests', function () { it("Should start unpaused", async function () { expect(await escrow.paused()).to.eq(false); }); @@ -60,33 +63,69 @@ describe('Pause tests', function () { await setPauseTx.wait(); await expect(escrow.set_order(user_eth, fee, {value})).to.be.revertedWith("Pausable: paused"); }); + + it("Should not allow when paused: claim_payment", async () => { + const setOrderTx = await escrow.connect(user_zk).set_order(user_eth, fee, {value}); + await setOrderTx.wait(); + + const setPauseTx = await escrow.pause(); + await setPauseTx.wait(); + + await expect(escrow.claim_payment(0, user_eth, value-fee)).to.be.revertedWith("Pausable: paused"); + }); }); -// */ -// // working :: + +describe('Ownable tests', function () { + it("Should not allow random user to pause", async () => { + await expect(escrow.connect(user_zk).pause()).to.be.revertedWith("Ownable: caller is not the owner"); + }); + + it("Should not allow random user to unpause", async () => { + const setPauseTx = await escrow.pause(); + await setPauseTx.wait(); + await expect(escrow.connect(user_zk).unpause()).to.be.revertedWith("Ownable: caller is not the owner"); + }); + + it("Should not allow random user to set_mm_zksync_wallet", async () => { + await expect(escrow.connect(user_zk).set_mm_zksync_wallet(user_zk)).to.be.revertedWith("Ownable: caller is not the owner"); + }); + + it("Should allow owner to set_mm_zksync_wallet", async () => { + const setTx = await escrow.set_mm_zksync_wallet(user_zk2); + await setTx.wait(); + + expect(await escrow.mm_zksync_wallet()).to.equals(user_zk2.address); + }); + + it("Should not allow random user to set_ethereum_payment_registry", async () => { + await expect(escrow.connect(user_zk).set_ethereum_payment_registry(user_eth)).to.be.revertedWith("Ownable: caller is not the owner"); + }); + + it("Should allow owner to set_ethereum_payment_registry", async () => { + const setTx = await escrow.set_ethereum_payment_registry(user_eth2); + await setTx.wait(); + + expect(await escrow.ethereum_payment_registry()).to.equals(user_eth2.address); + }); + +}) + describe('Set Order tests', function () { it("Should emit correct Event", async () => { - let events = await escrow.queryFilter("*"); - const events_length = events.length; - const setOrderTx = await escrow.connect(user_zk).set_order(user_eth, fee, {value}); - await setOrderTx.wait(); - - events = await escrow.queryFilter("*"); - expect(events.length).to.equal(events_length + 1); - expect(events[events.length - 1].fragment.name).to.equal("SetOrder"); + + await expect(setOrderTx) + .to.emit(escrow, "SetOrder").withArgs(0, user_eth, value-fee, fee) }); it("Should get the order setted", async () => { const setOrderTx = await escrow.connect(user_zk).set_order(user_eth, fee, {value}); - await setOrderTx.wait(); - - let events = await escrow.queryFilter("*"); - const newOrderEvent = events[events.length - 1]; - const orderId = newOrderEvent.args[0]; + await expect(setOrderTx) + .to.emit(escrow, "SetOrder").withArgs(0, user_eth, value-fee, fee) - const newOrder = await escrow.get_order(orderId); + const newOrder = await escrow.get_order(0); expect(newOrder[0]).to.eq(user_eth.address); //recipient_address expect(Number(newOrder[1])).to.eq(value-fee); //amount @@ -104,37 +143,59 @@ describe('Set Order tests', function () { }) }) -describe('Ownable tests', function () { - it("Should not allow random user to pause", async () => { - await expect(escrow.connect(user_zk).pause()).to.be.revertedWith("Ownable: caller is not the owner"); +describe('Claim Payment tests', function () { + it("Should allow PaymentRegistry to claim payment", async () => { + let mm_init_balance = await provider.getBalance(escrow.mm_zksync_wallet()); + + const setOrderTx = await escrow.connect(user_zk).set_order(user_eth, fee, {value}); + await setOrderTx.wait(); + + const claimPaymentTx = await escrow.connect(paymentRegistry).claim_payment(0, user_eth, value-fee); + await claimPaymentTx.wait(); + + let mm_final_balance = await provider.getBalance(escrow.mm_zksync_wallet()); + + expect(mm_final_balance - mm_init_balance).to.equals(value); }); - it("Should not allow random user to unpause", async () => { - const setPauseTx = await escrow.pause(); - await setPauseTx.wait(); - await expect(escrow.connect(user_zk).unpause()).to.be.revertedWith("Ownable: caller is not the owner"); + it("Should not allow PaymentRegistry to claim unexisting payment", async () => { + expect(escrow.connect(paymentRegistry).claim_payment(0, user_eth, value-fee)).to.be.revertedWith("Order claimed or nonexistent"); }); - it("Should not allow random user to set_mm_zksync_wallet", async () => { - await expect(escrow.connect(user_zk).set_mm_zksync_wallet(user_zk)).to.be.revertedWith("Ownable: caller is not the owner"); + it("Should not allow random user to call claim payment", async () => { + expect(escrow.connect(user_zk).claim_payment(0, user_eth, value)).to.be.revertedWith("Only PAYMENT_REGISTRY can call"); }); +}) - it("Should allow owner to set_mm_zksync_wallet", async () => { - const setTx = await escrow.set_mm_zksync_wallet(user_zk2); - await setTx.wait(); - expect(await escrow.mm_zksync_wallet()).to.equals(user_zk2.address); +describe('Claim payment batch tests', function () { + it("Should claim payment batch", async () => { + const setOrderTx = await escrow.connect(user_zk).set_order(user_eth, fee, {value}); + await setOrderTx.wait(); + + const setOrderTx2 = await escrow.connect(user_zk2).set_order(user_eth2, fee, {value}); + await setOrderTx2.wait(); + + await escrow.connect(deployer).set_mm_zksync_wallet(user_zk); + + const tx = await escrow.connect(paymentRegistry).claim_payment_batch([0, 1], [user_eth.address, user_eth2.address], [value-fee, value-fee]); + + await expect(tx) + .to.emit(escrow, "ClaimPayment").withArgs(0, user_zk.address, value-fee) + .to.emit(escrow, "ClaimPayment").withArgs(1, user_zk.address, value-fee); + + expect(await escrow.is_order_pending(0)).to.equal(false); }); - it("Should not allow random user to set_ethereum_payment_registry", async () => { - await expect(escrow.connect(user_zk).set_ethereum_payment_registry(user_eth)).to.be.revertedWith("Ownable: caller is not the owner"); + it("Should not claim payment batch when order missing", async () => { + await expect(escrow.connect(paymentRegistry).claim_payment_batch([0], [user_eth.address], [value-fee])).to.be.revertedWith("Order claimed or nonexistent"); }); - it("Should allow owner to set_ethereum_payment_registry", async () => { - const setTx = await escrow.set_ethereum_payment_registry(user_eth2); - await setTx.wait(); + it("Should not claim payment batch when not PAYMENT_REGISTRY", async () => { + const setOrderTx = await escrow.connect(user_zk).set_order(user_eth, fee, {value}); + await setOrderTx.wait(); - expect(await escrow.ethereum_payment_registry()).to.equals(user_eth2.address); + await expect(escrow.connect(user_eth).claim_payment_batch([0], [user_eth.address], [value-fee])).to.be.revertedWith("Only PAYMENT_REGISTRY can call"); }); +}); -}) diff --git a/contracts/zksync/test/set_order.sh b/contracts/zksync/test/set_order.sh deleted file mode 100755 index 1c2c5d58..00000000 --- a/contracts/zksync/test/set_order.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/bash -# cast call 0x97589bcE7727f5D0C8082440681DB6092b6Dda1a "getNames()(string)" --rpc-url http://localhost:8545 -# exit - -. contracts/utils/colors.sh #for ANSI colors - -FEE=10000000000000000 #in WEI -VALUE=2 #in ETH -VALUE_WEI=$(echo "scale=0; $VALUE * 10^18" | bc) -BRIDGE_AMOUNT_WEI=$(echo "scale=0; $VALUE_WEI - $FEE" | bc) -BRIDGE_AMOUNT_ETH=$(echo "scale=18; $BRIDGE_AMOUNT_WEI / 10^18" | bc) -# BRIDGE_AMOUNT_WEI=$(printf "%.0f" "$BRIDGE_AMOUNT_WEI") - - -printf "${GREEN}\n=> [SN] Making Set Order on Escrow${COLOR_RESET}\n" -echo "\nUser ZKSync funds before setOrder:" -npx zksync-cli wallet balance --chain "dockerized-node" --address "$USER_ZKSYNC_PUBLIC_ADDRESS" | grep -E -o "\d+(\.\d+)? ETH" -echo "\nEscrow ZKSync funds before setOrder:" -npx zksync-cli wallet balance --chain "dockerized-node" --address "$ZKSYNC_ESCROW_CONTRACT_ADDRESS" | grep -E -o "\d+(\.\d+)? ETH" - - -npx zksync-cli contract write --private-key $USER_ZKSYNC_PRIVATE_ADDRESS --chain "dockerized-node" --contract "$ZKSYNC_ESCROW_CONTRACT_ADDRESS" --method "set_order(address recipient_address, uint256 fee)" --args "$USER_ETHEREUM_PUBLIC_ADDRESS" "$FEE" --value "$VALUE" >> /dev/null - - -echo "\nUser ZKSync funds after setOrder:" -npx zksync-cli wallet balance --chain "dockerized-node" --address "$USER_ZKSYNC_PUBLIC_ADDRESS" | grep -E -o "\d+(\.\d+)? ETH" -echo "\nEscrow ZKSync funds after setOrder:" -npx zksync-cli wallet balance --chain "dockerized-node" --address "$ZKSYNC_ESCROW_CONTRACT_ADDRESS" | grep -E -o "\d+(\.\d+)? ETH" diff --git a/contracts/zksync/test/transfer.sh b/contracts/zksync/test/transfer.sh deleted file mode 100755 index f880e482..00000000 --- a/contracts/zksync/test/transfer.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/bash - -. contracts/utils/colors.sh #for ANSI colors - -# export DESTINATION_ADDRESS=0xceee57f2b700c2f37d1476a7974965e149fce2d4 -# export DESTINATION_ADDRESS_UINT=1181367337507422765615536123397692015769584198356 - -printf "${GREEN}\n=> [ETH] Making transfer to Destination account${COLOR_RESET}\n" - -MM_INITIAL_BALANCE=$(cast balance --rpc-url $ETHEREUM_RPC --ether $MM_ETHEREUM_PUBLIC_ADDRESS) -DESTINATION_INITIAL_BALANCE=$(cast balance --rpc-url $ETHEREUM_RPC --ether $USER_ETHEREUM_PUBLIC_ADDRESS) -echo "Initial MM balance: $MM_INITIAL_BALANCE" -echo "Initial Destination balance: $DESTINATION_INITIAL_BALANCE" - - -echo "Transferring $BRIDGE_AMOUNT_WEI WEI to $USER_ETHEREUM_PUBLIC_ADDRESS" - -cast send --rpc-url $ETHEREUM_RPC --private-key $MM_ETHEREUM_PRIVATE_KEY \ - $PAYMENT_REGISTRY_PROXY_ADDRESS "transfer(uint256, uint256, uint8)" \ - "0" "$USER_ETHEREUM_PUBLIC_ADDRESS_UINT" "1"\ - --value $BRIDGE_AMOUNT_WEI >> /dev/null - - - -MM_FINAL_BALANCE=$(cast balance --rpc-url $ETHEREUM_RPC --ether $MM_ETHEREUM_PUBLIC_ADDRESS) -DESTINATION_FINAL_BALANCE=$(cast balance --rpc-url $ETHEREUM_RPC --ether $USER_ETHEREUM_PUBLIC_ADDRESS) -echo "Final MM balance: $MM_FINAL_BALANCE" -echo "Final Destination balance: $DESTINATION_FINAL_BALANCE" diff --git a/contracts/zksync/test/utils.ts b/contracts/zksync/test/utils.ts index 40f88039..071e68d9 100644 --- a/contracts/zksync/test/utils.ts +++ b/contracts/zksync/test/utils.ts @@ -11,13 +11,12 @@ export async function deployAndInit(): Promise { const escrow = await deployContract("Escrow", [], { wallet: deployer }); - //TODO deploy paymentregistry on L1 local - const ethereum_payment_registry = "0x4337768cB3eC57Dd2cb843eFb929B773B13322de"; //process.env.PAYMENT_REGISTRY_PROXY_ADDRESS; + const ethereum_payment_registry = LOCAL_RICH_WALLETS[3].address; //semi-random address, prefunded to mock calls from this address + const mm_ethereum_wallet = process.env.MM_ZKSYNC_WALLET; const mm_zksync_wallet = process.env.MM_ZKSYNC_WALLET; - const native_token_eth_in_zksync = process.env.NATIVE_TOKEN_ETH_IN_ZKSYNC; - if (!ethereum_payment_registry || !mm_ethereum_wallet || !mm_zksync_wallet || !native_token_eth_in_zksync) { - console.log(ethereum_payment_registry,mm_ethereum_wallet,mm_zksync_wallet,native_token_eth_in_zksync); + if (!ethereum_payment_registry || !mm_ethereum_wallet || !mm_zksync_wallet) { + console.log(ethereum_payment_registry,mm_ethereum_wallet,mm_zksync_wallet); throw new Error("Missing required environment variables."); } @@ -26,11 +25,3 @@ export async function deployAndInit(): Promise { await initResult.wait(); return escrow } - -export async function deployPaymentRegistry(): Promise { - const deployer = getWallet(LOCAL_RICH_WALLETS[0].privateKey); - - const paymentRegistry = await deployContract("PaymentRegistry", [], { wallet: deployer }); - - return await paymentRegistry.wait() -} diff --git a/contracts/zksync/tests.md b/contracts/zksync/tests.md deleted file mode 100644 index 6c5ef4f6..00000000 --- a/contracts/zksync/tests.md +++ /dev/null @@ -1,14 +0,0 @@ -to run tests: - -first run a dockerized L1-L2 blockchains: -' -git clone https://github.com/matter-labs/local-setup.git - -cd local-setup - -run docker - -./start -' - -now from another terminal make zksync-tests diff --git a/docs/SUMMARY.md b/docs/SUMMARY.md index 1be0c436..3bb2d68b 100644 --- a/docs/SUMMARY.md +++ b/docs/SUMMARY.md @@ -14,15 +14,19 @@ * [📜 Introduction](contracts/README.md) -* [🏦 Escrow](contracts/escrow.md) +* [🏦 Escrow](contracts/escrow/escrow.md) + * [🏦 Starknet](contracts/escrow/starknet.md) + + * [🏦 Zksync](contracts/escrow/zksync.md) + * [🧾 Payment Registry](contracts/payment_registry.md) * [🔨 Deploy](contracts/deploy.md) -* [📈 Upgrade Contract](contracts/upgrade.md) +* [📈 Upgrade](contracts/upgrade.md) -* [⛔️ Pause Contract](contracts/pause.md) +* [⛔️ Pause](contracts/pause.md) ## Market Maker Bot diff --git a/docs/about_yab/FAQ.md b/docs/about_yab/FAQ.md index abe1b5be..f1506c93 100644 --- a/docs/about_yab/FAQ.md +++ b/docs/about_yab/FAQ.md @@ -2,8 +2,8 @@ ## What is YAB? -Yet Another Bridge (YAB) is the cheapest, fastest and most secure bridge -solution from Starknet to Ethereum. +Yet Another Bridge (YAB) is the cheapest, fastest and most secure bridge solution +from Starknet and ZKSync to Ethereum, and from Ethereum to Starknet and ZKSync ## What makes YAB different from other bridge solutions? @@ -35,9 +35,9 @@ bridge's final cost would be approximately $15. ## What chains are currently supported? -Currently, Starknet is the only supported chain. +Both Starknet and ZKSync are supported by YAB. -We are working on integrating ZkSync in the near future, so stay tuned for further updates! +We are working on integrating almost every other rollup in the near future, so stay tuned for further updates! ## How can I get in touch with the team? diff --git a/docs/contracts/README.md b/docs/contracts/README.md index 8e11b02f..d6a78fc3 100644 --- a/docs/contracts/README.md +++ b/docs/contracts/README.md @@ -7,7 +7,7 @@ Smart Contract on L2 Starknet blockchain YAB's functionality is the Market Maker (MM for short). In the following sections, you will find information about: -- [Escrow](escrow.md) +- [Escrow](./escrow/escrow.md) - [Payment Registry](payment_registry.md) - [Deploy](deploy.md) - [Upgrade Contract](upgrade.md) diff --git a/docs/contracts/deploy.md b/docs/contracts/deploy.md index ff31981d..f053f7e9 100644 --- a/docs/contracts/deploy.md +++ b/docs/contracts/deploy.md @@ -20,9 +20,11 @@ Another starknet dependency used in this project: - [OpenZeppelin cairo contracts](https://github.com/OpenZeppelin/cairo-contracts/) +[comment]: TODO add install ZKSync dockerized L1-L2 or in-memory-node if/when necessary, for make tests + ## Deploy Payment Registry (on Ethereum) -First, the Ethereum smart contract must be deployed. For Ethereum the deployment process +First, the Ethereum Payment Registry must be deployed. For Ethereum the deployment process you will need to: 1. Create your `.env` file: you need to configure the following variables in your own @@ -36,37 +38,60 @@ template for creating your .env file, paying special attention to the formats pr ETHERSCAN_API_KEY = API Key to use etherscan to read the Ethereum blockchain - STARKNET_MESSAGING_ADDRESS = Starknet Messaging address - MM_ETHEREUM_WALLET_ADDRESS = Ethereum wallet address of the MarketMaker + + STARKNET_MESSAGING_ADDRESS = Starknet Messaging address in L1 + + STARKNET_CLAIM_PAYMENT_SELECTOR = hex value of starknet\'s claim_payment selector + + STARKNET_CLAIM_PAYMENT_BATCH_SELECTOR = hex value of starknet\'s claim_payment_batch selector + + ZKSYNC_DIAMOND_PROXY_ADDRESS = ZKSync Diamond Proxy address in L1 + + ZKSYNC_CLAIM_PAYMENT_SELECTOR = hex value of ZKSync\'s claim_payment selector + + ZKSYNC_CLAIM_PAYMENT_BATCH_SELECTOR = hex value of ZKSync\'s claim_payment_batch selector ``` **NOTE**: - You can generate ETHERSCAN_API_KEY [following these steps](https://docs.etherscan.io/getting-started/creating-an-account). - For the deployment, you will need some ETH. - - You can get some GoerliEth from this [faucet](https://goerlifaucet.com/). + - You can get some SepoliaETH from [Infura](https://www.infura.io/faucet/sepolia) or [Alchemy](https://www.alchemy.com/faucets/ethereum-sepolia). - STARKNET_MESSAGING_ADDRESS is for when a L1 contract initiates a message to a L2 contract on Starknet. It does so by calling the sendMessageToL2 function on the Starknet Core Contract with the message parameters. Starknet Core Contracts are the following: - - Goerli: `0xde29d060D45901Fb19ED6C6e959EB22d8626708e` - Sepolia: `0xE2Bb56ee936fd6433DC0F6e7e3b8365C906AA057` - Mainnet: `0xc662c410C0ECf747543f5bA90660f6ABeBD9C8c4` + - ZKSYNC_DIAMOND_PROXY_ADDRESS is for when a L1 contract initiates a message to a L2 contract on ZKSync. It does so by calling the requestL2Transaction function on the ZKSync Core Contract with the message parameters. ZKSync Diamond Proxy's addresses are the following: + - Sepolia: `0x9A6DE0f62Aa270A8bCB1e2610078650D539B1Ef9` + - Mainnet: `0x32400084C286CF3E17e7B677ea9583e60a000324` + - You can generate the STARKNET_CLAIM_PAYMENT_SELECTOR value and the STARKNET_CLAIM_PAYMENT_BATHC_SELECTOR with `starkli`, by running, for example: + ```bash + starkli selector claim_payment + starkli selector claim_payment_batch + ``` + + - You can generate the ZKSYNC_CLAIM_PAYMENT_SELECTOR and the ZKSYNC_CLAIM_PAYMENT_BATCH_SELECTOR value by using `cast sig`, by running, for example: + ```bash + cast sig "claim_payment(uint256 order_id, address recipient_address, uint256 amount)" + cast sig "claim_payment_batch(uint256[] order_ids, address[] recipient_addresses, uint256[] amounts)" + ``` 2. Deploy Ethereum contract ```bash - make ethereum-deploy + make ethereum-deploy ``` This will deploy a [ERC1967 Proxy](https://docs.openzeppelin.com/contracts/4.x/api/proxy#ERC1967Proxy) smart contract, a [Payment Registry](../../contracts/ethereum/src/PaymentRegistry.sol) smart contract, and it will link them both. The purpose of having a proxy in front of our -smart contract is so that it is [upgradeable](https://docs.openzeppelin.com/contracts/4.x/api/proxy#UUPSUpgradeable), by simply deploying another smart +Payment Registry is so that it is [upgradeable](https://docs.openzeppelin.com/contracts/4.x/api/proxy#UUPSUpgradeable), by simply deploying another smart contract and changing the address pointed by the Proxy. ## Deploy Escrow (on Starknet) -After the Ethereum smart contract is deployed, the Starknet smart contracts must be +After the Ethereum Payment Registry is deployed, the Starknet Escrow must be declared and deployed. On Starknet, the deployment process is in two steps: @@ -79,10 +104,10 @@ On Starknet, the deployment process is in two steps: For this, you will need to: 1. Create your `.env` file: you need to configure the following variables in your own -.env file on the contracts/ethereum folder. You can use the env.example file as a +.env file on the contracts/starknet folder. You can use the env.example file as a template for creating your .env file, paying special attention to the formats provided - ```env + ```bash STARKNET_ACCOUNT = Absolute path of your starknet testnet account STARKNET_KEYSTORE = Absolute path of your starknet testnet keystore @@ -93,9 +118,6 @@ template for creating your .env file, paying special attention to the formats pr MM_STARKNET_WALLET_ADDRESS = Starknet wallet of the MarketMaker - CLAIM_PAYMENT_NAME = Exact name of the claim_payment function that is called from L1, case sensitive. - Example: claim_payment - MM_ETHEREUM_WALLET_ADDRESS = Ethereum wallet of the MarketMaker NATIVE_TOKEN_ETH_STARKNET = Ethereum's erc20 token handler contract in Starknet @@ -107,31 +129,31 @@ template for creating your .env file, paying special attention to the formats pr deployer of the smart contract. 2. Declare and Deploy: We sequentially declare and deploy the contracts, and connect it -to our Ethereum smart contract. +to our Ethereum Payment Registry. ### First alternative: automatic deploy and connect of Escrow and Payment Registry ```bash - make starknet-deploy-and-connect + make starknet-deploy-and-connect ``` - This make target consists of 4 steps: + This make target consists of 3 steps: 1. make starknet-build; builds the project - 2. make starknet-deploy; deploys the smart contract on the blockchain + 2. make starknet-deploy; deploys the Escrow on the Starknet blockchain 3. make ethereum-set-escrow; sets the newly created Starknet contract address on the -Ethereum smart contract, so that the L1 contract can communicate with the L2 contract - 4. make ethereum-set-claim-payment-selector; sets the Starknet _claim_payment_ function name on -the Ethereum smart contract, so that the L1 contract can communicate with the L2 contract +Ethereum Payment Registry, so that the L1 contract can communicate with the L2 contract ### Second alternative: manual deploy and connect of Escrow and Payment Registry This may be better suited for you if you plan to change some of the automatically declared variables, or if you simply want to make sure you understand the process. +
+Steps 1. Declare and Deploy - We sequentially declare and deploy the contracts. + We sequentially declare and deploy the contracts. This also builds the project beforehand. ```bash make starknet-deploy @@ -141,9 +163,9 @@ declared variables, or if you simply want to make sure you understand the proces 2. Setting _EscrowAddress_ - After the Starknet smart contracts are declared and deployed, the variable -_EscrowAddress_ from the Ethereum smart contract must be updated with the newly created -Starknet smart contract address. + After the Starknet Escrow is declared and deployed, the variable +_EscrowAddress_ from the Ethereum Payment Registry must be updated with the newly created +Starknet Escrow address. To do this, you can use @@ -152,24 +174,91 @@ Starknet smart contract address. ``` This script uses the previously set variable, **ESCROW_CONTRACT_ADDRESS** +
-3. Setting _EscrowClaimPaymentSelector_ - Ethereum's smart contract has another variable that must be configured, -_EscrowClaimPaymentSelector_, which is for specifying the _claim_payment_ function's name in the -Starknet Escrow smart contract. +## Deploy Escrow (on ZKSync) - You can set and change Ethereum's _EscrowClaimPaymentSelector_ variable, doing the following: +After the Ethereum Payment Registry is deployed, the ZKSync Escrow must be deployed. + +For this, you will need to: + +1. Create your `.env` file: you need to configure the following variables in your own +.env file on the contracts/zksync folder. You can use the env.example file as a +template for creating your .env file, paying special attention to the formats provided ```bash - make ethereum-set-claim-payment-selector + WALLET_PRIVATE_KEY = Private key of the deployer + + MM_ZKSYNC_WALLET = Public address of the Market Maker in ZKSync ``` - This script uses the CLAIM_PAYMENT_NAME .env variable to automatically generate the -selector in the necessary format +2. We deploy the contract, and connect it to our Ethereum Payment Registry. + +### First alternative: automatic deploy and connect of Escrow and Payment Registry + + ```bash + make zksync-deploy-and-connect + ``` + + This make target consists of 3 steps: + + 1. make zksync-build; builds the project + 2. make zksync-deploy; deploys the Escrow on the ZKSync blockchain + 3. ./set_zksync_escrow.sh; sets the newly created ZKSync contract address on the +Ethereum Payment Registry, so that the L1 contract can communicate with the L2 contract + +### Second alternative: manual deploy and connect of Escrow and Payment Registry + +This may be better suited for you if you plan to change some of the automatically +declared variables, or if you simply want to make sure you understand the process. + +
+Steps +1. Declare and Deploy + + We sequentially declare and deploy the contracts. This also builds the project beforehand. + + ```bash + make zksync-deploy + ``` + + This script also defines an important variable, **ZKSYNC_ESCROW_CONTRACT_ADDRESS** + +2. Setting _ZKSyncEscrowAddress_ + + After the ZKSync Escrow is deployed, the variable _ZKSyncEscrowAddress_ from the Ethereum Payment Registry must be updated with the newly created ZKSync Escrow address, to connect these both smart contracts. + + To do this, you can use + + ```bash + make zksync-connect + ``` + + This script uses the previously set variable, **ZKSYNC_ESCROW_CONTRACT_ADDRESS** +
+ ## Recap -At this point, we should have deployed an ETH smart contract as well as declared and -deployed a Starknet smart contract, both connected to act as a bridge between these -two chains. +At this point, we should have deployed an Ethereum smart contract, Payment Registry, as well as declared and deployed 2 L2 Escrows, one on Starknet and another one on ZKSync, both connected to Ethereum Payment Registry to act as a bridge between these chains. + +## More deploy targets + +There also exists more make targets that can help us deploy more easily and more quickly our smart contracts. Once we have correctly configured out _.env_ files, as explained above, we can use the following make targets: + +To deploy only our Ethereum Payment Registry and our Escrow on Starknet: +```bash +make ethereum-and-starknet-deploy +``` + +To deploy only our Ethereum Payment Registry and our Escrow on ZKSync: +```bash +make ethereum-and-zksync-deploy +``` + +To deploy everything stated above, our Ethereum Payment Registry, an Escrow on Starknet and another Escrow on ZKSync: +```bash +make deploy-all +``` + diff --git a/docs/contracts/escrow.md b/docs/contracts/escrow.md deleted file mode 100644 index f46e3cde..00000000 --- a/docs/contracts/escrow.md +++ /dev/null @@ -1,27 +0,0 @@ -# Escrow - -[Escrow](../../contracts/cairo/src/escrow.cairo) is a Smart Contract written in Cairo that resides in Ethereum's L2 Starknet. - -This contract is responsible for receiving Users' payments in L2, and liberating them -to the MM when, and only when, the MM has proved the L1 payment. - -This contract has a storage of all orders. When a new order is made, by calling the -`set_order` function, this contract reads the new order's details, verifies the Order -is acceptable, and if so, it stores this data and accepts from the sender the -appropriate amount of tokens. An Order's details are: the address where the User wants -to receive the transaction on L1, the amount he wants to receive, and the amount he is -willing to give the MM to concrete the bridge process. - -Once Escrow has accepted the new order, it will emit a `SetOrder` event, containing -this information so that MMs can decide if they want to accept this offer. - -The user must wait until an MM picks its order, which should be almost instantaneous -if the transfer fee is the suggested one. - -After an MM consolidates an order, Escrow will receive a `claim_payment` call from -Payment Registry, containing the information about how MM has indeed bridged the funds -to the User's L1 address, and where does MM want to receive it's L2 tokens. Escrow -will then cross-check this information to its own records, and if everything is in -check, Escrow will transfer the bridged amount of tokens, plus the fee, to MM's L2 -address. - diff --git a/docs/contracts/escrow/escrow.md b/docs/contracts/escrow/escrow.md new file mode 100644 index 00000000..ae5f03dd --- /dev/null +++ b/docs/contracts/escrow/escrow.md @@ -0,0 +1,32 @@ +# Escrow + +The Escrow is a Smart Contract that can reside in any Ethereum L2. + +This contract is responsible for receiving Users' payments in L2, and liberating them +to the MM when, and only when, the MM has proved the payment in L1. + +This contract has a storage of all orders. When a new order is made, by calling the +`set_order` function, this contract reads the new order's details, verifies the Order +is acceptable, and if so, stores this data and accepts from the sender the +appropriate amount of tokens. + +An Order's details are: +- The address where the User wants to receive the transaction on L1 +- The amount he wants to receive +- The amount he is willing to give the MM as fee to concrete the bridge process + +Once Escrow has accepted the new order, it will emit a `SetOrder` event, containing +this information so that MMs can decide if they want to accept this offer. + +The user must wait until an MM picks its order, which should be almost instantaneous +if the transfer fee is the suggested one. + +After an MM consolidates an order, Escrow will receive a `claim_payment` call from the Payment Registry, using the native mesagging system of the rollup, containing the information about how MM has indeed bridged the funds to the User's L1 address, and where does MM want to receive it's L2 tokens. + +Escrow will then cross-check this information to its own records, and if everything is in +check, Escrow will transfer the bridged amount of tokens, plus the fee, to MM's L2 +address. + +Currently, we have 2 implementations of this contract, for 2 different Ethereum L2 Rollups: +- For [Starknet](https://www.starknet.io/en) we have [escrow.cairo](../../../contracts/starknet/src/escrow.cairo), with [its own readme](./Starknet.md) +- For [ZKSync](https://zksync.io/) we have [escrow.sol](../../../contracts/zksync/contracts/escrow.sol), with [its own readme](./ZKSync.md) diff --git a/docs/contracts/escrow/starknet.md b/docs/contracts/escrow/starknet.md new file mode 100644 index 00000000..964296e0 --- /dev/null +++ b/docs/contracts/escrow/starknet.md @@ -0,0 +1,75 @@ +# Escrow.cairo + +[Escrow.cairo](../../contracts/cairo/src/escrow.cairo) is a Smart Contract written in Cairo that resides in Ethereum's L2 [Starknet](https://www.starknet.io/en), and is our implementation of our bridge's [Escrow](./Escrow.md) entity for this L2. + +## Project Layout + +- `/src`: Contains source files, Cairo smart contracts. + - `/src/test` & `/src/mocks`: Test files. +- `/target`: Autogenerated output files. +- `/scripts`: Scripts for contract deployment and interaction. +- `/`: Config files + +## How to Use + +- `make deps`: Installs dependencies +- `make starknet-build`: Compiles contracts. +- `make starknet-deploy`: Deploys using script `/deploy/deploy.ts`. +- `make starknet-connect`: Connects itself to saved PaymentRegistry address. +- `make starknet-deploy-and-connect`: Deploys and connects itself to saved PaymentRegistry address. +- `make ethereum-and-starknet-deploy`: Deploys both smart contracts and connects them to each other. +- `make starknet-test`: Runs local tests + +## How does a User set a new order? + +This contract recieves User's new orders with the function: +``` +fn set_order(ref self: ContractState, order: Order) -> u256 +``` + +Which recieves an `Order` structure: +```cairo +struct Order { + recipient_address: EthAddress, + amount: u256, + fee: u256 +} +``` + +And returns the new order's ID. + +## How does a MM detect a User's new order? + +When a new order is set, the following SetOrder Event is emitted, detectable by MM's: +```cairo +struct SetOrder { + order_id: u256, + recipient_address: EthAddress, + amount: u256, + fee: u256 +} +``` + +## How does a MM claim his payment? + +The `claim_payment` function is called, only by our [Payment Registry](../payment_registry.md), in order for the MM to retrieve its payment from the Escrow: +```cairo +#[l1_handler] +fn claim_payment( + ref self: ContractState, + from_address: felt252, + order_id: u256, + recipient_address: EthAddress, + amount: u256 +) +``` + +Alternatevly, the `claim_payment_batch` function is called, only by our [Payment Registry](../payment_registry.md), in order for the MM to retrieve many payments from the Escrow at once: +```cairo +#[l1_handler] +fn claim_payment_batch( + ref self: ContractState, + from_address: felt252, + orders: Array<(u256, EthAddress, u256)> +) +``` \ No newline at end of file diff --git a/docs/contracts/escrow/zksync.md b/docs/contracts/escrow/zksync.md new file mode 100644 index 00000000..1a0e6902 --- /dev/null +++ b/docs/contracts/escrow/zksync.md @@ -0,0 +1,78 @@ +# Escrow.sol + +[Escrow.sol](../../../contracts/zksync/contracts/escrow.sol) is a Smart Contract written in Solidity that resides in Ethereum's L2 [ZKSync](https://zksync.io/), and is our implementation of our bridge's [Escrow](./Escrow.md) entity for this L2. + +## Project Layout + +- `/contracts`: Contains source files, solidity smart contracts. +- `/deploy`: Scripts for contract deployment and interaction. +- `/test`: Test files. +- `/artifacts-zk`: Autogenerated with required libraries. +- `hardhat.config.ts`: Configuration settings. + +## How to Use + +- `make deps`: Installs dependencies +- `make zksync-build`: Compiles contracts. +- `make zksync-deploy`: Deploys using script `/deploy/deploy.ts`. +- `make zksync-connect`: Connects itself to saved PaymentRegistry address. +- `make zksync-deploy-and-connect`: Deploys and connects itself to saved PaymentRegistry address. +- `make ethereum-and-zksync-deploy`: Deploys both smart contracts and connects them to each other. + +### Local Tests + +To run local tests you should first start a local dockerized node. For this you can: +```bash +git clone https://github.com/matter-labs/local-setup.git +cd local-setup +./start.sh +``` + +Then, to run the contract's tests: +```bash +make zksync-test +``` + +### About Network Support: + +`hardhat.config.ts` comes with a list of networks to deploy and test contracts. Add more by adjusting the `networks` section in the `hardhat.config.ts`. To make a network the default, set the `defaultNetwork` to its name. + +You can also override the default using the `--network` option. For example: +`hardhat test --network dockerizedNode`. + +## How does a User set a new order? + +This contract recieves User's new orders with the function: +```solidity +function set_order(address recipient_address, uint256 fee) public payable whenNotPaused returns (uint256) +``` + +Which returns the new order's ID. + +## How does a MM detect a User's new order? + +When a new order is set, the following SetOrder Event is emitted, detectable by MM's: +```solidity +event SetOrder(uint256 order_id, address recipient_address, uint256 amount, uint256 fee); +``` + +## How does a MM claim his payment? + +The `claim_payment` function is called, only by our [Payment Registry](../payment_registry.md), in order for the MM to retrieve its payment from the Escrow: +```solidity +function claim_payment( + uint256 order_id, + address recipient_address, + uint256 amount +) public whenNotPaused +``` + +Alternatevly, the `claim_payment_batch` function is called, only by our [Payment Registry](../payment_registry.md), in order for the MM to retrieve many payments from the Escrow at once: +```solidity +function claim_payment_batch( + uint256[] calldata order_ids, + address[] calldata recipient_addresses, + uint256[] calldata amounts +) public whenNotPaused +``` + diff --git a/docs/contracts/upgrade.md b/docs/contracts/upgrade.md index d5374bcd..ba03a42f 100644 --- a/docs/contracts/upgrade.md +++ b/docs/contracts/upgrade.md @@ -84,3 +84,5 @@ for deployment is necessary: - Call the external **upgrade()** function, from [OpenZeppellin's Upgradeable implementation](https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.8.0/src/upgrades/upgradeable.cairo), with the new class hash +## Upgrade ZKSync +[comment]: TODO, add when ZKSync is Upgradeable \ No newline at end of file diff --git a/docs/mm_bot/README.md b/docs/mm_bot/README.md index d0738324..15d5df41 100644 --- a/docs/mm_bot/README.md +++ b/docs/mm_bot/README.md @@ -3,6 +3,26 @@ Market Maker Bot is a bot that provides liquidity to the Yet Another Bridge (YAB). -In the following sections, you will find information about: -- [Architecture](architecture.md) -- [Deploy](deploy.md) +When a user wants to bridge tokens using YAB, the user must call the `set_order` function from the Escrow contract. +If successful, the Escrow emits a `SetOrder` event with the newly placed order information. + +The Market Maker Bot listens to the `SetOrder` events and creates a new order in its database. +This way, the Market Maker Bot is able to fulfill all user's order. + +Once an order is fulfuilled, when the user has received the tokens in his desired destination chain, +the Market Maker will be able to claim his corresponding tokens from the Escrow in the source chain. + +When the Market Maker claims its tokens, the Escrow will send the tokens to the Market Maker's address and emit a `ClaimPayment` event. +The order is then marked as completed in the Market Maker's database. + +## Architecture +In the [Architecture](architecture.md) section you can find the following information: +- Functional Requirements +- Class Diagrams +- Non-Functional Requirements +- Main Architecture Components +- Infrastructure +- Scenarios + +## Deploy +If you want to deploy a Market Maker Bot, the [Deploy](deploy.md) section explains how to do it. diff --git a/docs/mm_bot/architecture.md b/docs/mm_bot/architecture.md index 51e891cc..6ba65f1d 100644 --- a/docs/mm_bot/architecture.md +++ b/docs/mm_bot/architecture.md @@ -16,12 +16,16 @@ The following diagram shows the mm classes and how they interact with each other ![mm_diagram_class.svg](images%2Fmm_diagram_class.svg) +> **_NOTE:_** To make the diagram more readable, some relationships were omitted. + ### Full Class Diagram The following diagram is a detailed version of the previous diagram, showing the attributes and methods of each class. ![mm_diagram_class_full.svg](images%2Fmm_diagram_class_full.svg) +> **_NOTE:_** To make the diagram more readable, some relationships were omitted. + ## Process View ### Non-Functional Requirements - The bot must be able to handle multiple orders concurrently. @@ -36,30 +40,37 @@ The bot architecture is as follows: ![architecture.png](images/architecture.png) -The bot is composed of the following components: -- **Main Process**: The main process of the bot. It has the following subcomponents: - - `Main Order Indexer`: The `Main Order Indexer` is responsible for indexing the orders from - the pending blocks. - - `Order Processor`: Responsible for processing the orders. - - `Failed Orders Processor`: Responsible for retrying the failed orders. - It runs every 5 minutes. - - `Accepted Blocks Processor`: Responsible for indexing the orders that belong to accepted blocks. It runs every 5 minutes. -- **Database**: The database is used to store the following data: - - Orders - - Errors - - Block numbers - -An important aspect of the bot is that it must be able to handle multiple orders concurrently. +One `Orders Processor` is needed to process the orders for each L2. +Each `Orders Processor` has an `Orders Indexer` and an `Order Executor`. + +The `Orders Indexer` is responsible for indexing the orders made on the L2 Escrow. It indexes orders by reading Escrow's events, +and when it finds a new order, it stores it in the database. Then, `Orders Processor` is able to assign the new order +to an `Order Executor`. + +The `Order Executor` is responsible for processing an individual order. This means, it will transfer the funds to the +recipient in L1 and claim the funds in L2. + +To ensure that the orders are not lost, the bot has an `Accepted Blocks Processor` that indexes the orders that belong +to already accepted blocks, and stores them in the database. This way, if the `Orders Processor` looses an order, it will be +captured and processed by the `Accepted Blocks Processor`. + +The bot has a `Failed Orders Processor` that is responsible for retrying the failed orders. When an order fails, the bot +stores the error, and marks the order as failed. This way, the `Failed Orders Processor` will be able to retry any failed order. + +An important aspect of this bot is that it must be able to process multiple orders at the same time. For that reason, the bot uses the library 'asyncio' to handle orders concurrently. This approach, preferred over using threads, is particularly suitable for the bot's I/O-bound nature and the potential high volume of orders it could potentially need to manage. Another important requirement is that the bot must have a reliable network connection to communicate -with Ethereum's and L2 networks' RPCs. +with Ethereum's and the L2 networks' RPCs. Accordingly, the bot has two RPC providers for each network. If the +primary provider fails, the bot will switch to the secondary provider. ## Physical View -There is a server to run the MM Bot Main Process as well as its -database. +A server is needed to run the MM Bot's Main Process. + +Also, two servers are needed for the database, one for the main database and another one to act as its read replica. +This read replica is for external applications, like transaction explorers or data analyzers, so that these don't affect the main database's performance and/or implicate any security concerns. ![physical_view.png](images/physical_view.png) @@ -74,9 +85,6 @@ And each has the following states: ![state_diagram.svg](images%2Fstate_diagram.svg) ### 2. Failed Orders Reprocessing -When an order fails, the bot stores the error, and marks the order as failed. This way, the `Failed -Orders Processor` is able to retry the failed orders. The following diagram shows the flow of a -failed order through the bot. ![failed_orders.svg](images%2Ffailed_orders.svg) @@ -84,8 +92,5 @@ failed order through the bot. When the bot starts, it retrieves incomplete orders from the database and continues their processing. ### 4. Accepted Blocks Indexation -The Main Order Indexer processes orders from pending blocks. The `Orders from -Accepted Blocks Processor` will index the orders that belong to accepted blocks. This way, if the `Main Order -Indexer` loses an order, it will be captured and processed by the `Orders from Accepted Blocks Processor`. ![accepted_blocks.svg](images%2Faccepted_blocks.svg) diff --git a/docs/mm_bot/deploy.md b/docs/mm_bot/deploy.md index d53bef0e..a73cd3c6 100644 --- a/docs/mm_bot/deploy.md +++ b/docs/mm_bot/deploy.md @@ -1,18 +1,15 @@ # Deploy Guide ## Prerequisites -- Python v3.10 or higher -- pip -- Postgres (Native or Docker) +- [Python v3.10](https://www.python.org/downloads/) +- [pip](https://pip.pypa.io/en/stable/installation/) +- Postgres ([Local](https://www.postgresql.org/) or [Docker](https://hub.docker.com/_/postgres)) +- [pyenv](https://github.com/pyenv/pyenv) (Optional) ## Setup ### Installation - -```bash -pip install -r requirements.txt -``` #### Virtual Environment -If you want to use a virtual environment, you can use the following command: +Create the virtual environment using the following command: ```bash make create_python_venv @@ -23,69 +20,89 @@ To run the virtual environment, you can use the following command: source venv/bin/activate ``` -### Environment Variables -This API uses environment variables to configure the application. You can create a `.env` file in the root of the project to set the environment variables. - -To create your own `.env` file run the following command: +#### Dependencies +To install the dependencies, you can use the following command: ```bash -make create_env +make deps ``` -The following environment variables are used: - - ENVIRONMENT= - ETHEREUM_RPC= - STARKNET_RPC= - ETH_FALLBACK_RPC_URL= - SN_FALLBACK_RPC_URL= - ETHEREUM_CONTRACT_ADDRESS= - STARKNET_CONTRACT_ADDRESS= - ETHEREUM_PRIVATE_KEY= - STARKNET_WALLET_ADDRESS= - STARKNET_PRIVATE_KEY= - HERODOTUS_API_KEY= - POSTGRES_HOST= - POSTGRES_USER= - POSTGRES_PASSWORD= - POSTGRES_DATABASE= - LOGGING_LEVEL= - LOGGING_DIRECTORY= - PAYMENT_CLAIMER= - - -There is a example file called `.env.example` in the root of the project. - ### Database Setup #### Create Database Container -This Bot uses a Postgres database. You can either install Postgres natively or use Docker (recommended for development environment). +This Bot uses a Postgres database. You can either install Postgres locally or use Docker (recommended for development environment). + If you use Docker, you can use the following command to start a Postgres container: ```bash make create_db container= user= password= database= ``` - Where: - - container: the name of the docker container. If not provided, the default value is 'postgres' - - user: the user to create. If not provided, the default value is 'user' - - password: the password for the user. If not provided, the default value is '123123123' - - database: the name of the database to create. If not provided, the default value is 'mm-bot' -This container will have a database called ``, by default it is `mm-bot`. +| Variable | Description | +|-----------|---------------------------------------------------------------------------------------| +| container | The name of the docker container. If not provided, the default value is `mm-bot` | +| user | The user to create. If not provided, the default value is `user` | +| password | The password for the user. If not provided, the default value is `123123123` | +| database | The name of the database to create. If not provided, the default value is `mm-bot-db` | + +This container will have a database called ``, by default it is `mm-bot-db`. #### Run Database Container If you want to run or re-run the database container, you can use the following command: ```bash -make run_db container= +make start_db container= ``` - Where: - - container: the name of the docker container. If not provided, the default value is 'postgres' + +| Variable | Description | +|-----------|---------------------------------------------------------------------------------------| +| container | The name of the docker container. If not provided, the default value is `mm-bot` | #### Stop Database Container If you want to stop the database container, you can use the following command: ```bash make stop_db container= ``` - Where: - - container: the name of the docker container. If not provided, the default value is 'postgres' + +| Variable | Description | +|-----------|---------------------------------------------------------------------------------------| +| container | The name of the docker container. If not provided, the default value is `mm-bot` | + +### Environment Variables +This API uses environment variables to configure the application. You can create a `.env` file in the root of the project to set the environment variables. + +To create your own `.env` file run the following command: + +```bash +make create_env +``` + +The following table describes each environment variable: + +| Variable | Description | +|---------------------------|-------------------------------------------------------------------------------------------------------------------| +| ENVIRONMENT | The environment of the application. It can be `dev` or `prod` | +| ETHEREUM_CHAIN_ID | The chain ID of the Ethereum network. It can be `1` for Mainnet, 11155111 for Sepolia | +| STARKNET_CHAIN_ID | The chain ID of the Starknet network. It can be `SN_MAINNET` for Mainnet, `SN_SEPOLIA` for Sepolia | +| ETHEREUM_RPC | The URL of the Ethereum RPC. You can get one at [Blast](https://blastapi.io/) or [Infure](https://www.infura.io/) | +| STARKNET_RPC | The URL of the Starknet RPC. You can get one at [Blast](https://blastapi.io/) or [Infure](https://www.infura.io/) | +| ZKSYNC_RPC | The URL of the ZkSync RPC. You can get one at [Blast](https://blastapi.io/) | +| ETH_FALLBACK_RPC_URL | The URL of the Ethereum RPC fallback | +| SN_FALLBACK_RPC_URL | The URL of the Starknet RPC fallback | +| ZKSYNC_FALLBACK_RPC_URL | The URL of the ZkSync RPC fallback | +| ETHEREUM_CONTRACT_ADDRESS | The address of the Payment Registry | +| STARKNET_CONTRACT_ADDRESS | The address of the Starknet Escrow | +| ZKS_CONTRACT_ADDRESS | The address of the ZkSync Escrow | +| ETHEREUM_PRIVATE_KEY | The private key of Market Maker on Ethereum | +| STARKNET_WALLET_ADDRESS | The wallet address of Market Maker on Starknet | +| STARKNET_PRIVATE_KEY | The private key of Market Maker on Starknet | +| HERODOTUS_API_KEY | (Optional) The API key of Herodotus. Needed if using herodotus payment claimer | +| POSTGRES_HOST | The host of the Postgres database | +| POSTGRES_USER | The user of the Postgres database | +| POSTGRES_PASSWORD | The password of the Postgres database | +| POSTGRES_DATABASE | The name of the Postgres database | +| LOGGING_LEVEL | The level of logging. It can be `DEBUG`, `INFO`, `WARNING`, `ERROR`, or `CRITICAL` | +| LOGGING_DIRECTORY | The directory to save the logs in prod `mode`. Only needed in `prod` mode | +| PAYMENT_CLAIMER | The payment claimer. It can be `herodotus` or `ethereum` | + +There is an example file called `.env.example` in the root of the project. #### Database Population To create the tables, you can use the following command: @@ -98,7 +115,7 @@ You must run schema.sql into the database to create the tables. You can use pgAd To start the Bot, you can use the following command: ```bash -python3 src/main.py +make run ``` ## Test [TODO] diff --git a/docs/mm_bot/diagrams/accepted_blocks.puml b/docs/mm_bot/diagrams/accepted_blocks.puml index 5e21a4c0..f6d39869 100644 --- a/docs/mm_bot/diagrams/accepted_blocks.puml +++ b/docs/mm_bot/diagrams/accepted_blocks.puml @@ -8,7 +8,7 @@ box Ethereum #99e6ff entity "Payment Registry" as PR #blue end box box "Market Maker" -control "Order Processor" as OP +control "Order Executor" as OP control "Order from Accepted Blocks Processor" as ABP database Database end box diff --git a/docs/mm_bot/diagrams/class_diagrams.puml b/docs/mm_bot/diagrams/class_diagrams.puml index 7611efff..f8f47036 100644 --- a/docs/mm_bot/diagrams/class_diagrams.puml +++ b/docs/mm_bot/diagrams/class_diagrams.puml @@ -1,26 +1,10 @@ @startuml title MM Diagram Class -hide members +'hide members class MM { - run() - process_order_events(order_events: list, order_service: OrderService, - eth_lock: asyncio.Lock, herodotus_semaphore: asyncio.Semaphore) - create_order_tasks(order: Order, order_service: OrderService, eth_lock: asyncio.Lock, - herodotus_semaphore: asyncio.Semaphore) - process_order(order: Order, order_service: OrderService, - eth_lock: asyncio.Lock, herodotus_semaphore: asyncio.Semaphore) - failed_orders_job(order_service: OrderService, - eth_lock: asyncio.Lock, herodotus_semaphore: asyncio.Semaphore) - process_failed_orders(order_service: OrderService, - eth_lock: asyncio.Lock, herodotus_semaphore: asyncio.Semaphore) - set_order_events_from_accepted_blocks_job(order_service: OrderService, block_dao: BlockDao, - eth_lock: asyncio.Lock, herodotus_semaphore: asyncio.Semaphore) - process_orders_from_accepted_blocks(order_service: OrderService, block_dao: BlockDao, - eth_lock: asyncio.Lock, herodotus_semaphore: asyncio.Semaphore) - transfer(order: Order, order_service: OrderService) - wait_transfer(order: Order, order_service: OrderService) + + run() } package services { @@ -29,6 +13,7 @@ package services { __ main methods __ + transfer(deposit_id, dst_addr, amount) + claim_payment(deposit_id, dst_addr, amount, value) + + claim_payment_zksync(order_id, destination_address, amount, value, gas_limit, gas_per_pub_data_byte_limit) + get_is_used_order(order_id, recipient_address, amount, rpc_node): bool __ auxiliary methods __ @@ -37,6 +22,7 @@ package services { + has_funds(amount: int): bool + create_transfer(deposit_id, dst_addr_bytes, amount, rpc_node) + create_claim_payment(deposit_id, dst_addr_bytes, amount, value, rpc_node) + + create_claim_payment_zksync(order_id, destination_address, amount, value, gas_limit, gas_per_pub_data_byte_limit, rpc_node) + get_nonce(w3: Web3, address) + estimate_transaction_fee(transaction, rpc_node) + get_gas_price(rpc_node) @@ -44,15 +30,14 @@ package services { + send_raw_transaction(signed_tx, rpc_node) + wait_for_transaction_receipt(tx_hash, rpc_node) } - MM *-- Ethereum class EthereumRpcNode { + w3 + account + contract } - Ethereum *-- EthereumRpcNode } + class Herodotus { + herodotus_prove(block, order_id, slot): str + herodotus_status(task_id): str @@ -61,10 +46,10 @@ package services { class OrderService { + create_order(order: Order): Order - + get_order(order_id): Order | None - + get_order(order_id): Order | None - + get_failed_orders() - + already_exists(order_id): bool + + get_order(order_id, origin_network): Order | None + + get_incomplete_orders(): list[Order] + + get_failed_orders(): list[Order] + + already_exists(order_id, origin_network): bool + set_order_processing(order: Order): Order + set_order_transferring(order: Order, tx_hash): Order + set_order_fulfilled(order: Order): Order @@ -77,15 +62,8 @@ package services { + reset_failed_order(order: Order): Order + set_failed(order: Order, failed: bool): Order } - MM *-- OrderService - class OverallFeeCalculator { - estimate_overall_fee(order: Order): int - estimate_transfer_fee(order: Order): int - estimate_yab_claim_payment_fee(): int - estimate_message_fee(order: Order): - } - MM *-- OverallFeeCalculator + package starknet { class Starknet { __ main methods __ @@ -96,123 +74,217 @@ package services { + claim_payment(order_id, block, slot): bool __ auxiliary methods __ - + create_set_order_event(event) - + get_order_id(event): int - + get_recipient_address(event): str - + get_amount(event): int - + parse_u256_from_double_u128(low, high): int - + get_fee(event): int + get_latest_block(rpc_node): int + sign_invoke_transaction(call: Call, max_fee: int, rpc_node) + estimate_message_fee(from_address, to_address, entry_point_selector, payload, rpc_node) + send_transaction(transaction, rpc_node) + wait_for_tx(transaction_hash, rpc_node) } - MM *-- Starknet class StarknetRpcNode { + full_node_client + account + contract_address } - Starknet *-- StarknetRpcNode class MMFullNodeClient { } - StarknetRpcNode *-- MMFullNodeClient + } + + package zksync { + class Zksync { + __ main methods __ + + get_set_order_events(from_block_number, to_block_number): list[SetOrderEvent] - class SetOrderEvent { - + order_id - + starknet_tx_hash - + recipient_address - + amount - + fee - + block_number - + is_used + __ auxiliary methods __ + + get_latest_block(rpc_node): int + + get_set_order_logs(from_block_number, to_block_number, rpc_node): list[EventData] + } + + class EthereumAsyncRpcNode { + + w3 + + contract + } + + } + + package executors { + class OrderExecutor { + - logger + - order_service + - sender + - payment_claimer + - fee_calculator + - eth_lock + - herodotus_semaphore + - MAX_ETH_TRANSFER_WEI + + + execute(order) + - process_order(order) + } + } + + package fee_calculators { + abstract FeeCalculator { + + estimate_overall_fee(order: Order): int + + estimate_transfer_fee(order: Order): int + + estimate_claim_payment_fee(order: Order): int + + {abstract} estimate_message_fee(order: Order): int + } + + class StarknetFeeCalculator { + } + + class ZksyncFeeCalculator { + + estimate_gas_limit(order: Order): int + + estimate_gas_per_pub_data_byte_limit(order: Order): int + } + } + + package indexers { + abstract OrderIndexer { + - logger + - order_service + + + {abstract} get_orders(from_block, to_block): list[Order] + + {abstract} get_new_orders(): list[Order] + + save_orders(set_order_events: list[SetOrderEvent]): list[Order] + } + + class StarknetOrderIndexer { + } + + class ZksyncOrderIndexer { } } package payment_claimer { abstract PaymentClaimer { - + send_payment_claim(order: Order, order_service: OrderService) - + wait_for_payment_claim(order: Order, order_service: OrderService) - + close_payment_claim(order: Order, order_service: OrderService) + - logger + + + {abstract} send_payment_claim(order: Order, order_service: OrderService) + + {abstract} wait_for_payment_claim(order: Order, order_service: OrderService) + + {abstract} close_payment_claim(order: Order, order_service: OrderService) } - MM *-right- PaymentClaimer class EthereumPaymentClaimer { - {static} estimate_claim_payment_fallback_message_fee(order_id, recipient_address, amount) + - fee_calculator + } + + class Ethereum2ZksyncPaymentClaimer { + - fee_calculator } - PaymentClaimer <|-- EthereumPaymentClaimer class HerodotusPaymentClaimer { } - PaymentClaimer <|-- HerodotusPaymentClaimer - HerodotusPaymentClaimer *-- Herodotus + } + + package processors { + class OrdersProcessor { + - logger + - order_indexer + - order_executor + + + process_orders() + } + + class AcceptedBlocksOrderProcessor { + - logger + - order_indexer + - order_executor + - block_dao + + + process_orders() + + process_orders_job() + } + + class FailedOrdersProcessor { + - logger + - order_executor + - order_service + + + process_orders() + + process_orders_job() + } + } + + package senders { + class EthereumSender { + - logger + - order_service + + + transfer(order: Order) + + wait_transfer(order: Order) } } package persistence <> { class BlockDao { - + get_latest_block(): int - + update_latest_block(latest_block: int) + + get_latest_block(network: Network): int + + update_latest_block(latest_block: int, network: Network) } - MM *-- BlockDao class ErrorDao { + create_error(error: Error): Error } - OrderService *-- ErrorDao class OrderDao { + create_order(order: Order): Order - + get_order(order_id: int): Order | None + + get_order(order_id: int, origin_network: Network): Order | None + get_orders(criteria): list[Type[Order]] + get_incomplete_orders() list[Type[Order]] + get_failed_orders(): list[Type[Order]] - + already_exists(order_id): bool + + already_exists(order_id: int, origin_network: Network): bool + update_order(order: Order): Order } - OrderService *-- OrderDao } package models { class Block { - + id + + id: int + + network: Network + latest_block + created_at } class Error { - + id - + order - + message - + created_at + + id: int + + order_id: int + + origin_network: Network + + order: Mapped[Order] + + message: str + + created_at: datetime + } + + enum Network { + STARKNET + ZKSYNC } class Order { - + order_id - + starknet_tx_hash - + recipient_address - + amount - + fee - + status - + failed - + tx_hash - + transferred_at - + herodotus_task_id - + herodotus_block - + herodotus_slot - + eth_claim_tx_hash - + completed_at - + created_at + + order_id: int + + origin_network: Network + + recipient_address: str + + amount: decimal + + fee: decimal + + status: OrderStatus + + failed: bool + + set_order_tx_hash: HexBytes + + transfer_tx_hash: HexBytes + + claim_tx_hash: HexBytes + + herodotus_task_id: str + + herodotus_block: int + + herodotus_slot: int + + created_at: datetime + + transferred_at: datetime + + completed_at: datetime - + get_int_amount() - + get_int_fee() + + get_int_amount(): int + + get_int_fee(): int + + summary(): str + + {static} from_set_order_event(event: SetOrderEvent): Order } - Error *-- Order - enum OrderStatus { PENDING PROCESSING @@ -223,6 +295,94 @@ package models { COMPLETED DROPPED } - Order *-- OrderStatus + + class SetOrderEvent { + + order_id: int + + origin_network: Network + + set_order_tx_hash: HexBytes + + recipient_address: str + + amount: int + + fee: int + + block_number: int + + is_used: bool + + + {static} from_starknet(event): SetOrderEvent + + {static} from_zksync(event): SetOrderEvent + + {static} parse_u256_from_double_u128(low: int, high: int): int + } } + +' Relations +' MM +MM *-down- FailedOrdersProcessor +MM *-down- AcceptedBlocksOrderProcessor +MM *-down- OrdersProcessor + +' Services +' Executors +'OrderExecutor *-- OrderService +OrderExecutor *-- EthereumSender +OrderExecutor *-- PaymentClaimer +OrderExecutor *-- FeeCalculator + +' Fee Calculator +'FeeCalculator *-- Ethereum +FeeCalculator <|-- StarknetFeeCalculator +FeeCalculator <|-- ZksyncFeeCalculator + +'StarknetFeeCalculator *-- Starknet +'ZksyncFeeCalculator *-- Zksync + +' Indexers +'OrderIndexer *-- OrderService +OrderIndexer <|-- StarknetOrderIndexer +OrderIndexer <|-- ZksyncOrderIndexer + +'StarknetOrderIndexer *-- Starknet +'ZksyncOrderIndexer *-- Zksync + +' Payment Claimer +PaymentClaimer <|-- EthereumPaymentClaimer +PaymentClaimer <|-- HerodotusPaymentClaimer +PaymentClaimer <|-- Ethereum2ZksyncPaymentClaimer +'EthereumPaymentClaimer *-- Ethereum +'EthereumPaymentClaimer *-- StarknetFeeCalculator +'Ethereum2ZksyncPaymentClaimer *-- Ethereum +'Ethereum2ZksyncPaymentClaimer *-- ZksyncFeeCalculator +'HerodotusPaymentClaimer *-- Herodotus + +' Processors +OrdersProcessor *-- OrderIndexer +OrdersProcessor *-- OrderExecutor + +'AcceptedBlocksOrderProcessor *-- OrderIndexer +'AcceptedBlocksOrderProcessor *-- OrderExecutor +'AcceptedBlocksOrderProcessor *-- BlockDao + +'FailedOrdersProcessor *-- OrderExecutor +'FailedOrdersProcessor *-- OrderService + +' Senders +'EthereumSender *-- OrderService +'EthereumSender *-- Ethereum + +OrderService *-- OrderDao +OrderService *-- ErrorDao + +Ethereum *-- EthereumRpcNode + +Starknet *-- StarknetRpcNode +StarknetRpcNode *-- MMFullNodeClient + +Zksync *-- EthereumAsyncRpcNode + +' Models +Order *-- SetOrderEvent +Order *-- OrderStatus +Order *-- Network + +Error *-- Order +Error *-- Network + +Block *-- Network @enduml diff --git a/docs/mm_bot/diagrams/failed_orders.puml b/docs/mm_bot/diagrams/failed_orders.puml index 0d4d7dbc..1c78e970 100644 --- a/docs/mm_bot/diagrams/failed_orders.puml +++ b/docs/mm_bot/diagrams/failed_orders.puml @@ -1,14 +1,14 @@ @startuml hide footbox actor User as U -box Starknet #ebc7ff +box L2 #ebc7ff entity Escrow as E #purple end box box Ethereum #99e6ff entity "Payment Registry" as PR #blue end box box "Market Maker" -control "Order Processor" as OP +control "Order Executor" as OP control "Failed Order Processor" as FOP database Database end box diff --git a/docs/mm_bot/diagrams/order_processing.puml b/docs/mm_bot/diagrams/order_processing.puml index acec11a0..ba0b4694 100644 --- a/docs/mm_bot/diagrams/order_processing.puml +++ b/docs/mm_bot/diagrams/order_processing.puml @@ -1,13 +1,13 @@ @startuml hide footbox actor User as U -box Starknet #ebc7ff +box L2 #ebc7ff entity Escrow as E #purple end box box Ethereum #99e6ff entity "Payment Registry" as PR #blue box "Market Maker" -control "Order Processor" as OP +control "Orders Processor" as OP database Database end box diff --git a/docs/mm_bot/images/accepted_blocks.svg b/docs/mm_bot/images/accepted_blocks.svg index 384fef9f..75f1257f 100644 --- a/docs/mm_bot/images/accepted_blocks.svg +++ b/docs/mm_bot/images/accepted_blocks.svg @@ -1 +1 @@ -StarknetEthereumMarket MakerUserEscrowPayment RegistryOrder ProcessorOrder from Accepted Blocks ProcessorDatabaseOrder already existsin an accepted blockGets Orders from Accepted BlocksStores missing ordersProcesses missing OrderProcesses OrderTransfers fundsTransfers fundsSends proof of paymentSends proof of paymentSend fundsStores Order as completed \ No newline at end of file +StarknetEthereumMarket MakerUserEscrowPayment RegistryOrder ExecutorOrder from Accepted Blocks ProcessorDatabaseOrder already existsin an accepted blockGets Orders from Accepted BlocksStores missing ordersProcesses missing OrderProcesses OrderTransfers fundsTransfers fundsSends proof of paymentSends proof of paymentSend fundsStores Order as completed \ No newline at end of file diff --git a/docs/mm_bot/images/architecture.png b/docs/mm_bot/images/architecture.png index 00ab9bd3..e1b8ebf4 100644 Binary files a/docs/mm_bot/images/architecture.png and b/docs/mm_bot/images/architecture.png differ diff --git a/docs/mm_bot/images/failed_orders.svg b/docs/mm_bot/images/failed_orders.svg index 237c6667..651da7e8 100644 --- a/docs/mm_bot/images/failed_orders.svg +++ b/docs/mm_bot/images/failed_orders.svg @@ -1 +1 @@ -StarknetEthereumMarket MakerUserEscrowPayment RegistryOrder ProcessorFailed Order ProcessorDatabaseSets OrderGets OrderProcesses OrderStores Order as failed due to an errorGets failed ordersProcesses failed orderTransfers fundsTransfers fundsSends proof of paymentSends proof of paymentSend fundsStores Order as completed \ No newline at end of file +L2EthereumMarket MakerUserEscrowPayment RegistryOrder ExecutorFailed Order ProcessorDatabaseSets OrderGets OrderProcesses OrderStores Order as failed due to an errorGets failed ordersProcesses failed orderTransfers fundsTransfers fundsSends proof of paymentSends proof of paymentSend fundsStores Order as completed \ No newline at end of file diff --git a/docs/mm_bot/images/mm_diagram_class.svg b/docs/mm_bot/images/mm_diagram_class.svg index 40633c75..29e1bc83 100644 --- a/docs/mm_bot/images/mm_diagram_class.svg +++ b/docs/mm_bot/images/mm_diagram_class.svg @@ -1 +1 @@ -MM Diagram Classservicesethereumstarknetpayment_claimerpersistencemodelsHerodotusOrderServiceOverallFeeCalculatorEthereumEthereumRpcNodeStarknetStarknetRpcNodeMMFullNodeClientSetOrderEventPaymentClaimerEthereumPaymentClaimerHerodotusPaymentClaimerBlockDaoErrorDaoOrderDaoBlockErrorOrderOrderStatusMM \ No newline at end of file +MM Diagram Classservicesethereumstarknetzksyncexecutorsfee_calculatorsindexerspayment_claimerprocessorssenderspersistencemodelsHerodotusOrderServiceEthereumEthereumRpcNodeStarknetStarknetRpcNodeMMFullNodeClientZksyncEthereumAsyncRpcNodeOrderExecutorFeeCalculatorStarknetFeeCalculatorZksyncFeeCalculatorOrderIndexerStarknetOrderIndexerZksyncOrderIndexerPaymentClaimerEthereumPaymentClaimerEthereum2ZksyncPaymentClaimerHerodotusPaymentClaimerOrdersProcessorAcceptedBlocksOrderProcessorFailedOrdersProcessorEthereumSenderBlockDaoErrorDaoOrderDaoBlockErrorNetworkOrderOrderStatusSetOrderEventMM \ No newline at end of file diff --git a/docs/mm_bot/images/mm_diagram_class_full.svg b/docs/mm_bot/images/mm_diagram_class_full.svg index 7636e293..ea20f3a6 100644 --- a/docs/mm_bot/images/mm_diagram_class_full.svg +++ b/docs/mm_bot/images/mm_diagram_class_full.svg @@ -1 +1 @@ -MM Diagram Classservicesethereumstarknetpayment_claimerpersistencemodelsHerodotusherodotus_prove(block, order_id, slot): strherodotus_status(task_id): strherodotus_poll_status(task_id): boolOrderServicecreate_order(order: Order): Orderget_order(order_id): Order | Noneget_order(order_id): Order | Noneget_failed_orders()already_exists(order_id): boolset_order_processing(order: Order): Orderset_order_transferring(order: Order, tx_hash): Orderset_order_fulfilled(order: Order): Orderset_order_proving_herodotus(order: Order, task_id, block, slot): Orderset_order_proving_ethereum(order: Order, tx_hash): Orderset_order_proved(order: Order): Orderset_order_completed(order: Order): Orderset_order_dropped(order: Order): Orderset_order_failed(order: Order, error_message: str): Orderreset_failed_order(order: Order): Orderset_failed(order: Order, failed: bool): OrderOverallFeeCalculatorestimate_overall_fee(order: Order): intestimate_transfer_fee(order: Order): intestimate_yab_claim_payment_fee(): intestimate_message_fee(order: Order):Ethereumtransfer(deposit_id, dst_addr, amount)claim_payment(deposit_id, dst_addr, amount, value)get_is_used_order(order_id, recipient_address, amount, rpc_node): bool main methodsget_latest_block(rpc_node): intget_balance(rpc_node): inthas_funds(amount: int): boolcreate_transfer(deposit_id, dst_addr_bytes, amount, rpc_node)create_claim_payment(deposit_id, dst_addr_bytes, amount, value, rpc_node)get_nonce(w3: Web3, address)estimate_transaction_fee(transaction, rpc_node)get_gas_price(rpc_node)has_enough_funds(amount: int, gas_fee: int): boolsend_raw_transaction(signed_tx, rpc_node)wait_for_transaction_receipt(tx_hash, rpc_node)auxiliary methodsEthereumRpcNodew3accountcontractStarknetget_starknet_events(from_block_number: Literal["pending", "latest"] | int | None,to_block_number: Literal["pending", "latest"] | int | None,continuation_token, rpc_node)get_order_events(from_block_number, to_block_number): list[SetOrderEvent]claim_payment(order_id, block, slot): bool main methodscreate_set_order_event(event)get_order_id(event): intget_recipient_address(event): strget_amount(event): intparse_u256_from_double_u128(low, high): intget_fee(event): intget_latest_block(rpc_node): intsign_invoke_transaction(call: Call, max_fee: int, rpc_node)estimate_message_fee(from_address, to_address, entry_point_selector, payload, rpc_node)send_transaction(transaction, rpc_node)wait_for_tx(transaction_hash, rpc_node)auxiliary methodsStarknetRpcNodefull_node_clientaccountcontract_addressMMFullNodeClientSetOrderEventorder_idstarknet_tx_hashrecipient_addressamountfeeblock_numberis_usedPaymentClaimersend_payment_claim(order: Order, order_service: OrderService)wait_for_payment_claim(order: Order, order_service: OrderService)close_payment_claim(order: Order, order_service: OrderService)EthereumPaymentClaimerestimate_claim_payment_fallback_message_fee(order_id, recipient_address, amount)HerodotusPaymentClaimerBlockDaoget_latest_block(): intupdate_latest_block(latest_block: int)ErrorDaocreate_error(error: Error): ErrorOrderDaocreate_order(order: Order): Orderget_order(order_id: int): Order | Noneget_orders(criteria): list[Type[Order]]get_incomplete_orders() list[Type[Order]]get_failed_orders(): list[Type[Order]]already_exists(order_id): boolupdate_order(order: Order): OrderBlockidlatest_blockcreated_atErroridordermessagecreated_atOrderorder_idstarknet_tx_hashrecipient_addressamountfeestatusfailedtx_hashtransferred_atherodotus_task_idherodotus_blockherodotus_sloteth_claim_tx_hashcompleted_atcreated_atget_int_amount()get_int_fee()OrderStatusPENDINGPROCESSINGTRANSFERRINGFULFILLEDPROVINGPROVEDCOMPLETEDDROPPEDMMrun()process_order_events(order_events: list, order_service: OrderService,eth_lock: asyncio.Lock, herodotus_semaphore: asyncio.Semaphore)create_order_tasks(order: Order, order_service: OrderService, eth_lock: asyncio.Lock,herodotus_semaphore: asyncio.Semaphore)process_order(order: Order, order_service: OrderService,eth_lock: asyncio.Lock, herodotus_semaphore: asyncio.Semaphore)failed_orders_job(order_service: OrderService,eth_lock: asyncio.Lock, herodotus_semaphore: asyncio.Semaphore)process_failed_orders(order_service: OrderService,eth_lock: asyncio.Lock, herodotus_semaphore: asyncio.Semaphore)set_order_events_from_accepted_blocks_job(order_service: OrderService, block_dao: BlockDao,eth_lock: asyncio.Lock, herodotus_semaphore: asyncio.Semaphore)process_orders_from_accepted_blocks(order_service: OrderService, block_dao: BlockDao,eth_lock: asyncio.Lock, herodotus_semaphore: asyncio.Semaphore)transfer(order: Order, order_service: OrderService)wait_transfer(order: Order, order_service: OrderService) \ No newline at end of file +MM Diagram Classservicesethereumstarknetzksyncexecutorsfee_calculatorsindexerspayment_claimerprocessorssenderspersistencemodelsHerodotusherodotus_prove(block, order_id, slot): strherodotus_status(task_id): strherodotus_poll_status(task_id): boolOrderServicecreate_order(order: Order): Orderget_order(order_id, origin_network): Order | Noneget_incomplete_orders(): list[Order]get_failed_orders(): list[Order]already_exists(order_id, origin_network): boolset_order_processing(order: Order): Orderset_order_transferring(order: Order, tx_hash): Orderset_order_fulfilled(order: Order): Orderset_order_proving_herodotus(order: Order, task_id, block, slot): Orderset_order_proving_ethereum(order: Order, tx_hash): Orderset_order_proved(order: Order): Orderset_order_completed(order: Order): Orderset_order_dropped(order: Order): Orderset_order_failed(order: Order, error_message: str): Orderreset_failed_order(order: Order): Orderset_failed(order: Order, failed: bool): OrderEthereumtransfer(deposit_id, dst_addr, amount)claim_payment(deposit_id, dst_addr, amount, value)claim_payment_zksync(order_id, destination_address, amount, value, gas_limit, gas_per_pub_data_byte_limit)get_is_used_order(order_id, recipient_address, amount, rpc_node): bool main methodsget_latest_block(rpc_node): intget_balance(rpc_node): inthas_funds(amount: int): boolcreate_transfer(deposit_id, dst_addr_bytes, amount, rpc_node)create_claim_payment(deposit_id, dst_addr_bytes, amount, value, rpc_node)create_claim_payment_zksync(order_id, destination_address, amount, value, gas_limit, gas_per_pub_data_byte_limit, rpc_node)get_nonce(w3: Web3, address)estimate_transaction_fee(transaction, rpc_node)get_gas_price(rpc_node)has_enough_funds(amount: int, gas_fee: int): boolsend_raw_transaction(signed_tx, rpc_node)wait_for_transaction_receipt(tx_hash, rpc_node)auxiliary methodsEthereumRpcNodew3accountcontractStarknetget_starknet_events(from_block_number: Literal["pending", "latest"] | int | None,to_block_number: Literal["pending", "latest"] | int | None,continuation_token, rpc_node)get_order_events(from_block_number, to_block_number): list[SetOrderEvent]claim_payment(order_id, block, slot): bool main methodsget_latest_block(rpc_node): intsign_invoke_transaction(call: Call, max_fee: int, rpc_node)estimate_message_fee(from_address, to_address, entry_point_selector, payload, rpc_node)send_transaction(transaction, rpc_node)wait_for_tx(transaction_hash, rpc_node)auxiliary methodsStarknetRpcNodefull_node_clientaccountcontract_addressMMFullNodeClientZksyncget_set_order_events(from_block_number, to_block_number): list[SetOrderEvent] main methodsget_latest_block(rpc_node): intget_set_order_logs(from_block_number, to_block_number, rpc_node): list[EventData]auxiliary methodsEthereumAsyncRpcNodew3contractOrderExecutorloggerorder_servicesenderpayment_claimerfee_calculatoreth_lockherodotus_semaphoreMAX_ETH_TRANSFER_WEIexecute(order)process_order(order)FeeCalculatorestimate_overall_fee(order: Order): intestimate_transfer_fee(order: Order): intestimate_claim_payment_fee(order: Order): intestimate_message_fee(order: Order): intStarknetFeeCalculatorZksyncFeeCalculatorestimate_gas_limit(order: Order): intestimate_gas_per_pub_data_byte_limit(order: Order): intOrderIndexerloggerorder_serviceget_orders(from_block, to_block): list[Order]get_new_orders(): list[Order]save_orders(set_order_events: list[SetOrderEvent]): list[Order]StarknetOrderIndexerZksyncOrderIndexerPaymentClaimerloggersend_payment_claim(order: Order, order_service: OrderService)wait_for_payment_claim(order: Order, order_service: OrderService)close_payment_claim(order: Order, order_service: OrderService)EthereumPaymentClaimerfee_calculatorEthereum2ZksyncPaymentClaimerfee_calculatorHerodotusPaymentClaimerOrdersProcessorloggerorder_indexerorder_executorprocess_orders()AcceptedBlocksOrderProcessorloggerorder_indexerorder_executorblock_daoprocess_orders()process_orders_job()FailedOrdersProcessorloggerorder_executororder_serviceprocess_orders()process_orders_job()EthereumSenderloggerorder_servicetransfer(order: Order)wait_transfer(order: Order)BlockDaoget_latest_block(network: Network): intupdate_latest_block(latest_block: int, network: Network)ErrorDaocreate_error(error: Error): ErrorOrderDaocreate_order(order: Order): Orderget_order(order_id: int, origin_network: Network): Order | Noneget_orders(criteria): list[Type[Order]]get_incomplete_orders() list[Type[Order]]get_failed_orders(): list[Type[Order]]already_exists(order_id: int, origin_network: Network): boolupdate_order(order: Order): OrderBlockid: intnetwork: Networklatest_blockcreated_atErrorid: intorder_id: intorigin_network: Networkorder: Mapped[Order]message: strcreated_at: datetimeNetworkSTARKNETZKSYNCOrderorder_id: intorigin_network: Networkrecipient_address: stramount: decimalfee: decimalstatus: OrderStatusfailed: boolset_order_tx_hash: HexBytestransfer_tx_hash: HexBytesclaim_tx_hash: HexBytesherodotus_task_id: strherodotus_block: intherodotus_slot: intcreated_at: datetimetransferred_at: datetimecompleted_at: datetimeget_int_amount(): intget_int_fee(): intsummary(): strfrom_set_order_event(event: SetOrderEvent): OrderOrderStatusPENDINGPROCESSINGTRANSFERRINGFULFILLEDPROVINGPROVEDCOMPLETEDDROPPEDSetOrderEventorder_id: intorigin_network: Networkset_order_tx_hash: HexBytesrecipient_address: stramount: intfee: intblock_number: intis_used: boolfrom_starknet(event): SetOrderEventfrom_zksync(event): SetOrderEventparse_u256_from_double_u128(low: int, high: int): intMMrun() \ No newline at end of file diff --git a/docs/mm_bot/images/order_processing.svg b/docs/mm_bot/images/order_processing.svg index b844e4d0..db9be92c 100644 --- a/docs/mm_bot/images/order_processing.svg +++ b/docs/mm_bot/images/order_processing.svg @@ -1 +1 @@ -StarknetEthereumMarket MakerUserEscrowPayment RegistryOrder ProcessorDatabaseSets OrderGets OrderStores Order as pendingProcesses OrderTransfers fundsTransfers fundsSends proof of paymentSends proof of paymentSend fundsStores Order as completed \ No newline at end of file +L2EthereumMarket MakerUserEscrowPayment RegistryOrders ProcessorDatabaseSets OrderGets OrderStores Order as pendingProcesses OrderTransfers fundsTransfers fundsSends proof of paymentSends proof of paymentSend fundsStores Order as completed \ No newline at end of file diff --git a/docs/mm_bot/images/physical_view.png b/docs/mm_bot/images/physical_view.png index 245c70cd..47472e8e 100644 Binary files a/docs/mm_bot/images/physical_view.png and b/docs/mm_bot/images/physical_view.png differ diff --git a/mm-bot/.env.example b/mm-bot/.env.example index 5b9e0843..795ac346 100644 --- a/mm-bot/.env.example +++ b/mm-bot/.env.example @@ -1,6 +1,7 @@ ENVIRONMENT= -ETHEREUM_CHAIN_ID=<1=mainnet|5=goerli|11155111=sepolia> -STARKNET_CHAIN_ID= +ETHEREUM_CHAIN_ID=<1=mainnet|11155111=sepolia> +STARKNET_CHAIN_ID=<0x534e5f4d41494e=main|0x534e5f5345504f4c4941=sepolia> +ZKSYNC_CHAIN_ID=<324=mainnet|300=sepolia> ETHEREUM_RPC= STARKNET_RPC= ZKSYNC_RPC= diff --git a/mm-bot/Makefile b/mm-bot/Makefile index 3787114c..2ea28b19 100644 --- a/mm-bot/Makefile +++ b/mm-bot/Makefile @@ -1,3 +1,5 @@ +.PHONE: deps run create_env create_python_venv start_db stop_db create_db + # Database variables container = mm-bot user = user @@ -6,6 +8,11 @@ database = mm-bot-db # Application Commands +deps: + @echo "Installing dependencies..." + @. venv/bin/activate && pip install -r requirements.txt + @echo "Dependencies installed successfully!" + run: @echo "Running application..." @. venv/bin/activate && python3 src/main.py @@ -17,16 +24,16 @@ create_env: create_python_venv: @echo "Creating virtual environment..." - @python3 -m venv venv + @python3.10 -m venv venv @echo "Virtual environment created successfully!" # Database Commands start_db: - @if [ "$(container)" = "postgres" ]; then echo "Using default container name: postgres."; fi + @if [ "$(container)" = "mm-bot" ]; then echo "Using default container name: mm-bot."; fi docker start $(container) stop_db: - @if [ "$(container)" = "postgres" ]; then echo "Using default container name: postgres."; fi + @if [ "$(container)" = "mm-bot" ]; then echo "Using default container name: mm-bot."; fi docker stop $(container) create_db: diff --git a/mm-bot/README.md b/mm-bot/README.md index e2649f0b..756beee3 100644 --- a/mm-bot/README.md +++ b/mm-bot/README.md @@ -1,19 +1,16 @@ # Market Maker Bot Market Maker Bot is a bot that provides liquidity to the Yet Another Bridge (YAB). -# Prerequisites -- Python v3.10 or higher -- pip -- Postgres (Native or Docker) +## Prerequisites +- [Python v3.10](https://www.python.org/downloads/) +- [pip](https://pip.pypa.io/en/stable/installation/) +- Postgres ([Local](https://www.postgresql.org/) or [Docker](https://hub.docker.com/_/postgres)) +- [pyenv](https://github.com/pyenv/pyenv) (Optional) -# Setup -## Installation - -```bash -pip install -r requirements.txt -``` -### Virtual Environment -If you want to use a virtual environment, you can use the following command: +## Setup +### Installation +#### Virtual Environment +Create the virtual environment using the following command: ```bash make create_python_venv @@ -24,85 +21,106 @@ To run the virtual environment, you can use the following command: source venv/bin/activate ``` -## Environment Variables -This API uses environment variables to configure the application. You can create a `.env` file in the root of the project to set the environment variables. - -To create your own `.env` file run the following command: +#### Dependencies +To install the dependencies, you can use the following command: ```bash -make create_env +make deps ``` -The following environment variables are used: - - ENVIRONMENT= - ETHEREUM_RPC= - STARKNET_RPC= - ETHEREUM_FALLBACK_RPC= - STARKNET_FALLBACK_RPC= - ETHEREUM_CONTRACT_ADDRESS= - STARKNET_CONTRACT_ADDRESS= - ETHEREUM_PRIVATE_KEY= - STARKNET_WALLET_ADDRESS= - STARKNET_PRIVATE_KEY= - HERODOTUS_API_KEY= - POSTGRES_HOST= - POSTGRES_USER= - POSTGRES_PASSWORD= - POSTGRES_DATABASE= - LOGGING_LEVEL= - LOGGING_DIRECTORY= - PAYMENT_CLAIMER= - - -There is a example file called `.env.example` in the root of the project. - -## Database Setup -### Create Database Container -This Bot uses a Postgres database. You can either install Postgres natively or use Docker (recommended for development environment). +### Database Setup +#### Create Database Container +This Bot uses a Postgres database. You can either install Postgres locally or use Docker (recommended for development environment). + If you use Docker, you can use the following command to start a Postgres container: ```bash make create_db container= user= password= database= ``` - Where: - - container: the name of the docker container. If not provided, the default value is 'postgres' - - user: the user to create. If not provided, the default value is 'user' - - password: the password for the user. If not provided, the default value is '123123123' - - database: the name of the database to create. If not provided, the default value is 'mm-bot' -This container will have a database called ``, by default it is `mm-bot`. +| Variable | Description | +|-----------|---------------------------------------------------------------------------------------| +| container | The name of the docker container. If not provided, the default value is `mm-bot` | +| user | The user to create. If not provided, the default value is `user` | +| password | The password for the user. If not provided, the default value is `123123123` | +| database | The name of the database to create. If not provided, the default value is `mm-bot-db` | -### Run Database Container +This container will have a database called ``, by default it is `mm-bot-db`. + +#### Run Database Container If you want to run or re-run the database container, you can use the following command: ```bash -make run_db container= +make start_db container= ``` - Where: - - container: the name of the docker container. If not provided, the default value is 'postgres' -### Stop Database Container +| Variable | Description | +|-----------|---------------------------------------------------------------------------------------| +| container | The name of the docker container. If not provided, the default value is `mm-bot` | + +#### Stop Database Container If you want to stop the database container, you can use the following command: ```bash make stop_db container= ``` - Where: - - container: the name of the docker container. If not provided, the default value is 'postgres' -### Database Population +| Variable | Description | +|-----------|---------------------------------------------------------------------------------------| +| container | The name of the docker container. If not provided, the default value is `mm-bot` | + +### Environment Variables +This API uses environment variables to configure the application. You can create a `.env` file in the root of the project to set the environment variables. + +To create your own `.env` file run the following command: + +```bash +make create_env +``` + +The following table describes each environment variable: + +| Variable | Description | +|---------------------------|-------------------------------------------------------------------------------------------------------------------| +| ENVIRONMENT | The environment of the application. It can be `dev` or `prod` | +| ETHEREUM_CHAIN_ID | The chain ID of the Ethereum network. It can be `1` for Mainnet, 11155111 for Sepolia | +| STARKNET_CHAIN_ID | The chain ID of the Starknet network. It can be `0x534e5f4d41494e` for Mainnet, `0x534e5f5345504f4c4941` for Sepolia | +| ZKSYNC_CHAIN_ID | The chain ID of the ZKSync network. I can be `324` for Mainnet, `300` for sepolia | +| ETHEREUM_RPC | The URL of the Ethereum RPC. You can get one at [Blast](https://blastapi.io/) or [Infure](https://www.infura.io/) | +| STARKNET_RPC | The URL of the Starknet RPC. You can get one at [Blast](https://blastapi.io/) or [Infure](https://www.infura.io/) | +| ZKSYNC_RPC | The URL of the ZkSync RPC. You can get one at [Blast](https://blastapi.io/) | +| ETH_FALLBACK_RPC_URL | The URL of the Ethereum RPC fallback | +| SN_FALLBACK_RPC_URL | The URL of the Starknet RPC fallback | +| ZKSYNC_FALLBACK_RPC_URL | The URL of the ZkSync RPC fallback | +| ETHEREUM_CONTRACT_ADDRESS | The address of the Payment Registry | +| STARKNET_CONTRACT_ADDRESS | The address of the Starknet Escrow | +| ZKS_CONTRACT_ADDRESS | The address of the ZkSync Escrow | +| ETHEREUM_PRIVATE_KEY | The private key of Market Maker on Ethereum | +| STARKNET_WALLET_ADDRESS | The wallet address of Market Maker on Starknet | +| STARKNET_PRIVATE_KEY | The private key of Market Maker on Starknet | +| HERODOTUS_API_KEY | (Optional) The API key of Herodotus. Needed if using herodotus payment claimer | +| POSTGRES_HOST | The host of the Postgres database | +| POSTGRES_USER | The user of the Postgres database | +| POSTGRES_PASSWORD | The password of the Postgres database | +| POSTGRES_DATABASE | The name of the Postgres database | +| LOGGING_LEVEL | The level of logging. It can be `DEBUG`, `INFO`, `WARNING`, `ERROR`, or `CRITICAL` | +| LOGGING_DIRECTORY | The directory to save the logs in prod `mode`. Only needed in `prod` mode | +| PAYMENT_CLAIMER | The payment claimer. It can be `herodotus` or `ethereum` | + +There is an example file called `.env.example` in the root of the project. + +#### Database Population To create the tables, you can use the following command: ```bash TODO ``` You must run schema.sql into the database to create the tables. You can use pgAdmin or any other tool to run the script. -# Development +## Development To start the Bot, you can use the following command: ```bash -python3 src/main.py +make run ``` -# Test [TODO] +## Test [TODO] To run the tests, you can use the following command: ```bash diff --git a/mm-bot/abi/Escrow.json b/mm-bot/abi/Escrow.json index 508e423f..adea7b9a 100644 --- a/mm-bot/abi/Escrow.json +++ b/mm-bot/abi/Escrow.json @@ -140,6 +140,29 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "uint256[]", + "name": "order_ids", + "type": "uint256[]" + }, + { + "internalType": "address[]", + "name": "recipient_addresses", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "name": "claim_payment_batch", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [], "name": "ethereum_payment_registry", @@ -350,8 +373,8 @@ "type": "function" } ], - "bytecode": "0x00020000000000020008000000000002000000000501034f000000000105001900000060011002700000010c0110019700010000001503550000008003000039000000400030043f00000001022001900000002f0000c13d000000040210008c0000033f0000413d000000000205043b000000e0022002700000010e0320009c000000370000a13d0000010f0320009c000000440000213d000001150320009c000000a50000213d000001180320009c0000013a0000613d000001190120009c0000033f0000c13d0000000001000416000000000101004b0000033f0000c13d0000003301000039000000000201041a00000123052001970000000003000411000000000335004b000001990000c13d0000013a02200197000000000021041b0000010c0100004100000000020004140000010c0320009c0000000002018019000000c00120021000000130011001c70000800d0200003900000003030000390000013b040000410000000006000019000001b70000013d0000000001000416000000000101004b0000033f0000c13d0000002001000039000001000010044300000120000004430000010d010000410000042a0001042e0000011a0320009c0000008a0000a13d0000011b0320009c000000c50000213d0000011e0320009c000000f00000613d0000011f0120009c0000033f0000c13d0000000001000416000000000101004b0000033f0000c13d0000009d01000039000001940000013d000001100320009c000000ce0000213d000001130320009c000001680000613d000001140220009c0000033f0000c13d0000000002000416000000000202004b0000033f0000c13d000000040110008a000000600110008c0000033f0000413d0000000401500370000000000401043b0000002401500370000000000601043b000001230160009c0000033f0000213d0000004401500370000000000301043b0000006501000039000000000101041a000000ff01100190000001a00000c13d0000009c01000039000000000101041a00000123011001970000000002000411000000000112004b000001bc0000c13d000400000003001d00000000004004350000009901000039000300000001001d000000200010043f0000010c0100004100000000020004140000010c0320009c0000000002018019000000c0012002100000012b011001c70000801002000039000600000004001d000500000006001d042904240000040f000000060300002900000001022001900000033f0000613d000000000101043b000000000101041a000000ff01100190000002f20000c13d000000400100043d00000044021000390000013703000041000000000032043500000024021000390000001c030000390000000000320435000001240200004100000000002104350000000402100039000000200300003900000000003204350000010c020000410000010c0310009c000000000102801900000040011002100000012e011001c70000042b00010430000001200320009c0000016d0000613d000001210320009c000001100000613d000001220120009c0000033f0000c13d0000000001000416000000000101004b0000033f0000c13d0000003301000039000000000101041a00000123011001970000000002000411000000000221004b000001990000c13d0000006502000039000000000302041a000000ff04300190000001aa0000c13d0000012401000041000000800010043f0000002001000039000000840010043f0000001401000039000000a40010043f0000014a01000041000001a70000013d000001160320009c0000017c0000613d000001170120009c0000033f0000c13d0000000001000416000000000101004b0000033f0000c13d0000003301000039000000000101041a00000123011001970000000002000411000000000221004b000001990000c13d0000006502000039000000000302041a000000ff04300190000001a00000c13d000001000400008a000000000343016f00000001033001bf000000000032041b000000800010043f0000010c0100004100000000020004140000010c0320009c0000000002018019000000c00120021000000138011001c70000800d0200003900000001030000390000013904000041000001b70000013d0000011c0320009c000001280000613d0000011d0120009c0000033f0000c13d0000000001000416000000000101004b0000033f0000c13d0000006501000039000001350000013d000001110320009c000001900000613d000001120220009c0000033f0000c13d0000000002000416000000000202004b0000033f0000c13d000000040110008a000000200110008c0000033f0000413d0000000401500370000000000101043b000001230210009c0000033f0000213d0000003302000039000000000202041a00000123022001970000000003000411000000000232004b000001990000c13d000000000201004b000001c40000c13d0000012401000041000000800010043f0000002001000039000000840010043f0000002601000039000000a40010043f0000012501000041000000c40010043f0000012601000041000000e40010043f00000127010000410000042b000104300000000002000416000000000202004b0000033f0000c13d000000040110008a000000400110008c0000033f0000413d0000000401500370000000000301043b000001230130009c0000033f0000213d0000002401500370000000000401043b000001230140009c0000033f0000213d000000000500041a0003ff0000500194000600000003001d000500000004001d000001c70000c13d000000ff0150019000000000020000190000000102006039000700000002001d0000000002000415000000070220008a0000000502200210000000000101004b000001cb0000c13d000001420150019700000101011001bf0000000006000019000001ef0000013d000000040110008a000000400110008c0000033f0000413d0000000401500370000000000301043b000001230130009c0000033f0000213d0000002401500370000000000401043b0000006501000039000000000101041a000000ff01100190000001a00000c13d0000000001000416000000000201004b000001fc0000c13d0000012401000041000000800010043f0000002001000039000000840010043f0000001501000039000000a40010043f0000015201000041000001a70000013d0000000002000416000000000202004b0000033f0000c13d000000040110008a000000200110008c0000033f0000413d0000000401500370000000000101043b00000000001004350000009901000039000000200010043f00000000010000190429040d0000040f000000000101041a000000ff011001900000000001000019000000010100c039000001960000013d0000000002000416000000000202004b0000033f0000c13d000000040110008a000000200110008c0000033f0000413d0006000000050353042903e90000040f0000004002100039000000000002043500000000010104360000000000010435000000060100035f0000000401100370000000000101043b00000000001004350000009801000039000000200010043f00000000010000190429040d0000040f000600000001001d042903e90000040f0000000605000029000000000205041a000001230220019700000000032104360000000104500039000000000404041a00000000004304350000000204500039000000000404041a00000040011000390000000000410435000000400400043d0000000002240436000000000303043300000000003204350000000001010433000000400240003900000000001204350000010c010000410000010c0240009c000000000401801900000040014002100000013c011001c70000042a0001042e0000000001000416000000000101004b0000033f0000c13d0000003301000039000001940000013d0000000002000416000000000202004b0000033f0000c13d000000040110008a000000200110008c0000033f0000413d0000000401500370000000000201043b000001230120009c0000033f0000213d000600000002001d042903f50000040f042903bb0000040f0000009c010000390000018a0000013d0000000002000416000000000202004b0000033f0000c13d000000040110008a000000200110008c0000033f0000413d0000000401500370000000000201043b000001230120009c0000033f0000213d000600000002001d042903f50000040f042903bb0000040f0000009d01000039000000000201041a0000013a0220019700000006022001af000000000021041b00000000010000190000042a0001042e0000000001000416000000000101004b0000033f0000c13d0000009c01000039000000000101041a0000012301100197000000800010043f00000128010000410000042a0001042e0000012401000041000000800010043f0000002001000039000000840010043f000000a40010043f0000014801000041000001a70000013d0000012401000041000000800010043f0000002001000039000000840010043f0000001001000039000000a40010043f0000014b01000041000000c40010043f0000012a010000410000042b00010430000001000400008a000000000343016f000000000032041b000000800010043f0000010c0100004100000000020004140000010c0320009c0000000002018019000000c00120021000000138011001c70000800d02000039000000010300003900000149040000410429041f0000040f00000001012001900000033f0000613d00000000010000190000042a0001042e0000012401000041000000800010043f0000002001000039000000840010043f0000001e01000039000000a40010043f0000012901000041000001a70000013d042903d30000040f00000000010000190000042a0001042e0000000002000415000000080220008a0000000502200210000800000000001d000400000002001d000200000005001d0000013d010000410000000000100439000000000100041000000004001004430000010c0100004100000000020004140000010c0320009c0000000002018019000000c0012002100000013e011001c70000800202000039042904240000040f0000000102200190000002990000613d000000000101043b000000000101004b000002a20000c13d0000000205000029000000ff0150018f000000010110008c0000000001000019000000010100603900000004020000290000000502200270000000000201001f000002a50000c13d000001000100008a000000000115016f000000010600003900000001011001bf000000030200006b000001420150619700000101011061bf0000000006006019000000000010041b0000ff0001100190000002ba0000c13d000000400100043d00000064021000390000014603000041000000000032043500000044021000390000014703000041000000000032043500000024021000390000002b03000039000002ae0000013d000000000241004b0000029a0000a13d000000e002000039000000400020043f000000800030043f0000000001410049000300000001001d000000a00010043f000400000004001d000000c00040043f0000009701000039000600000001001d000000000101041a00000000001004350000009801000039000000200010043f0000010c0400004100000000010004140000010c0210009c0000000001048019000000c0011002100000012b011001c70000801002000039000500000003001d042904240000040f00000001022001900000033f0000613d000000800200043d0000012302200197000000000101043b000000000301041a0000013a03300197000000000223019f000000000021041b0000000102100039000000a00300043d000000000032041b0000000201100039000000c00200043d000000000021041b0000000601000029000000000101041a00000000001004350000009901000039000000200010043f00000000010004140000010c0210009c0000010c01008041000000c0011002100000012b011001c70000801002000039042904240000040f00000001022001900000033f0000613d000000000101043b000000000201041a000001000300008a000000000232016f00000001022001bf000000000021041b0000000601000029000000000101041a00000000001004350000009a01000039000000200010043f0000010c0300004100000000010004140000010c0210009c0000000001038019000000c0011002100000012b011001c70000801002000039042904240000040f00000001022001900000033f0000613d000000000101043b000000000201041a0000013a022001970000000003000411000000000232019f000000000021041b0000000601000029000000000101041a00000000001004350000009b01000039000000200010043f0000014d01000041000000000010043900000000010004140000010c0210009c0000010c01008041000000c0011002100000014e011001c70000800b02000039042904240000040f0000000102200190000002990000613d000000000101043b000200000001001d0000010c0100004100000000020004140000010c0320009c0000000002018019000000c0012002100000012b011001c70000801002000039042904240000040f000000010220019000000006020000290000033f0000613d000000000101043b0000000203000029000000000031041b000000000202041a000000010100008a000200000002001d000000000112004b0000033b0000613d000000020400002900000001014000390000000602000029000000000012041b000000400100043d00000060021000390000000403000029000000000032043500000040021000390000000303000029000000000032043500000020021000390000000503000029000000000032043500000000004104350000010c0400004100000000020004140000010c0320009c00000000020480190000010c0310009c00000000010480190000004001100210000000c002200210000000000112019f0000014f011001c70000800d02000039000000010300003900000150040000410429041f0000040f00000001012001900000033f0000613d000000400100043d000000020200002900000000002104350000010c0210009c0000010c01008041000000400110021000000151011001c70000042a0001042e000000000001042f0000012401000041000000800010043f0000002001000039000000840010043f0000001e01000039000000a40010043f0000014c01000041000001a70000013d00000004010000290000000501100270000000000100001f000000400100043d00000064021000390000013f03000041000000000032043500000044021000390000014003000041000000000032043500000024021000390000002e030000390000000000320435000001240200004100000000002104350000000402100039000000200300003900000000003204350000010c020000410000010c0310009c0000000001028019000000400110021000000141011001c70000042b00010430000400000006001d000000000100041100000123061001970000003301000039000000000201041a0000013a03200197000000000363019f000000000031041b0000010c0100004100000000030004140000010c0430009c0000000003018019000000c00130021000000130011001c700000123052001970000800d0200003900000003030000390000013b040000410429041f0000040f0000000504000029000000060300002900000001012001900000033f0000613d0000009701000039000000000001041b0000009c01000039000000000201041a0000013a02200197000000000232019f000000000021041b0000009d01000039000000000201041a0000013a02200197000000000242019f000000000021041b000000040100006b000001ba0000c13d000000000200041a0000014301200197000000000010041b0000000103000039000000400100043d00000000003104350000010c0200004100000000040004140000010c0540009c00000000040280190000010c0510009c00000000010280190000004001100210000000c002400210000000000112019f00000144011001c70000800d020000390000014504000041000001b70000013d00000000003004350000009801000039000000200010043f0000010c0100004100000000020004140000010c0320009c0000000002018019000000c0012002100000012b011001c70000801002000039042904240000040f000000050500002900000001022001900000033f0000613d000000400200043d0000012c0320009c000003090000413d000001350100004100000000001004350000004101000039000000040010043f00000136010000410000042b00010430000000000101043b0000006003200039000000400030043f000000000301041a000001230330019700000000063204360000000104100039000000000404041a000200000006001d000000000046043500000040022000390000000201100039000000000101041a000100000002001d0000000000120435000000000153004b000003410000c13d00000002010000290000000001010433000000040110006c000003480000c13d000000060100002900000000001004350000000301000029000000200010043f0000010c0100004100000000020004140000010c0320009c0000000002018019000000c0012002100000012b011001c70000801002000039042904240000040f00000001022001900000033f0000613d000000000101043b000000000201041a000001000300008a000000000232016f000000000021041b00000002010000290000000001010433000000010200002900000000020204330000000003120019000000000123004b0000000001000019000000010100403900000001011001900000034f0000613d000001350100004100000000001004350000001101000039000003060000013d00000000010000190000042b00010430000000400100043d00000044021000390000012d03000041000000000032043500000024021000390000001e030000390000007e0000013d000000400100043d00000044021000390000012f030000410000000000320435000000240210003900000013030000390000007e0000013d0000009d01000039000500000001001d000000000201041a00000000010004140000012304200197000000040240008c000003590000c13d00000001020000390000000001000031000003690000013d0000010c020000410000010c0510009c0000000001028019000000c001100210000000000203004b000003610000c13d0000000002040019000003640000013d00000130011001c7000080090200003900000000050000190429041f0000040f000100000001035500000060011002700000010c0010019d0000010c01100197000000000301004b000003860000c13d000000400100043d0000000102200190000003b50000613d0000000502000029000000000202041a000000400310003900000004040000290000000000430435000001230220019700000020031000390000000000230435000000060200002900000000002104350000010c0200004100000000030004140000010c0430009c00000000030280190000010c0410009c00000000010280190000004001100210000000c002300210000000000112019f00000133011001c70000800d0200003900000001030000390000013404000041000001b70000013d000001310310009c000003030000213d0000001f03100039000000200400008a000000000343016f0000003f03300039000000000343016f000000400400043d0000000003340019000000000543004b00000000050000190000000105004039000001310630009c000003030000213d0000000105500190000003030000c13d000000400030043f0000001f0310018f000000000414043600000001050003670000000501100272000003a50000613d000000000600001900000005076002100000000008740019000000000775034f000000000707043b00000000007804350000000106600039000000000716004b0000039d0000413d000000000603004b0000036b0000613d0000000501100210000000000515034f00000000011400190000000303300210000000000401043300000000043401cf000000000434022f000000000505043b0000010003300089000000000535022f00000000033501cf000000000343019f00000000003104350000036b0000013d000000440210003900000132030000410000000000320435000000240210003900000010030000390000007e0000013d0000003301000039000000000101041a00000123011001970000000002000411000000000121004b000003c20000c13d000000000001042d000000400100043d00000044021000390000014803000041000000000032043500000124020000410000000000210435000000240210003900000020030000390000000000320435000000040210003900000000003204350000010c020000410000010c0310009c000000000102801900000040011002100000012e011001c70000042b0001043000000123061001970000003301000039000000000201041a0000013a03200197000000000363019f000000000031041b0000010c0100004100000000030004140000010c0430009c0000000003018019000000c00130021000000130011001c700000123052001970000800d0200003900000003030000390000013b040000410429041f0000040f0000000101200190000003e70000613d000000000001042d00000000010000190000042b00010430000000400100043d0000012c0210009c000003ef0000813d0000006002100039000000400020043f000000000001042d000001350100004100000000001004350000004101000039000000040010043f00000136010000410000042b000104300000006501000039000000000101041a000000ff01100190000003fa0000c13d000000000001042d000000400100043d00000044021000390000014b030000410000000000320435000000240210003900000010030000390000000000320435000001240200004100000000002104350000000402100039000000200300003900000000003204350000010c020000410000010c0310009c000000000102801900000040011002100000012e011001c70000042b00010430000000000001042f0000010c020000410000010c0310009c000000000102801900000000030004140000010c0430009c0000000003028019000000c0023002100000004001100210000000000121019f0000012b011001c70000801002000039042904240000040f00000001022001900000041d0000613d000000000101043b000000000001042d00000000010000190000042b0001043000000422002104210000000102000039000000000001042d0000000002000019000000000001042d00000427002104230000000102000039000000000001042d0000000002000019000000000001042d00000429000004320000042a0001042e0000042b00010430000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffff0000000200000000000000000000000000000040000001000000000000000000000000000000000000000000000000000000000000000000000000005fcb317b000000000000000000000000000000000000000000000000000000008da5cb5a00000000000000000000000000000000000000000000000000000000e2b2e23e00000000000000000000000000000000000000000000000000000000e2b2e23f00000000000000000000000000000000000000000000000000000000f2fde38b000000000000000000000000000000000000000000000000000000008da5cb5b00000000000000000000000000000000000000000000000000000000a5168739000000000000000000000000000000000000000000000000000000007b4437a6000000000000000000000000000000000000000000000000000000007b4437a7000000000000000000000000000000000000000000000000000000008456cb59000000000000000000000000000000000000000000000000000000005fcb317c00000000000000000000000000000000000000000000000000000000715018a600000000000000000000000000000000000000000000000000000000485cc954000000000000000000000000000000000000000000000000000000005a5d0a16000000000000000000000000000000000000000000000000000000005a5d0a17000000000000000000000000000000000000000000000000000000005c975abb00000000000000000000000000000000000000000000000000000000485cc955000000000000000000000000000000000000000000000000000000004c034fe00000000000000000000000000000000000000000000000000000000002ca15ee0000000000000000000000000000000000000000000000000000000012fe8e17000000000000000000000000000000000000000000000000000000003f4ba83a000000000000000000000000ffffffffffffffffffffffffffffffffffffffff08c379a0000000000000000000000000000000000000000000000000000000004f776e61626c653a206e6577206f776e657220697320746865207a65726f20616464726573730000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008400000080000000000000000000000000000000000000000000000000000000200000008000000000000000004f6e6c79205041594d454e545f52454749535452592063616e2063616c6c000000000000000000000000000000000000000000640000008000000000000000000200000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffa0726563697069656e745f61646472657373206e6f74206d61746368204c3100000000000000000000000000000000000000000064000000000000000000000000616d6f756e74206e6f74206d61746368204c31000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffff5472616e73666572206661696c65642e00000000000000000000000000000000020000000000000000000000000000000000006000000000000000000000000055188540052a206e959fa07e62a5f0542065989dcf08853e21b5668c778e46054e487b710000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000240000000000000000000000004f7264657220636c61696d6564206f72206e6f6e6578697374656e7400000000020000000000000000000000000000000000002000000080000000000000000062e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258ffffffffffffffffffffffff00000000000000000000000000000000000000008be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e000000000000000000000000000000000000000600000000000000000000000001806aa1896bbf26568e884a7374b41e002500962caba6a15023a8d90e8508b830200000200000000000000000000000000000024000000000000000000000000647920696e697469616c697a6564000000000000000000000000000000000000496e697469616c697a61626c653a20636f6e747261637420697320616c7265610000000000000000000000000000000000000084000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff02000000000000000000000000000000000000200000000000000000000000007f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024986e697469616c697a696e67000000000000000000000000000000000000000000496e697469616c697a61626c653a20636f6e7472616374206973206e6f7420694f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65725db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa5061757361626c653a206e6f74207061757365640000000000000000000000005061757361626c653a20706175736564000000000000000000000000000000004554482073656e74206d757374206265206d6f7265207468616e206665650000796b89b91644bc98cd93958e4c9038275d622183e25ac5af08cc6b5d95539132020000020000000000000000000000000000000400000000000000000000000002000000000000000000000000000000000000800000000000000000000000000dda38f349344fc4dd0c4d86e05db4f03805a23302d0307980837419e2c2772a0000000000000000000000000000000000000020000000000000000000000000736f6d6520455448206d7573742062652073656e7400000000000000000000000000000000000000000000000000000000000000000000000000000000000000cff3126cef560cd6a96c1a8e7744b5ba30409c1f2a3b912747b9cc8d343b7da2", - "deployedBytecode": "0x00020000000000020008000000000002000000000501034f000000000105001900000060011002700000010c0110019700010000001503550000008003000039000000400030043f00000001022001900000002f0000c13d000000040210008c0000033f0000413d000000000205043b000000e0022002700000010e0320009c000000370000a13d0000010f0320009c000000440000213d000001150320009c000000a50000213d000001180320009c0000013a0000613d000001190120009c0000033f0000c13d0000000001000416000000000101004b0000033f0000c13d0000003301000039000000000201041a00000123052001970000000003000411000000000335004b000001990000c13d0000013a02200197000000000021041b0000010c0100004100000000020004140000010c0320009c0000000002018019000000c00120021000000130011001c70000800d0200003900000003030000390000013b040000410000000006000019000001b70000013d0000000001000416000000000101004b0000033f0000c13d0000002001000039000001000010044300000120000004430000010d010000410000042a0001042e0000011a0320009c0000008a0000a13d0000011b0320009c000000c50000213d0000011e0320009c000000f00000613d0000011f0120009c0000033f0000c13d0000000001000416000000000101004b0000033f0000c13d0000009d01000039000001940000013d000001100320009c000000ce0000213d000001130320009c000001680000613d000001140220009c0000033f0000c13d0000000002000416000000000202004b0000033f0000c13d000000040110008a000000600110008c0000033f0000413d0000000401500370000000000401043b0000002401500370000000000601043b000001230160009c0000033f0000213d0000004401500370000000000301043b0000006501000039000000000101041a000000ff01100190000001a00000c13d0000009c01000039000000000101041a00000123011001970000000002000411000000000112004b000001bc0000c13d000400000003001d00000000004004350000009901000039000300000001001d000000200010043f0000010c0100004100000000020004140000010c0320009c0000000002018019000000c0012002100000012b011001c70000801002000039000600000004001d000500000006001d042904240000040f000000060300002900000001022001900000033f0000613d000000000101043b000000000101041a000000ff01100190000002f20000c13d000000400100043d00000044021000390000013703000041000000000032043500000024021000390000001c030000390000000000320435000001240200004100000000002104350000000402100039000000200300003900000000003204350000010c020000410000010c0310009c000000000102801900000040011002100000012e011001c70000042b00010430000001200320009c0000016d0000613d000001210320009c000001100000613d000001220120009c0000033f0000c13d0000000001000416000000000101004b0000033f0000c13d0000003301000039000000000101041a00000123011001970000000002000411000000000221004b000001990000c13d0000006502000039000000000302041a000000ff04300190000001aa0000c13d0000012401000041000000800010043f0000002001000039000000840010043f0000001401000039000000a40010043f0000014a01000041000001a70000013d000001160320009c0000017c0000613d000001170120009c0000033f0000c13d0000000001000416000000000101004b0000033f0000c13d0000003301000039000000000101041a00000123011001970000000002000411000000000221004b000001990000c13d0000006502000039000000000302041a000000ff04300190000001a00000c13d000001000400008a000000000343016f00000001033001bf000000000032041b000000800010043f0000010c0100004100000000020004140000010c0320009c0000000002018019000000c00120021000000138011001c70000800d0200003900000001030000390000013904000041000001b70000013d0000011c0320009c000001280000613d0000011d0120009c0000033f0000c13d0000000001000416000000000101004b0000033f0000c13d0000006501000039000001350000013d000001110320009c000001900000613d000001120220009c0000033f0000c13d0000000002000416000000000202004b0000033f0000c13d000000040110008a000000200110008c0000033f0000413d0000000401500370000000000101043b000001230210009c0000033f0000213d0000003302000039000000000202041a00000123022001970000000003000411000000000232004b000001990000c13d000000000201004b000001c40000c13d0000012401000041000000800010043f0000002001000039000000840010043f0000002601000039000000a40010043f0000012501000041000000c40010043f0000012601000041000000e40010043f00000127010000410000042b000104300000000002000416000000000202004b0000033f0000c13d000000040110008a000000400110008c0000033f0000413d0000000401500370000000000301043b000001230130009c0000033f0000213d0000002401500370000000000401043b000001230140009c0000033f0000213d000000000500041a0003ff0000500194000600000003001d000500000004001d000001c70000c13d000000ff0150019000000000020000190000000102006039000700000002001d0000000002000415000000070220008a0000000502200210000000000101004b000001cb0000c13d000001420150019700000101011001bf0000000006000019000001ef0000013d000000040110008a000000400110008c0000033f0000413d0000000401500370000000000301043b000001230130009c0000033f0000213d0000002401500370000000000401043b0000006501000039000000000101041a000000ff01100190000001a00000c13d0000000001000416000000000201004b000001fc0000c13d0000012401000041000000800010043f0000002001000039000000840010043f0000001501000039000000a40010043f0000015201000041000001a70000013d0000000002000416000000000202004b0000033f0000c13d000000040110008a000000200110008c0000033f0000413d0000000401500370000000000101043b00000000001004350000009901000039000000200010043f00000000010000190429040d0000040f000000000101041a000000ff011001900000000001000019000000010100c039000001960000013d0000000002000416000000000202004b0000033f0000c13d000000040110008a000000200110008c0000033f0000413d0006000000050353042903e90000040f0000004002100039000000000002043500000000010104360000000000010435000000060100035f0000000401100370000000000101043b00000000001004350000009801000039000000200010043f00000000010000190429040d0000040f000600000001001d042903e90000040f0000000605000029000000000205041a000001230220019700000000032104360000000104500039000000000404041a00000000004304350000000204500039000000000404041a00000040011000390000000000410435000000400400043d0000000002240436000000000303043300000000003204350000000001010433000000400240003900000000001204350000010c010000410000010c0240009c000000000401801900000040014002100000013c011001c70000042a0001042e0000000001000416000000000101004b0000033f0000c13d0000003301000039000001940000013d0000000002000416000000000202004b0000033f0000c13d000000040110008a000000200110008c0000033f0000413d0000000401500370000000000201043b000001230120009c0000033f0000213d000600000002001d042903f50000040f042903bb0000040f0000009c010000390000018a0000013d0000000002000416000000000202004b0000033f0000c13d000000040110008a000000200110008c0000033f0000413d0000000401500370000000000201043b000001230120009c0000033f0000213d000600000002001d042903f50000040f042903bb0000040f0000009d01000039000000000201041a0000013a0220019700000006022001af000000000021041b00000000010000190000042a0001042e0000000001000416000000000101004b0000033f0000c13d0000009c01000039000000000101041a0000012301100197000000800010043f00000128010000410000042a0001042e0000012401000041000000800010043f0000002001000039000000840010043f000000a40010043f0000014801000041000001a70000013d0000012401000041000000800010043f0000002001000039000000840010043f0000001001000039000000a40010043f0000014b01000041000000c40010043f0000012a010000410000042b00010430000001000400008a000000000343016f000000000032041b000000800010043f0000010c0100004100000000020004140000010c0320009c0000000002018019000000c00120021000000138011001c70000800d02000039000000010300003900000149040000410429041f0000040f00000001012001900000033f0000613d00000000010000190000042a0001042e0000012401000041000000800010043f0000002001000039000000840010043f0000001e01000039000000a40010043f0000012901000041000001a70000013d042903d30000040f00000000010000190000042a0001042e0000000002000415000000080220008a0000000502200210000800000000001d000400000002001d000200000005001d0000013d010000410000000000100439000000000100041000000004001004430000010c0100004100000000020004140000010c0320009c0000000002018019000000c0012002100000013e011001c70000800202000039042904240000040f0000000102200190000002990000613d000000000101043b000000000101004b000002a20000c13d0000000205000029000000ff0150018f000000010110008c0000000001000019000000010100603900000004020000290000000502200270000000000201001f000002a50000c13d000001000100008a000000000115016f000000010600003900000001011001bf000000030200006b000001420150619700000101011061bf0000000006006019000000000010041b0000ff0001100190000002ba0000c13d000000400100043d00000064021000390000014603000041000000000032043500000044021000390000014703000041000000000032043500000024021000390000002b03000039000002ae0000013d000000000241004b0000029a0000a13d000000e002000039000000400020043f000000800030043f0000000001410049000300000001001d000000a00010043f000400000004001d000000c00040043f0000009701000039000600000001001d000000000101041a00000000001004350000009801000039000000200010043f0000010c0400004100000000010004140000010c0210009c0000000001048019000000c0011002100000012b011001c70000801002000039000500000003001d042904240000040f00000001022001900000033f0000613d000000800200043d0000012302200197000000000101043b000000000301041a0000013a03300197000000000223019f000000000021041b0000000102100039000000a00300043d000000000032041b0000000201100039000000c00200043d000000000021041b0000000601000029000000000101041a00000000001004350000009901000039000000200010043f00000000010004140000010c0210009c0000010c01008041000000c0011002100000012b011001c70000801002000039042904240000040f00000001022001900000033f0000613d000000000101043b000000000201041a000001000300008a000000000232016f00000001022001bf000000000021041b0000000601000029000000000101041a00000000001004350000009a01000039000000200010043f0000010c0300004100000000010004140000010c0210009c0000000001038019000000c0011002100000012b011001c70000801002000039042904240000040f00000001022001900000033f0000613d000000000101043b000000000201041a0000013a022001970000000003000411000000000232019f000000000021041b0000000601000029000000000101041a00000000001004350000009b01000039000000200010043f0000014d01000041000000000010043900000000010004140000010c0210009c0000010c01008041000000c0011002100000014e011001c70000800b02000039042904240000040f0000000102200190000002990000613d000000000101043b000200000001001d0000010c0100004100000000020004140000010c0320009c0000000002018019000000c0012002100000012b011001c70000801002000039042904240000040f000000010220019000000006020000290000033f0000613d000000000101043b0000000203000029000000000031041b000000000202041a000000010100008a000200000002001d000000000112004b0000033b0000613d000000020400002900000001014000390000000602000029000000000012041b000000400100043d00000060021000390000000403000029000000000032043500000040021000390000000303000029000000000032043500000020021000390000000503000029000000000032043500000000004104350000010c0400004100000000020004140000010c0320009c00000000020480190000010c0310009c00000000010480190000004001100210000000c002200210000000000112019f0000014f011001c70000800d02000039000000010300003900000150040000410429041f0000040f00000001012001900000033f0000613d000000400100043d000000020200002900000000002104350000010c0210009c0000010c01008041000000400110021000000151011001c70000042a0001042e000000000001042f0000012401000041000000800010043f0000002001000039000000840010043f0000001e01000039000000a40010043f0000014c01000041000001a70000013d00000004010000290000000501100270000000000100001f000000400100043d00000064021000390000013f03000041000000000032043500000044021000390000014003000041000000000032043500000024021000390000002e030000390000000000320435000001240200004100000000002104350000000402100039000000200300003900000000003204350000010c020000410000010c0310009c0000000001028019000000400110021000000141011001c70000042b00010430000400000006001d000000000100041100000123061001970000003301000039000000000201041a0000013a03200197000000000363019f000000000031041b0000010c0100004100000000030004140000010c0430009c0000000003018019000000c00130021000000130011001c700000123052001970000800d0200003900000003030000390000013b040000410429041f0000040f0000000504000029000000060300002900000001012001900000033f0000613d0000009701000039000000000001041b0000009c01000039000000000201041a0000013a02200197000000000232019f000000000021041b0000009d01000039000000000201041a0000013a02200197000000000242019f000000000021041b000000040100006b000001ba0000c13d000000000200041a0000014301200197000000000010041b0000000103000039000000400100043d00000000003104350000010c0200004100000000040004140000010c0540009c00000000040280190000010c0510009c00000000010280190000004001100210000000c002400210000000000112019f00000144011001c70000800d020000390000014504000041000001b70000013d00000000003004350000009801000039000000200010043f0000010c0100004100000000020004140000010c0320009c0000000002018019000000c0012002100000012b011001c70000801002000039042904240000040f000000050500002900000001022001900000033f0000613d000000400200043d0000012c0320009c000003090000413d000001350100004100000000001004350000004101000039000000040010043f00000136010000410000042b00010430000000000101043b0000006003200039000000400030043f000000000301041a000001230330019700000000063204360000000104100039000000000404041a000200000006001d000000000046043500000040022000390000000201100039000000000101041a000100000002001d0000000000120435000000000153004b000003410000c13d00000002010000290000000001010433000000040110006c000003480000c13d000000060100002900000000001004350000000301000029000000200010043f0000010c0100004100000000020004140000010c0320009c0000000002018019000000c0012002100000012b011001c70000801002000039042904240000040f00000001022001900000033f0000613d000000000101043b000000000201041a000001000300008a000000000232016f000000000021041b00000002010000290000000001010433000000010200002900000000020204330000000003120019000000000123004b0000000001000019000000010100403900000001011001900000034f0000613d000001350100004100000000001004350000001101000039000003060000013d00000000010000190000042b00010430000000400100043d00000044021000390000012d03000041000000000032043500000024021000390000001e030000390000007e0000013d000000400100043d00000044021000390000012f030000410000000000320435000000240210003900000013030000390000007e0000013d0000009d01000039000500000001001d000000000201041a00000000010004140000012304200197000000040240008c000003590000c13d00000001020000390000000001000031000003690000013d0000010c020000410000010c0510009c0000000001028019000000c001100210000000000203004b000003610000c13d0000000002040019000003640000013d00000130011001c7000080090200003900000000050000190429041f0000040f000100000001035500000060011002700000010c0010019d0000010c01100197000000000301004b000003860000c13d000000400100043d0000000102200190000003b50000613d0000000502000029000000000202041a000000400310003900000004040000290000000000430435000001230220019700000020031000390000000000230435000000060200002900000000002104350000010c0200004100000000030004140000010c0430009c00000000030280190000010c0410009c00000000010280190000004001100210000000c002300210000000000112019f00000133011001c70000800d0200003900000001030000390000013404000041000001b70000013d000001310310009c000003030000213d0000001f03100039000000200400008a000000000343016f0000003f03300039000000000343016f000000400400043d0000000003340019000000000543004b00000000050000190000000105004039000001310630009c000003030000213d0000000105500190000003030000c13d000000400030043f0000001f0310018f000000000414043600000001050003670000000501100272000003a50000613d000000000600001900000005076002100000000008740019000000000775034f000000000707043b00000000007804350000000106600039000000000716004b0000039d0000413d000000000603004b0000036b0000613d0000000501100210000000000515034f00000000011400190000000303300210000000000401043300000000043401cf000000000434022f000000000505043b0000010003300089000000000535022f00000000033501cf000000000343019f00000000003104350000036b0000013d000000440210003900000132030000410000000000320435000000240210003900000010030000390000007e0000013d0000003301000039000000000101041a00000123011001970000000002000411000000000121004b000003c20000c13d000000000001042d000000400100043d00000044021000390000014803000041000000000032043500000124020000410000000000210435000000240210003900000020030000390000000000320435000000040210003900000000003204350000010c020000410000010c0310009c000000000102801900000040011002100000012e011001c70000042b0001043000000123061001970000003301000039000000000201041a0000013a03200197000000000363019f000000000031041b0000010c0100004100000000030004140000010c0430009c0000000003018019000000c00130021000000130011001c700000123052001970000800d0200003900000003030000390000013b040000410429041f0000040f0000000101200190000003e70000613d000000000001042d00000000010000190000042b00010430000000400100043d0000012c0210009c000003ef0000813d0000006002100039000000400020043f000000000001042d000001350100004100000000001004350000004101000039000000040010043f00000136010000410000042b000104300000006501000039000000000101041a000000ff01100190000003fa0000c13d000000000001042d000000400100043d00000044021000390000014b030000410000000000320435000000240210003900000010030000390000000000320435000001240200004100000000002104350000000402100039000000200300003900000000003204350000010c020000410000010c0310009c000000000102801900000040011002100000012e011001c70000042b00010430000000000001042f0000010c020000410000010c0310009c000000000102801900000000030004140000010c0430009c0000000003028019000000c0023002100000004001100210000000000121019f0000012b011001c70000801002000039042904240000040f00000001022001900000041d0000613d000000000101043b000000000001042d00000000010000190000042b0001043000000422002104210000000102000039000000000001042d0000000002000019000000000001042d00000427002104230000000102000039000000000001042d0000000002000019000000000001042d00000429000004320000042a0001042e0000042b00010430000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffff0000000200000000000000000000000000000040000001000000000000000000000000000000000000000000000000000000000000000000000000005fcb317b000000000000000000000000000000000000000000000000000000008da5cb5a00000000000000000000000000000000000000000000000000000000e2b2e23e00000000000000000000000000000000000000000000000000000000e2b2e23f00000000000000000000000000000000000000000000000000000000f2fde38b000000000000000000000000000000000000000000000000000000008da5cb5b00000000000000000000000000000000000000000000000000000000a5168739000000000000000000000000000000000000000000000000000000007b4437a6000000000000000000000000000000000000000000000000000000007b4437a7000000000000000000000000000000000000000000000000000000008456cb59000000000000000000000000000000000000000000000000000000005fcb317c00000000000000000000000000000000000000000000000000000000715018a600000000000000000000000000000000000000000000000000000000485cc954000000000000000000000000000000000000000000000000000000005a5d0a16000000000000000000000000000000000000000000000000000000005a5d0a17000000000000000000000000000000000000000000000000000000005c975abb00000000000000000000000000000000000000000000000000000000485cc955000000000000000000000000000000000000000000000000000000004c034fe00000000000000000000000000000000000000000000000000000000002ca15ee0000000000000000000000000000000000000000000000000000000012fe8e17000000000000000000000000000000000000000000000000000000003f4ba83a000000000000000000000000ffffffffffffffffffffffffffffffffffffffff08c379a0000000000000000000000000000000000000000000000000000000004f776e61626c653a206e6577206f776e657220697320746865207a65726f20616464726573730000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008400000080000000000000000000000000000000000000000000000000000000200000008000000000000000004f6e6c79205041594d454e545f52454749535452592063616e2063616c6c000000000000000000000000000000000000000000640000008000000000000000000200000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffa0726563697069656e745f61646472657373206e6f74206d61746368204c3100000000000000000000000000000000000000000064000000000000000000000000616d6f756e74206e6f74206d61746368204c31000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffff5472616e73666572206661696c65642e00000000000000000000000000000000020000000000000000000000000000000000006000000000000000000000000055188540052a206e959fa07e62a5f0542065989dcf08853e21b5668c778e46054e487b710000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000240000000000000000000000004f7264657220636c61696d6564206f72206e6f6e6578697374656e7400000000020000000000000000000000000000000000002000000080000000000000000062e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258ffffffffffffffffffffffff00000000000000000000000000000000000000008be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e000000000000000000000000000000000000000600000000000000000000000001806aa1896bbf26568e884a7374b41e002500962caba6a15023a8d90e8508b830200000200000000000000000000000000000024000000000000000000000000647920696e697469616c697a6564000000000000000000000000000000000000496e697469616c697a61626c653a20636f6e747261637420697320616c7265610000000000000000000000000000000000000084000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff02000000000000000000000000000000000000200000000000000000000000007f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024986e697469616c697a696e67000000000000000000000000000000000000000000496e697469616c697a61626c653a20636f6e7472616374206973206e6f7420694f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65725db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa5061757361626c653a206e6f74207061757365640000000000000000000000005061757361626c653a20706175736564000000000000000000000000000000004554482073656e74206d757374206265206d6f7265207468616e206665650000796b89b91644bc98cd93958e4c9038275d622183e25ac5af08cc6b5d95539132020000020000000000000000000000000000000400000000000000000000000002000000000000000000000000000000000000800000000000000000000000000dda38f349344fc4dd0c4d86e05db4f03805a23302d0307980837419e2c2772a0000000000000000000000000000000000000020000000000000000000000000736f6d6520455448206d7573742062652073656e7400000000000000000000000000000000000000000000000000000000000000000000000000000000000000cff3126cef560cd6a96c1a8e7744b5ba30409c1f2a3b912747b9cc8d343b7da2", + "bytecode": "0x0003000000000002000e000000000002000000000801034f000000000108001900000060011002700000015e01100197000200000018035500010000000803550000008003000039000000400030043f0000000102200190000000330000c13d000000040210008c0000047d0000413d000000000208043b000000e002200270000001600320009c0000003b0000213d0000016c0320009c000000590000213d000001720320009c000000aa0000213d000001750320009c0000010e0000613d000001760220009c0000047d0000c13d000000040110008a000000400110008c0000047d0000413d0000000401800370000000000101043b000c00000001001d000001770110009c0000047d0000213d0000002401800370000000000301043b0000006501000039000000000101041a000000ff01100190000002e20000c13d0000000001000416000000000201004b000003060000c13d0000017801000041000000800010043f0000002001000039000000840010043f0000001501000039000000a40010043f000001a901000041000002e90000013d0000000001000416000000000101004b0000047d0000c13d0000002001000039000001000010044300000120000004430000015f01000041000005750001042e000001610320009c000000640000213d000001670320009c000000c30000213d0000016a0320009c0000011d0000613d0000016b0120009c0000047d0000c13d0000000001000416000000000101004b0000047d0000c13d0000003301000039000000000201041a00000177052001970000000003000411000000000335004b000002db0000c13d0000018502200197000000000021041b0000015e0100004100000000020004140000015e0320009c0000000002018019000000c0012002100000017f011001c70000800d02000039000000030300003900000186040000410000000006000019000002f90000013d0000016d0320009c000000e30000213d000001700320009c0000014b0000613d000001710120009c0000047d0000c13d0000000001000416000000000101004b0000047d0000c13d0000009d01000039000002d60000013d000001620320009c000000ec0000213d000001650320009c0000016b0000613d000001660220009c0000047d0000c13d0000000002000416000000000202004b0000047d0000c13d000000040110008a000000600110008c0000047d0000413d0000000401800370000000000101043b000c00000001001d0000002401800370000000000101043b000b00000001001d000001770110009c0000047d0000213d0000004401800370000000000301043b0000006501000039000000000101041a000000ff01100190000002e20000c13d0000009c01000039000000000101041a00000177011001970000000002000411000000000112004b000002fe0000c13d000a00000003001d0000000c0100002900000000001004350000009901000039000900000001001d000000200010043f0000015e0100004100000000020004140000015e0320009c0000000002018019000000c0012002100000017d011001c700008010020000390574056f0000040f00000001022001900000047d0000613d000000000101043b000000000101041a000000ff01100190000004300000c13d000000400100043d0000004402100039000001a103000041000000000032043500000024021000390000001c030000390000000000320435000001780200004100000000002104350000000402100039000000200300003900000000003204350000015e020000410000015e0310009c000000000102801900000040011002100000019e011001c70000057600010430000001730320009c000001700000613d000001740120009c0000047d0000c13d0000000001000416000000000101004b0000047d0000c13d0000003301000039000000000101041a00000177011001970000000002000411000000000221004b000002db0000c13d0000006502000039000000000302041a000000ff04300190000002ec0000c13d0000017801000041000000800010043f0000002001000039000000840010043f0000001401000039000000a40010043f0000019601000041000002e90000013d000001680320009c000002ac0000613d000001690120009c0000047d0000c13d0000000001000416000000000101004b0000047d0000c13d0000003301000039000000000101041a00000177011001970000000002000411000000000221004b000002db0000c13d0000006502000039000000000302041a000000ff04300190000002e20000c13d000001000400008a000000000343016f00000001033001bf000000000032041b000000800010043f0000015e0100004100000000020004140000015e0320009c0000000002018019000000c00120021000000183011001c70000800d0200003900000001030000390000018404000041000002f90000013d0000016e0320009c000002c00000613d0000016f0120009c0000047d0000c13d0000000001000416000000000101004b0000047d0000c13d0000006501000039000002cd0000013d000001630320009c000002d20000613d000001640220009c0000047d0000c13d0000000002000416000000000202004b0000047d0000c13d000000040110008a000000200110008c0000047d0000413d0000000401800370000000000101043b000001770210009c0000047d0000213d0000003302000039000000000202041a00000177022001970000000003000411000000000232004b000002db0000c13d000000000201004b000003a30000c13d0000017801000041000000800010043f0000002001000039000000840010043f0000002601000039000000a40010043f0000017901000041000000c40010043f0000017a01000041000000e40010043f0000017b0100004100000576000104300000000002000416000000000202004b0000047d0000c13d000000040110008a000000200110008c0000047d0000413d0000000401800370000000000101043b000c00000001001d000001770110009c0000047d0000213d057405400000040f057405060000040f0000009c01000039000002ba0000013d0000000002000416000000000202004b0000047d0000c13d000000040110008a000000200110008c0000047d0000413d000c000000080353057405340000040f00000040021000390000000000020435000000000101043600000000000104350000000c0100035f0000000401100370000000000101043b00000000001004350000009801000039000000200010043f0000000001000019057405580000040f000c00000001001d057405340000040f0000000c05000029000000000205041a000001770220019700000000032104360000000104500039000000000404041a00000000004304350000000204500039000000000404041a00000040011000390000000000410435000000400400043d0000000002240436000000000303043300000000003204350000000001010433000000400240003900000000001204350000015e010000410000015e0240009c0000000004018019000000400140021000000187011001c7000005750001042e0000000002000416000000000202004b0000047d0000c13d000000040110008a000000400110008c0000047d0000413d0000000401800370000000000101043b000c00000001001d000001770110009c0000047d0000213d0000002401800370000000000101043b000b00000001001d000001770110009c0000047d0000213d000000000300041a0009ff0000300194000003a60000c13d000000ff0130019000000000020000190000000102006039000d00000002001d00000000020004150000000d0220008a0000000502200210000000000101004b000003aa0000c13d0000018d0130019700000101011001bf0000000004000019000003ce0000013d0000000001000416000000000101004b0000047d0000c13d0000003301000039000002d60000013d0000000002000416000000000202004b0000047d0000c13d000000040210008a000000600220008c0000047d0000413d0000000402800370000000000202043b000001800320009c0000047d0000213d00000023032000390000019704000041000000000513004b000000000500001900000000050480190000019703300197000000000603004b0000000004008019000001970330009c000000000405c019000000000304004b0000047d0000c13d0000000403200039000000000338034f000000000303043b000900000003001d000001800330009c0000047d0000213d000500240020003d000000090200002900000005022002100000000502200029000000000212004b0000047d0000213d0000002402800370000000000302043b000001800230009c0000047d0000213d00000023023000390000019704000041000000000512004b000000000500001900000000050480190000019702200197000000000602004b0000000004008019000001970220009c000000000405c019000000000204004b0000047d0000c13d0000000402300039000000000228034f000000000202043b000001800420009c0000047d0000213d000400240030003d00000005032002100000000403300029000000000313004b0000047d0000213d0000004403800370000000000403043b000001800340009c0000047d0000213d00000023034000390000019705000041000000000613004b000000000600001900000000060580190000019703300197000000000703004b0000000005008019000001970330009c000000000506c019000000000305004b0000047d0000c13d0000000403400039000000000338034f000000000303043b000001800530009c0000047d0000213d000300240040003d00000005043002100000000304400029000000000114004b0000047d0000213d0000006501000039000000000101041a000000ff01100190000002e20000c13d0000009c01000039000000000101041a00000177011001970000000004000411000000000114004b000002fe0000c13d000000090120006b000004970000c13d000000090130006b000004970000c13d000000090100006b000002fc0000613d000800990000003d000280100000003d000100980000003d000b00000000001d0000000b04000029000000050140021000000005031000290000000102000367000000000332034f000000000303043b000c00000003001d000000090340006c000005020000813d0000000403100029000000000332034f000000000303043b000700000003001d000001770330009c0000047d0000213d0000000301100029000000000112034f000000000101043b000a00000001001d0000000c0100002900000000001004350000000801000029000000200010043f00000000010004140000015e0210009c0000015e01008041000000c0011002100000017d011001c700000002020000290574056f0000040f00000001022001900000047d0000613d000000000101043b000000000101041a000000ff01100190000000980000613d0000000c0100002900000000001004350000000101000029000000200010043f00000000010004140000015e0210009c0000015e01008041000000c0011002100000017d011001c700008010020000390574056f0000040f00000001022001900000047d0000613d000000400200043d0000019c0320009c000004410000813d000000000101043b0000006003200039000000400030043f000000000301041a000001770330019700000000053204360000000104100039000000000404041a000000000045043500000040022000390000000201100039000000000101041a0000000000120435000000070130006c0000047f0000c13d000600000002001d000700000005001d00000000010504330000000a0110006c000004860000c13d0000000c0100002900000000001004350000000801000029000000200010043f00000000010004140000015e0210009c0000015e01008041000000c0011002100000017d011001c700008010020000390574056f0000040f00000001022001900000047d0000613d000000000101043b000000000201041a000001000300008a000000000232016f000000000021041b00000007010000290000000001010433000000060200002900000000020204330000000003120019000000000123004b000000000100001900000001010040390000000101100190000004790000c13d0000009d09000039000000000209041a00000000010004140000017704200197000000040240008c000002470000c13d00000001020000390000000001000031000002580000013d000700000009001d0000015e0210009c0000015e01008041000000c001100210000000000203004b000002510000613d0000017f011001c700008009020000390000000005000019000002520000013d00000000020400190574056a0000040f000200000001035500000060011002700000015e0010019d0000015e011001970000000709000029000000000301004b000002870000613d000001800310009c000004410000213d0000001f03100039000000200400008a000000000343016f0000003f03300039000000000443016f000000400300043d0000000004430019000000000534004b00000000050000190000000105004039000001800640009c000004410000213d0000000105500190000004410000c13d000000400040043f000000000313043600000002040003670000000505100272000002780000613d000000000600001900000005076002100000000008730019000000000774034f000000000707043b00000000007804350000000106600039000000000756004b000002700000413d0000001f01100190000002870000613d0000000505500210000000000454034f00000000035300190000000301100210000000000503043300000000051501cf000000000515022f000000000404043b0000010001100089000000000414022f00000000011401cf000000000151019f00000000001304350000000101200190000004fb0000613d000000000109041a000000400200043d00000040032000390000000a0400002900000000004304350000017701100197000000200320003900000000001304350000000c01000029000000000012043500000000010004140000015e0310009c0000015e0400004100000000010480190000015e0320009c00000000020480190000004002200210000000c001100210000000000121019f00000181011001c70000800d02000039000000010300003900000182040000410574056a0000040f00000001012001900000047d0000613d0000000b010000290000015e011001970000015e0210009c000004790000613d0000000102100039000b00000002001d000000090120006c000001da0000413d000002fc0000013d0000000002000416000000000202004b0000047d0000c13d000000040110008a000000200110008c0000047d0000413d0000000401800370000000000101043b000c00000001001d000001770110009c0000047d0000213d057405400000040f057405060000040f0000009d01000039000000000201041a00000185022001970000000c022001af000000000021041b0000000001000019000005750001042e0000000002000416000000000202004b0000047d0000c13d000000040110008a000000200110008c0000047d0000413d0000000401800370000000000101043b00000000001004350000009901000039000000200010043f0000000001000019057405580000040f000000000101041a000000ff011001900000000001000019000000010100c039000002d80000013d0000000001000416000000000101004b0000047d0000c13d0000009c01000039000000000101041a0000017701100197000000800010043f0000017c01000041000005750001042e0000017801000041000000800010043f0000002001000039000000840010043f000000a40010043f0000019301000041000002e90000013d0000017801000041000000800010043f0000002001000039000000840010043f0000001001000039000000a40010043f000001a201000041000000c40010043f00000194010000410000057600010430000001000400008a000000000343016f000000000032041b000000800010043f0000015e0100004100000000020004140000015e0320009c0000000002018019000000c00120021000000183011001c70000800d02000039000000010300003900000195040000410574056a0000040f00000001012001900000047d0000613d0000000001000019000005750001042e0000017801000041000000800010043f0000002001000039000000840010043f0000001e01000039000000a40010043f0000019801000041000002e90000013d000000000231004b000003dc0000a13d000000e002000039000000400020043f0000000c02000029000000800020043f0000000001310049000900000001001d000000a00010043f000a00000003001d000000c00030043f0000009701000039000b00000001001d000000000101041a00000000001004350000009801000039000000200010043f0000015e0300004100000000010004140000015e0210009c0000000001038019000000c0011002100000017d011001c700008010020000390574056f0000040f00000001022001900000047d0000613d000000800200043d0000017702200197000000000101043b000000000301041a0000018503300197000000000223019f000000000021041b0000000102100039000000a00300043d000000000032041b0000000201100039000000c00200043d000000000021041b0000000b01000029000000000101041a00000000001004350000009901000039000000200010043f00000000010004140000015e0210009c0000015e01008041000000c0011002100000017d011001c700008010020000390574056f0000040f00000001022001900000047d0000613d000000000101043b000000000201041a000001000300008a000000000232016f00000001022001bf000000000021041b0000000b01000029000000000101041a00000000001004350000009a01000039000000200010043f0000015e0300004100000000010004140000015e0210009c0000000001038019000000c0011002100000017d011001c700008010020000390574056f0000040f00000001022001900000047d0000613d000000000101043b000000000201041a00000185022001970000000003000411000000000232019f000000000021041b0000000b01000029000000000101041a00000000001004350000009b01000039000000200010043f000001a401000041000000000010043900000000010004140000015e0210009c0000015e01008041000000c001100210000001a5011001c70000800b020000390574056f0000040f0000000102200190000003db0000613d000000000101043b000800000001001d0000015e0100004100000000020004140000015e0320009c0000000002018019000000c0012002100000017d011001c700008010020000390574056f0000040f00000001022001900000047d0000613d000000000101043b0000000802000029000000000021041b0000000b01000029000000000201041a000000010100008a000800000002001d000000000112004b000004790000613d000000080400002900000001014000390000000b02000029000000000012041b000000400100043d00000060021000390000000a03000029000000000032043500000040021000390000000903000029000000000032043500000020021000390000000c03000029000000000032043500000000004104350000015e0400004100000000020004140000015e0320009c00000000020480190000015e0310009c00000000010480190000004001100210000000c002200210000000000112019f000001a6011001c70000800d020000390000000103000039000001a7040000410574056a0000040f00000001012001900000047d0000613d000000400100043d000000080200002900000000002104350000015e0210009c0000015e010080410000004001100210000001a8011001c7000005750001042e0574051e0000040f0000000001000019000005750001042e00000000020004150000000e0220008a0000000502200210000e00000000001d000a00000002001d000800000003001d00000188010000410000000000100439000000000100041000000004001004430000015e0100004100000000020004140000015e0320009c0000000002018019000000c00120021000000189011001c700008002020000390574056f0000040f0000000102200190000003db0000613d000000000101043b000000000101004b000003e40000c13d0000000803000029000000ff0130018f000000010110008c000000000100001900000001010060390000000a020000290000000502200270000000000201001f000003e70000c13d000001000100008a000000000113016f000000010400003900000001011001bf000000090200006b0000018d0130619700000101011061bf0000000004006019000000000010041b0000ff0001100190000003fc0000c13d000000400100043d00000064021000390000019103000041000000000032043500000044021000390000019203000041000000000032043500000024021000390000002b03000039000003f00000013d000000000001042f0000017801000041000000800010043f0000002001000039000000840010043f0000001e01000039000000a40010043f000001a301000041000002e90000013d0000000a010000290000000501100270000000000100001f000000400100043d00000064021000390000018a03000041000000000032043500000044021000390000018b03000041000000000032043500000024021000390000002e030000390000000000320435000001780200004100000000002104350000000402100039000000200300003900000000003204350000015e020000410000015e0310009c000000000102801900000040011002100000018c011001c70000057600010430000a00000004001d000000000100041100000177061001970000003301000039000000000201041a0000018503200197000000000363019f000000000031041b0000015e0100004100000000030004140000015e0430009c0000000003018019000000c0013002100000017f011001c700000177052001970000800d02000039000000030300003900000186040000410574056a0000040f00000001012001900000047d0000613d0000009c01000039000000000201041a00000185022001970000000c022001af000000000021041b0000009d01000039000000000201041a00000185022001970000000b022001af000000000021041b0000000a0100006b000002fc0000c13d000000000200041a0000018e01200197000000000010041b0000000103000039000000400100043d00000000003104350000015e0200004100000000040004140000015e0540009c00000000040280190000015e0510009c00000000010280190000004001100210000000c002400210000000000112019f0000018f011001c70000800d020000390000019004000041000002f90000013d0000000c0100002900000000001004350000009801000039000000200010043f0000015e0100004100000000020004140000015e0320009c0000000002018019000000c0012002100000017d011001c700008010020000390574056f0000040f00000001022001900000047d0000613d000000400200043d0000017e0320009c000004470000a13d0000019a0100004100000000001004350000004101000039000000040010043f0000019b010000410000057600010430000000000101043b0000006003200039000000400030043f000000000301041a000001770330019700000000053204360000000104100039000000000404041a000800000005001d000000000045043500000040022000390000000201100039000000000101041a000700000002001d00000000001204350000000b0130006c0000047f0000c13d000000080100002900000000010104330000000a0110006c000004860000c13d0000000c0100002900000000001004350000000901000029000000200010043f0000015e0100004100000000020004140000015e0320009c0000000002018019000000c0012002100000017d011001c700008010020000390574056f0000040f00000001022001900000047d0000613d000000000101043b000000000201041a000001000300008a000000000232016f000000000021041b00000008010000290000000001010433000000070200002900000000020204330000000003120019000000000123004b0000000001000019000000010100403900000001011001900000048d0000613d0000019a0100004100000000001004350000001101000039000004440000013d00000000010000190000057600010430000000400100043d00000044021000390000019d03000041000000000032043500000024021000390000001e030000390000009e0000013d000000400100043d00000044021000390000019f030000410000000000320435000000240210003900000013030000390000009e0000013d0000009d01000039000b00000001001d000000000201041a00000000010004140000017704200197000000040240008c0000049f0000c13d00000001020000390000000001000031000004af0000013d0000017801000041000000800010043f0000002001000039000000840010043f0000000f01000039000000a40010043f0000019901000041000002e90000013d0000015e020000410000015e0510009c0000000001028019000000c001100210000000000203004b000004a70000c13d0000000002040019000004aa0000013d0000017f011001c7000080090200003900000000050000190574056a0000040f000200000001035500000060011002700000015e0010019d0000015e01100197000000000301004b000004cc0000c13d0000000101200190000004fb0000613d0000000b01000029000000000101041a000000400200043d00000040032000390000000a0400002900000000004304350000017701100197000000200320003900000000001304350000000c0100002900000000001204350000015e0100004100000000030004140000015e0430009c00000000030180190000015e0420009c00000000020180190000004001200210000000c002300210000000000112019f00000181011001c70000800d0200003900000001030000390000018204000041000002f90000013d000001800310009c000004410000213d0000001f03100039000000200400008a000000000343016f0000003f03300039000000000343016f000000400400043d0000000003340019000000000543004b00000000050000190000000105004039000001800630009c000004410000213d0000000105500190000004410000c13d000000400030043f0000001f0310018f000000000414043600000002050003670000000501100272000004eb0000613d000000000600001900000005076002100000000008740019000000000775034f000000000707043b00000000007804350000000106600039000000000716004b000004e30000413d000000000603004b000004b10000613d0000000501100210000000000515034f00000000011400190000000303300210000000000401043300000000043401cf000000000434022f000000000505043b0000010003300089000000000535022f00000000033501cf000000000343019f0000000000310435000004b10000013d000000400100043d0000004402100039000001a0030000410000000000320435000000240210003900000010030000390000009e0000013d0000019a0100004100000000001004350000003201000039000004440000013d0000003301000039000000000101041a00000177011001970000000002000411000000000121004b0000050d0000c13d000000000001042d000000400100043d00000044021000390000019303000041000000000032043500000178020000410000000000210435000000240210003900000020030000390000000000320435000000040210003900000000003204350000015e020000410000015e0310009c000000000102801900000040011002100000019e011001c7000005760001043000000177061001970000003301000039000000000201041a0000018503200197000000000363019f000000000031041b0000015e0100004100000000030004140000015e0430009c0000000003018019000000c0013002100000017f011001c700000177052001970000800d02000039000000030300003900000186040000410574056a0000040f0000000101200190000005320000613d000000000001042d00000000010000190000057600010430000000400100043d0000019c0210009c0000053a0000813d0000006002100039000000400020043f000000000001042d0000019a0100004100000000001004350000004101000039000000040010043f0000019b0100004100000576000104300000006501000039000000000101041a000000ff01100190000005450000c13d000000000001042d000000400100043d0000004402100039000001a2030000410000000000320435000000240210003900000010030000390000000000320435000001780200004100000000002104350000000402100039000000200300003900000000003204350000015e020000410000015e0310009c000000000102801900000040011002100000019e011001c70000057600010430000000000001042f0000015e020000410000015e0310009c000000000102801900000000030004140000015e0430009c0000000003028019000000c0023002100000004001100210000000000121019f0000017d011001c700008010020000390574056f0000040f0000000102200190000005680000613d000000000101043b000000000001042d000000000100001900000576000104300000056d002104210000000102000039000000000001042d0000000002000019000000000001042d00000572002104230000000102000039000000000001042d0000000002000019000000000001042d0000057400000432000005750001042e0000057600010430000000000000000000000000000000000000000000000000000000000000000000000000ffffffff0000000200000000000000000000000000000040000001000000000000000000000000000000000000000000000000000000000000000000000000005fcb317b000000000000000000000000000000000000000000000000000000008da5cb5a00000000000000000000000000000000000000000000000000000000e2b2e23e00000000000000000000000000000000000000000000000000000000e2b2e23f00000000000000000000000000000000000000000000000000000000f2fde38b000000000000000000000000000000000000000000000000000000008da5cb5b00000000000000000000000000000000000000000000000000000000a5168739000000000000000000000000000000000000000000000000000000007b4437a6000000000000000000000000000000000000000000000000000000007b4437a7000000000000000000000000000000000000000000000000000000008456cb59000000000000000000000000000000000000000000000000000000005fcb317c00000000000000000000000000000000000000000000000000000000715018a600000000000000000000000000000000000000000000000000000000485cc954000000000000000000000000000000000000000000000000000000005a5d0a16000000000000000000000000000000000000000000000000000000005a5d0a17000000000000000000000000000000000000000000000000000000005c975abb00000000000000000000000000000000000000000000000000000000485cc955000000000000000000000000000000000000000000000000000000004c034fe000000000000000000000000000000000000000000000000000000000156be1ad00000000000000000000000000000000000000000000000000000000156be1ae000000000000000000000000000000000000000000000000000000003f4ba83a0000000000000000000000000000000000000000000000000000000002ca15ee0000000000000000000000000000000000000000000000000000000012fe8e17000000000000000000000000ffffffffffffffffffffffffffffffffffffffff08c379a0000000000000000000000000000000000000000000000000000000004f776e61626c653a206e6577206f776e657220697320746865207a65726f20616464726573730000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008400000080000000000000000000000000000000000000000000000000000000200000008000000000000000000200000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffff9f0200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffff020000000000000000000000000000000000006000000000000000000000000055188540052a206e959fa07e62a5f0542065989dcf08853e21b5668c778e4605020000000000000000000000000000000000002000000080000000000000000062e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258ffffffffffffffffffffffff00000000000000000000000000000000000000008be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e000000000000000000000000000000000000000600000000000000000000000001806aa1896bbf26568e884a7374b41e002500962caba6a15023a8d90e8508b830200000200000000000000000000000000000024000000000000000000000000647920696e697469616c697a6564000000000000000000000000000000000000496e697469616c697a61626c653a20636f6e747261637420697320616c7265610000000000000000000000000000000000000084000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff02000000000000000000000000000000000000200000000000000000000000007f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024986e697469616c697a696e67000000000000000000000000000000000000000000496e697469616c697a61626c653a20636f6e7472616374206973206e6f7420694f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657200000000000000000000000000000000000000640000008000000000000000005db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa5061757361626c653a206e6f742070617573656400000000000000000000000080000000000000000000000000000000000000000000000000000000000000004f6e6c79205041594d454e545f52454749535452592063616e2063616c6c0000496e76616c6964206c656e6774687300000000000000000000000000000000004e487b71000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffa0726563697069656e745f61646472657373206e6f74206d61746368204c3100000000000000000000000000000000000000000064000000000000000000000000616d6f756e74206e6f74206d61746368204c31000000000000000000000000005472616e73666572206661696c65642e000000000000000000000000000000004f7264657220636c61696d6564206f72206e6f6e6578697374656e74000000005061757361626c653a20706175736564000000000000000000000000000000004554482073656e74206d757374206265206d6f7265207468616e206665650000796b89b91644bc98cd93958e4c9038275d622183e25ac5af08cc6b5d95539132020000020000000000000000000000000000000400000000000000000000000002000000000000000000000000000000000000800000000000000000000000000dda38f349344fc4dd0c4d86e05db4f03805a23302d0307980837419e2c2772a0000000000000000000000000000000000000020000000000000000000000000736f6d6520455448206d7573742062652073656e74000000000000000000000026a0e90b81f50f500dc69a94d9ae02005a5e2f98f543c055002ebb68b4f974b7", + "deployedBytecode": "0x0003000000000002000e000000000002000000000801034f000000000108001900000060011002700000015e01100197000200000018035500010000000803550000008003000039000000400030043f0000000102200190000000330000c13d000000040210008c0000047d0000413d000000000208043b000000e002200270000001600320009c0000003b0000213d0000016c0320009c000000590000213d000001720320009c000000aa0000213d000001750320009c0000010e0000613d000001760220009c0000047d0000c13d000000040110008a000000400110008c0000047d0000413d0000000401800370000000000101043b000c00000001001d000001770110009c0000047d0000213d0000002401800370000000000301043b0000006501000039000000000101041a000000ff01100190000002e20000c13d0000000001000416000000000201004b000003060000c13d0000017801000041000000800010043f0000002001000039000000840010043f0000001501000039000000a40010043f000001a901000041000002e90000013d0000000001000416000000000101004b0000047d0000c13d0000002001000039000001000010044300000120000004430000015f01000041000005750001042e000001610320009c000000640000213d000001670320009c000000c30000213d0000016a0320009c0000011d0000613d0000016b0120009c0000047d0000c13d0000000001000416000000000101004b0000047d0000c13d0000003301000039000000000201041a00000177052001970000000003000411000000000335004b000002db0000c13d0000018502200197000000000021041b0000015e0100004100000000020004140000015e0320009c0000000002018019000000c0012002100000017f011001c70000800d02000039000000030300003900000186040000410000000006000019000002f90000013d0000016d0320009c000000e30000213d000001700320009c0000014b0000613d000001710120009c0000047d0000c13d0000000001000416000000000101004b0000047d0000c13d0000009d01000039000002d60000013d000001620320009c000000ec0000213d000001650320009c0000016b0000613d000001660220009c0000047d0000c13d0000000002000416000000000202004b0000047d0000c13d000000040110008a000000600110008c0000047d0000413d0000000401800370000000000101043b000c00000001001d0000002401800370000000000101043b000b00000001001d000001770110009c0000047d0000213d0000004401800370000000000301043b0000006501000039000000000101041a000000ff01100190000002e20000c13d0000009c01000039000000000101041a00000177011001970000000002000411000000000112004b000002fe0000c13d000a00000003001d0000000c0100002900000000001004350000009901000039000900000001001d000000200010043f0000015e0100004100000000020004140000015e0320009c0000000002018019000000c0012002100000017d011001c700008010020000390574056f0000040f00000001022001900000047d0000613d000000000101043b000000000101041a000000ff01100190000004300000c13d000000400100043d0000004402100039000001a103000041000000000032043500000024021000390000001c030000390000000000320435000001780200004100000000002104350000000402100039000000200300003900000000003204350000015e020000410000015e0310009c000000000102801900000040011002100000019e011001c70000057600010430000001730320009c000001700000613d000001740120009c0000047d0000c13d0000000001000416000000000101004b0000047d0000c13d0000003301000039000000000101041a00000177011001970000000002000411000000000221004b000002db0000c13d0000006502000039000000000302041a000000ff04300190000002ec0000c13d0000017801000041000000800010043f0000002001000039000000840010043f0000001401000039000000a40010043f0000019601000041000002e90000013d000001680320009c000002ac0000613d000001690120009c0000047d0000c13d0000000001000416000000000101004b0000047d0000c13d0000003301000039000000000101041a00000177011001970000000002000411000000000221004b000002db0000c13d0000006502000039000000000302041a000000ff04300190000002e20000c13d000001000400008a000000000343016f00000001033001bf000000000032041b000000800010043f0000015e0100004100000000020004140000015e0320009c0000000002018019000000c00120021000000183011001c70000800d0200003900000001030000390000018404000041000002f90000013d0000016e0320009c000002c00000613d0000016f0120009c0000047d0000c13d0000000001000416000000000101004b0000047d0000c13d0000006501000039000002cd0000013d000001630320009c000002d20000613d000001640220009c0000047d0000c13d0000000002000416000000000202004b0000047d0000c13d000000040110008a000000200110008c0000047d0000413d0000000401800370000000000101043b000001770210009c0000047d0000213d0000003302000039000000000202041a00000177022001970000000003000411000000000232004b000002db0000c13d000000000201004b000003a30000c13d0000017801000041000000800010043f0000002001000039000000840010043f0000002601000039000000a40010043f0000017901000041000000c40010043f0000017a01000041000000e40010043f0000017b0100004100000576000104300000000002000416000000000202004b0000047d0000c13d000000040110008a000000200110008c0000047d0000413d0000000401800370000000000101043b000c00000001001d000001770110009c0000047d0000213d057405400000040f057405060000040f0000009c01000039000002ba0000013d0000000002000416000000000202004b0000047d0000c13d000000040110008a000000200110008c0000047d0000413d000c000000080353057405340000040f00000040021000390000000000020435000000000101043600000000000104350000000c0100035f0000000401100370000000000101043b00000000001004350000009801000039000000200010043f0000000001000019057405580000040f000c00000001001d057405340000040f0000000c05000029000000000205041a000001770220019700000000032104360000000104500039000000000404041a00000000004304350000000204500039000000000404041a00000040011000390000000000410435000000400400043d0000000002240436000000000303043300000000003204350000000001010433000000400240003900000000001204350000015e010000410000015e0240009c0000000004018019000000400140021000000187011001c7000005750001042e0000000002000416000000000202004b0000047d0000c13d000000040110008a000000400110008c0000047d0000413d0000000401800370000000000101043b000c00000001001d000001770110009c0000047d0000213d0000002401800370000000000101043b000b00000001001d000001770110009c0000047d0000213d000000000300041a0009ff0000300194000003a60000c13d000000ff0130019000000000020000190000000102006039000d00000002001d00000000020004150000000d0220008a0000000502200210000000000101004b000003aa0000c13d0000018d0130019700000101011001bf0000000004000019000003ce0000013d0000000001000416000000000101004b0000047d0000c13d0000003301000039000002d60000013d0000000002000416000000000202004b0000047d0000c13d000000040210008a000000600220008c0000047d0000413d0000000402800370000000000202043b000001800320009c0000047d0000213d00000023032000390000019704000041000000000513004b000000000500001900000000050480190000019703300197000000000603004b0000000004008019000001970330009c000000000405c019000000000304004b0000047d0000c13d0000000403200039000000000338034f000000000303043b000900000003001d000001800330009c0000047d0000213d000500240020003d000000090200002900000005022002100000000502200029000000000212004b0000047d0000213d0000002402800370000000000302043b000001800230009c0000047d0000213d00000023023000390000019704000041000000000512004b000000000500001900000000050480190000019702200197000000000602004b0000000004008019000001970220009c000000000405c019000000000204004b0000047d0000c13d0000000402300039000000000228034f000000000202043b000001800420009c0000047d0000213d000400240030003d00000005032002100000000403300029000000000313004b0000047d0000213d0000004403800370000000000403043b000001800340009c0000047d0000213d00000023034000390000019705000041000000000613004b000000000600001900000000060580190000019703300197000000000703004b0000000005008019000001970330009c000000000506c019000000000305004b0000047d0000c13d0000000403400039000000000338034f000000000303043b000001800530009c0000047d0000213d000300240040003d00000005043002100000000304400029000000000114004b0000047d0000213d0000006501000039000000000101041a000000ff01100190000002e20000c13d0000009c01000039000000000101041a00000177011001970000000004000411000000000114004b000002fe0000c13d000000090120006b000004970000c13d000000090130006b000004970000c13d000000090100006b000002fc0000613d000800990000003d000280100000003d000100980000003d000b00000000001d0000000b04000029000000050140021000000005031000290000000102000367000000000332034f000000000303043b000c00000003001d000000090340006c000005020000813d0000000403100029000000000332034f000000000303043b000700000003001d000001770330009c0000047d0000213d0000000301100029000000000112034f000000000101043b000a00000001001d0000000c0100002900000000001004350000000801000029000000200010043f00000000010004140000015e0210009c0000015e01008041000000c0011002100000017d011001c700000002020000290574056f0000040f00000001022001900000047d0000613d000000000101043b000000000101041a000000ff01100190000000980000613d0000000c0100002900000000001004350000000101000029000000200010043f00000000010004140000015e0210009c0000015e01008041000000c0011002100000017d011001c700008010020000390574056f0000040f00000001022001900000047d0000613d000000400200043d0000019c0320009c000004410000813d000000000101043b0000006003200039000000400030043f000000000301041a000001770330019700000000053204360000000104100039000000000404041a000000000045043500000040022000390000000201100039000000000101041a0000000000120435000000070130006c0000047f0000c13d000600000002001d000700000005001d00000000010504330000000a0110006c000004860000c13d0000000c0100002900000000001004350000000801000029000000200010043f00000000010004140000015e0210009c0000015e01008041000000c0011002100000017d011001c700008010020000390574056f0000040f00000001022001900000047d0000613d000000000101043b000000000201041a000001000300008a000000000232016f000000000021041b00000007010000290000000001010433000000060200002900000000020204330000000003120019000000000123004b000000000100001900000001010040390000000101100190000004790000c13d0000009d09000039000000000209041a00000000010004140000017704200197000000040240008c000002470000c13d00000001020000390000000001000031000002580000013d000700000009001d0000015e0210009c0000015e01008041000000c001100210000000000203004b000002510000613d0000017f011001c700008009020000390000000005000019000002520000013d00000000020400190574056a0000040f000200000001035500000060011002700000015e0010019d0000015e011001970000000709000029000000000301004b000002870000613d000001800310009c000004410000213d0000001f03100039000000200400008a000000000343016f0000003f03300039000000000443016f000000400300043d0000000004430019000000000534004b00000000050000190000000105004039000001800640009c000004410000213d0000000105500190000004410000c13d000000400040043f000000000313043600000002040003670000000505100272000002780000613d000000000600001900000005076002100000000008730019000000000774034f000000000707043b00000000007804350000000106600039000000000756004b000002700000413d0000001f01100190000002870000613d0000000505500210000000000454034f00000000035300190000000301100210000000000503043300000000051501cf000000000515022f000000000404043b0000010001100089000000000414022f00000000011401cf000000000151019f00000000001304350000000101200190000004fb0000613d000000000109041a000000400200043d00000040032000390000000a0400002900000000004304350000017701100197000000200320003900000000001304350000000c01000029000000000012043500000000010004140000015e0310009c0000015e0400004100000000010480190000015e0320009c00000000020480190000004002200210000000c001100210000000000121019f00000181011001c70000800d02000039000000010300003900000182040000410574056a0000040f00000001012001900000047d0000613d0000000b010000290000015e011001970000015e0210009c000004790000613d0000000102100039000b00000002001d000000090120006c000001da0000413d000002fc0000013d0000000002000416000000000202004b0000047d0000c13d000000040110008a000000200110008c0000047d0000413d0000000401800370000000000101043b000c00000001001d000001770110009c0000047d0000213d057405400000040f057405060000040f0000009d01000039000000000201041a00000185022001970000000c022001af000000000021041b0000000001000019000005750001042e0000000002000416000000000202004b0000047d0000c13d000000040110008a000000200110008c0000047d0000413d0000000401800370000000000101043b00000000001004350000009901000039000000200010043f0000000001000019057405580000040f000000000101041a000000ff011001900000000001000019000000010100c039000002d80000013d0000000001000416000000000101004b0000047d0000c13d0000009c01000039000000000101041a0000017701100197000000800010043f0000017c01000041000005750001042e0000017801000041000000800010043f0000002001000039000000840010043f000000a40010043f0000019301000041000002e90000013d0000017801000041000000800010043f0000002001000039000000840010043f0000001001000039000000a40010043f000001a201000041000000c40010043f00000194010000410000057600010430000001000400008a000000000343016f000000000032041b000000800010043f0000015e0100004100000000020004140000015e0320009c0000000002018019000000c00120021000000183011001c70000800d02000039000000010300003900000195040000410574056a0000040f00000001012001900000047d0000613d0000000001000019000005750001042e0000017801000041000000800010043f0000002001000039000000840010043f0000001e01000039000000a40010043f0000019801000041000002e90000013d000000000231004b000003dc0000a13d000000e002000039000000400020043f0000000c02000029000000800020043f0000000001310049000900000001001d000000a00010043f000a00000003001d000000c00030043f0000009701000039000b00000001001d000000000101041a00000000001004350000009801000039000000200010043f0000015e0300004100000000010004140000015e0210009c0000000001038019000000c0011002100000017d011001c700008010020000390574056f0000040f00000001022001900000047d0000613d000000800200043d0000017702200197000000000101043b000000000301041a0000018503300197000000000223019f000000000021041b0000000102100039000000a00300043d000000000032041b0000000201100039000000c00200043d000000000021041b0000000b01000029000000000101041a00000000001004350000009901000039000000200010043f00000000010004140000015e0210009c0000015e01008041000000c0011002100000017d011001c700008010020000390574056f0000040f00000001022001900000047d0000613d000000000101043b000000000201041a000001000300008a000000000232016f00000001022001bf000000000021041b0000000b01000029000000000101041a00000000001004350000009a01000039000000200010043f0000015e0300004100000000010004140000015e0210009c0000000001038019000000c0011002100000017d011001c700008010020000390574056f0000040f00000001022001900000047d0000613d000000000101043b000000000201041a00000185022001970000000003000411000000000232019f000000000021041b0000000b01000029000000000101041a00000000001004350000009b01000039000000200010043f000001a401000041000000000010043900000000010004140000015e0210009c0000015e01008041000000c001100210000001a5011001c70000800b020000390574056f0000040f0000000102200190000003db0000613d000000000101043b000800000001001d0000015e0100004100000000020004140000015e0320009c0000000002018019000000c0012002100000017d011001c700008010020000390574056f0000040f00000001022001900000047d0000613d000000000101043b0000000802000029000000000021041b0000000b01000029000000000201041a000000010100008a000800000002001d000000000112004b000004790000613d000000080400002900000001014000390000000b02000029000000000012041b000000400100043d00000060021000390000000a03000029000000000032043500000040021000390000000903000029000000000032043500000020021000390000000c03000029000000000032043500000000004104350000015e0400004100000000020004140000015e0320009c00000000020480190000015e0310009c00000000010480190000004001100210000000c002200210000000000112019f000001a6011001c70000800d020000390000000103000039000001a7040000410574056a0000040f00000001012001900000047d0000613d000000400100043d000000080200002900000000002104350000015e0210009c0000015e010080410000004001100210000001a8011001c7000005750001042e0574051e0000040f0000000001000019000005750001042e00000000020004150000000e0220008a0000000502200210000e00000000001d000a00000002001d000800000003001d00000188010000410000000000100439000000000100041000000004001004430000015e0100004100000000020004140000015e0320009c0000000002018019000000c00120021000000189011001c700008002020000390574056f0000040f0000000102200190000003db0000613d000000000101043b000000000101004b000003e40000c13d0000000803000029000000ff0130018f000000010110008c000000000100001900000001010060390000000a020000290000000502200270000000000201001f000003e70000c13d000001000100008a000000000113016f000000010400003900000001011001bf000000090200006b0000018d0130619700000101011061bf0000000004006019000000000010041b0000ff0001100190000003fc0000c13d000000400100043d00000064021000390000019103000041000000000032043500000044021000390000019203000041000000000032043500000024021000390000002b03000039000003f00000013d000000000001042f0000017801000041000000800010043f0000002001000039000000840010043f0000001e01000039000000a40010043f000001a301000041000002e90000013d0000000a010000290000000501100270000000000100001f000000400100043d00000064021000390000018a03000041000000000032043500000044021000390000018b03000041000000000032043500000024021000390000002e030000390000000000320435000001780200004100000000002104350000000402100039000000200300003900000000003204350000015e020000410000015e0310009c000000000102801900000040011002100000018c011001c70000057600010430000a00000004001d000000000100041100000177061001970000003301000039000000000201041a0000018503200197000000000363019f000000000031041b0000015e0100004100000000030004140000015e0430009c0000000003018019000000c0013002100000017f011001c700000177052001970000800d02000039000000030300003900000186040000410574056a0000040f00000001012001900000047d0000613d0000009c01000039000000000201041a00000185022001970000000c022001af000000000021041b0000009d01000039000000000201041a00000185022001970000000b022001af000000000021041b0000000a0100006b000002fc0000c13d000000000200041a0000018e01200197000000000010041b0000000103000039000000400100043d00000000003104350000015e0200004100000000040004140000015e0540009c00000000040280190000015e0510009c00000000010280190000004001100210000000c002400210000000000112019f0000018f011001c70000800d020000390000019004000041000002f90000013d0000000c0100002900000000001004350000009801000039000000200010043f0000015e0100004100000000020004140000015e0320009c0000000002018019000000c0012002100000017d011001c700008010020000390574056f0000040f00000001022001900000047d0000613d000000400200043d0000017e0320009c000004470000a13d0000019a0100004100000000001004350000004101000039000000040010043f0000019b010000410000057600010430000000000101043b0000006003200039000000400030043f000000000301041a000001770330019700000000053204360000000104100039000000000404041a000800000005001d000000000045043500000040022000390000000201100039000000000101041a000700000002001d00000000001204350000000b0130006c0000047f0000c13d000000080100002900000000010104330000000a0110006c000004860000c13d0000000c0100002900000000001004350000000901000029000000200010043f0000015e0100004100000000020004140000015e0320009c0000000002018019000000c0012002100000017d011001c700008010020000390574056f0000040f00000001022001900000047d0000613d000000000101043b000000000201041a000001000300008a000000000232016f000000000021041b00000008010000290000000001010433000000070200002900000000020204330000000003120019000000000123004b0000000001000019000000010100403900000001011001900000048d0000613d0000019a0100004100000000001004350000001101000039000004440000013d00000000010000190000057600010430000000400100043d00000044021000390000019d03000041000000000032043500000024021000390000001e030000390000009e0000013d000000400100043d00000044021000390000019f030000410000000000320435000000240210003900000013030000390000009e0000013d0000009d01000039000b00000001001d000000000201041a00000000010004140000017704200197000000040240008c0000049f0000c13d00000001020000390000000001000031000004af0000013d0000017801000041000000800010043f0000002001000039000000840010043f0000000f01000039000000a40010043f0000019901000041000002e90000013d0000015e020000410000015e0510009c0000000001028019000000c001100210000000000203004b000004a70000c13d0000000002040019000004aa0000013d0000017f011001c7000080090200003900000000050000190574056a0000040f000200000001035500000060011002700000015e0010019d0000015e01100197000000000301004b000004cc0000c13d0000000101200190000004fb0000613d0000000b01000029000000000101041a000000400200043d00000040032000390000000a0400002900000000004304350000017701100197000000200320003900000000001304350000000c0100002900000000001204350000015e0100004100000000030004140000015e0430009c00000000030180190000015e0420009c00000000020180190000004001200210000000c002300210000000000112019f00000181011001c70000800d0200003900000001030000390000018204000041000002f90000013d000001800310009c000004410000213d0000001f03100039000000200400008a000000000343016f0000003f03300039000000000343016f000000400400043d0000000003340019000000000543004b00000000050000190000000105004039000001800630009c000004410000213d0000000105500190000004410000c13d000000400030043f0000001f0310018f000000000414043600000002050003670000000501100272000004eb0000613d000000000600001900000005076002100000000008740019000000000775034f000000000707043b00000000007804350000000106600039000000000716004b000004e30000413d000000000603004b000004b10000613d0000000501100210000000000515034f00000000011400190000000303300210000000000401043300000000043401cf000000000434022f000000000505043b0000010003300089000000000535022f00000000033501cf000000000343019f0000000000310435000004b10000013d000000400100043d0000004402100039000001a0030000410000000000320435000000240210003900000010030000390000009e0000013d0000019a0100004100000000001004350000003201000039000004440000013d0000003301000039000000000101041a00000177011001970000000002000411000000000121004b0000050d0000c13d000000000001042d000000400100043d00000044021000390000019303000041000000000032043500000178020000410000000000210435000000240210003900000020030000390000000000320435000000040210003900000000003204350000015e020000410000015e0310009c000000000102801900000040011002100000019e011001c7000005760001043000000177061001970000003301000039000000000201041a0000018503200197000000000363019f000000000031041b0000015e0100004100000000030004140000015e0430009c0000000003018019000000c0013002100000017f011001c700000177052001970000800d02000039000000030300003900000186040000410574056a0000040f0000000101200190000005320000613d000000000001042d00000000010000190000057600010430000000400100043d0000019c0210009c0000053a0000813d0000006002100039000000400020043f000000000001042d0000019a0100004100000000001004350000004101000039000000040010043f0000019b0100004100000576000104300000006501000039000000000101041a000000ff01100190000005450000c13d000000000001042d000000400100043d0000004402100039000001a2030000410000000000320435000000240210003900000010030000390000000000320435000001780200004100000000002104350000000402100039000000200300003900000000003204350000015e020000410000015e0310009c000000000102801900000040011002100000019e011001c70000057600010430000000000001042f0000015e020000410000015e0310009c000000000102801900000000030004140000015e0430009c0000000003028019000000c0023002100000004001100210000000000121019f0000017d011001c700008010020000390574056f0000040f0000000102200190000005680000613d000000000101043b000000000001042d000000000100001900000576000104300000056d002104210000000102000039000000000001042d0000000002000019000000000001042d00000572002104230000000102000039000000000001042d0000000002000019000000000001042d0000057400000432000005750001042e0000057600010430000000000000000000000000000000000000000000000000000000000000000000000000ffffffff0000000200000000000000000000000000000040000001000000000000000000000000000000000000000000000000000000000000000000000000005fcb317b000000000000000000000000000000000000000000000000000000008da5cb5a00000000000000000000000000000000000000000000000000000000e2b2e23e00000000000000000000000000000000000000000000000000000000e2b2e23f00000000000000000000000000000000000000000000000000000000f2fde38b000000000000000000000000000000000000000000000000000000008da5cb5b00000000000000000000000000000000000000000000000000000000a5168739000000000000000000000000000000000000000000000000000000007b4437a6000000000000000000000000000000000000000000000000000000007b4437a7000000000000000000000000000000000000000000000000000000008456cb59000000000000000000000000000000000000000000000000000000005fcb317c00000000000000000000000000000000000000000000000000000000715018a600000000000000000000000000000000000000000000000000000000485cc954000000000000000000000000000000000000000000000000000000005a5d0a16000000000000000000000000000000000000000000000000000000005a5d0a17000000000000000000000000000000000000000000000000000000005c975abb00000000000000000000000000000000000000000000000000000000485cc955000000000000000000000000000000000000000000000000000000004c034fe000000000000000000000000000000000000000000000000000000000156be1ad00000000000000000000000000000000000000000000000000000000156be1ae000000000000000000000000000000000000000000000000000000003f4ba83a0000000000000000000000000000000000000000000000000000000002ca15ee0000000000000000000000000000000000000000000000000000000012fe8e17000000000000000000000000ffffffffffffffffffffffffffffffffffffffff08c379a0000000000000000000000000000000000000000000000000000000004f776e61626c653a206e6577206f776e657220697320746865207a65726f20616464726573730000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008400000080000000000000000000000000000000000000000000000000000000200000008000000000000000000200000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffff9f0200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffff020000000000000000000000000000000000006000000000000000000000000055188540052a206e959fa07e62a5f0542065989dcf08853e21b5668c778e4605020000000000000000000000000000000000002000000080000000000000000062e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258ffffffffffffffffffffffff00000000000000000000000000000000000000008be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e000000000000000000000000000000000000000600000000000000000000000001806aa1896bbf26568e884a7374b41e002500962caba6a15023a8d90e8508b830200000200000000000000000000000000000024000000000000000000000000647920696e697469616c697a6564000000000000000000000000000000000000496e697469616c697a61626c653a20636f6e747261637420697320616c7265610000000000000000000000000000000000000084000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff02000000000000000000000000000000000000200000000000000000000000007f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024986e697469616c697a696e67000000000000000000000000000000000000000000496e697469616c697a61626c653a20636f6e7472616374206973206e6f7420694f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657200000000000000000000000000000000000000640000008000000000000000005db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa5061757361626c653a206e6f742070617573656400000000000000000000000080000000000000000000000000000000000000000000000000000000000000004f6e6c79205041594d454e545f52454749535452592063616e2063616c6c0000496e76616c6964206c656e6774687300000000000000000000000000000000004e487b71000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffa0726563697069656e745f61646472657373206e6f74206d61746368204c3100000000000000000000000000000000000000000064000000000000000000000000616d6f756e74206e6f74206d61746368204c31000000000000000000000000005472616e73666572206661696c65642e000000000000000000000000000000004f7264657220636c61696d6564206f72206e6f6e6578697374656e74000000005061757361626c653a20706175736564000000000000000000000000000000004554482073656e74206d757374206265206d6f7265207468616e206665650000796b89b91644bc98cd93958e4c9038275d622183e25ac5af08cc6b5d95539132020000020000000000000000000000000000000400000000000000000000000002000000000000000000000000000000000000800000000000000000000000000dda38f349344fc4dd0c4d86e05db4f03805a23302d0307980837419e2c2772a0000000000000000000000000000000000000020000000000000000000000000736f6d6520455448206d7573742062652073656e74000000000000000000000026a0e90b81f50f500dc69a94d9ae02005a5e2f98f543c055002ebb68b4f974b7", "linkReferences": {}, "deployedLinkReferences": {}, "factoryDeps": {} diff --git a/mm-bot/abi/PaymentRegistry.json b/mm-bot/abi/PaymentRegistry.json index 79100403..19f3ea78 100644 --- a/mm-bot/abi/PaymentRegistry.json +++ b/mm-bot/abi/PaymentRegistry.json @@ -1 +1 @@ -{"abi":[{"type":"constructor","inputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"StarknetEscrowAddress","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"StarknetEscrowClaimPaymentSelector","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"UPGRADE_INTERFACE_VERSION","inputs":[],"outputs":[{"name":"","type":"string","internalType":"string"}],"stateMutability":"view"},{"type":"function","name":"ZKSyncEscrowAddress","inputs":[],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"view"},{"type":"function","name":"claimPayment","inputs":[{"name":"orderId","type":"uint256","internalType":"uint256"},{"name":"destAddress","type":"uint256","internalType":"uint256"},{"name":"amount","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"payable"},{"type":"function","name":"claimPaymentZKSync","inputs":[{"name":"orderId","type":"uint256","internalType":"uint256"},{"name":"destAddress","type":"uint256","internalType":"uint256"},{"name":"amount","type":"uint256","internalType":"uint256"},{"name":"gasLimit","type":"uint256","internalType":"uint256"},{"name":"gasPerPubdataByteLimit","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"payable"},{"type":"function","name":"initialize","inputs":[{"name":"snMessaging","type":"address","internalType":"address"},{"name":"StarknetEscrowAddress_","type":"uint256","internalType":"uint256"},{"name":"StarknetEscrowClaimPaymentSelector_","type":"uint256","internalType":"uint256"},{"name":"marketMaker_","type":"address","internalType":"address"},{"name":"ZKSyncMailboxAddress","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"marketMaker","inputs":[],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"view"},{"type":"function","name":"owner","inputs":[],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"view"},{"type":"function","name":"proxiableUUID","inputs":[],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"type":"function","name":"renounceOwnership","inputs":[],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"setMMAddress","inputs":[{"name":"newMMAddress","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"setStarknetClaimPaymentSelector","inputs":[{"name":"NewStarknetEscrowClaimPaymentSelector","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"setStarknetEscrowAddress","inputs":[{"name":"newStarknetEscrowAddress","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"setZKSyncEscrowAddress","inputs":[{"name":"newZKSyncEscrowAddress","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"transfer","inputs":[{"name":"orderId","type":"uint256","internalType":"uint256"},{"name":"destAddress","type":"uint256","internalType":"uint256"},{"name":"chainId","type":"uint8","internalType":"enum PaymentRegistry.Chain"}],"outputs":[],"stateMutability":"payable"},{"type":"function","name":"transferOwnership","inputs":[{"name":"newOwner","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"transfers","inputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"outputs":[{"name":"destAddress","type":"uint256","internalType":"uint256"},{"name":"amount","type":"uint256","internalType":"uint256"},{"name":"isUsed","type":"bool","internalType":"bool"},{"name":"chainId","type":"uint8","internalType":"enum PaymentRegistry.Chain"}],"stateMutability":"view"},{"type":"function","name":"upgradeToAndCall","inputs":[{"name":"newImplementation","type":"address","internalType":"address"},{"name":"data","type":"bytes","internalType":"bytes"}],"outputs":[],"stateMutability":"payable"},{"type":"event","name":"ClaimPayment","inputs":[{"name":"transferInfo","type":"tuple","indexed":false,"internalType":"struct PaymentRegistry.TransferInfo","components":[{"name":"destAddress","type":"uint256","internalType":"uint256"},{"name":"amount","type":"uint256","internalType":"uint256"},{"name":"isUsed","type":"bool","internalType":"bool"},{"name":"chainId","type":"uint8","internalType":"enum PaymentRegistry.Chain"}]}],"anonymous":false},{"type":"event","name":"Initialized","inputs":[{"name":"version","type":"uint64","indexed":false,"internalType":"uint64"}],"anonymous":false},{"type":"event","name":"ModifiedStarknetClaimPaymentSelector","inputs":[{"name":"newEscrowClaimPaymentSelector","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false},{"type":"event","name":"ModifiedStarknetEscrowAddress","inputs":[{"name":"newEscrowAddress","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false},{"type":"event","name":"ModifiedZKSyncEscrowAddress","inputs":[{"name":"newEscrowAddress","type":"address","indexed":false,"internalType":"address"}],"anonymous":false},{"type":"event","name":"OwnershipTransferred","inputs":[{"name":"previousOwner","type":"address","indexed":true,"internalType":"address"},{"name":"newOwner","type":"address","indexed":true,"internalType":"address"}],"anonymous":false},{"type":"event","name":"Transfer","inputs":[{"name":"orderId","type":"uint256","indexed":true,"internalType":"uint256"},{"name":"srcAddress","type":"address","indexed":false,"internalType":"address"},{"name":"transferInfo","type":"tuple","indexed":false,"internalType":"struct PaymentRegistry.TransferInfo","components":[{"name":"destAddress","type":"uint256","internalType":"uint256"},{"name":"amount","type":"uint256","internalType":"uint256"},{"name":"isUsed","type":"bool","internalType":"bool"},{"name":"chainId","type":"uint8","internalType":"enum PaymentRegistry.Chain"}]}],"anonymous":false},{"type":"event","name":"Upgraded","inputs":[{"name":"implementation","type":"address","indexed":true,"internalType":"address"}],"anonymous":false},{"type":"error","name":"AddressEmptyCode","inputs":[{"name":"target","type":"address","internalType":"address"}]},{"type":"error","name":"ERC1967InvalidImplementation","inputs":[{"name":"implementation","type":"address","internalType":"address"}]},{"type":"error","name":"ERC1967NonPayable","inputs":[]},{"type":"error","name":"FailedInnerCall","inputs":[]},{"type":"error","name":"InvalidInitialization","inputs":[]},{"type":"error","name":"NotInitializing","inputs":[]},{"type":"error","name":"OwnableInvalidOwner","inputs":[{"name":"owner","type":"address","internalType":"address"}]},{"type":"error","name":"OwnableUnauthorizedAccount","inputs":[{"name":"account","type":"address","internalType":"address"}]},{"type":"error","name":"UUPSUnauthorizedCallContext","inputs":[]},{"type":"error","name":"UUPSUnsupportedProxiableUUID","inputs":[{"name":"slot","type":"bytes32","internalType":"bytes32"}]}],"bytecode":{"object":"0x60a06040523060805234801561001457600080fd5b5061001d610022565b6100d4565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000900460ff16156100725760405163f92ee8a960e01b815260040160405180910390fd5b80546001600160401b03908116146100d15780546001600160401b0319166001600160401b0390811782556040519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50565b6080516118ba6100fd60003960008181610ea701528181610ed0015261101601526118ba6000f3fe6080604052600436106101145760003560e01c8063942b8aea116100a0578063d71b8af011610064578063d71b8af01461030a578063d788f4c91461031d578063f04193c814610333578063f12ba5c714610353578063f2fde38b1461037357600080fd5b8063942b8aea14610259578063a713961114610279578063acfefa5214610299578063ad3cb1cc146102b9578063c1f9789a146102f757600080fd5b80633c64f04b116100e75780633c64f04b146101af5780634f1ef2861461020757806352d1902d1461021a578063715018a61461022f5780638da5cb5b1461024457600080fd5b806303b54d52146101195780630b5e4f1a1461013b5780631519e9611461014e5780631f21f9af14610177575b600080fd5b34801561012557600080fd5b5061013961013436600461133e565b610393565b005b610139610149366004611395565b6104f6565b34801561015a57600080fd5b5061016460025481565b6040519081526020015b60405180910390f35b34801561018357600080fd5b50600154610197906001600160a01b031681565b6040516001600160a01b03909116815260200161016e565b3480156101bb57600080fd5b506101f76101ca3660046113d0565b60006020819052908152604090208054600182015460029092015490919060ff8082169161010090041684565b60405161016e9493929190611421565b610139610215366004611463565b610724565b34801561022657600080fd5b50610164610743565b34801561023b57600080fd5b50610139610760565b34801561025057600080fd5b50610197610774565b34801561026557600080fd5b50600354610197906001600160a01b031681565b34801561028557600080fd5b50610139610294366004611525565b6107a2565b3480156102a557600080fd5b506101396102b4366004611525565b6107cc565b3480156102c557600080fd5b506102ea604051806040016040528060058152602001640352e302e360dc1b81525081565b60405161016e9190611590565b6101396103053660046115a3565b610829565b6101396103183660046115cf565b610ab4565b34801561032957600080fd5b5061016460045481565b34801561033f57600080fd5b5061013961034e3660046113d0565b610dcb565b34801561035f57600080fd5b5061013961036e3660046113d0565b610e08565b34801561037f57600080fd5b5061013961038e366004611525565b610e45565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a008054600160401b810460ff16159067ffffffffffffffff166000811580156103d95750825b905060008267ffffffffffffffff1660011480156103f65750303b155b905081158015610404575080155b156104225760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff19166001178555831561044c57845460ff60401b1916600160401b1785555b61045533610e83565b61045d610e94565b600680546001600160a01b03808d166001600160a01b0319928316179092556005805489841690831617905560028b905560048a905560018054928a169290911691909117905583156104ea57845460ff60401b19168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50505050505050505050565b6104fe610774565b6001600160a01b0316336001600160a01b0316148061052757506001546001600160a01b031633145b61054c5760405162461bcd60e51b81526004016105439061160c565b60405180910390fd5b600085858560016040516020016105669493929190611653565b60408051601f198184030181529181528151602092830120600081815292839052912060028101549192509060ff1615156001146105dc5760405162461bcd60e51b81526020600482015260136024820152722a3930b739b332b9103737ba103337bab7321760691b6044820152606401610543565b8054600182015460408051602481018b905260448101939093526064808401929092528051808403909201825260849092018252602080820180516001600160e01b031663a516873960e01b9081179091526005546003548551600080825294810190965291946001600160a01b039182169363eb672419933493169186908c908c908461067a565b60608152602001906001900390816106655790505b50336040518963ffffffff1660e01b815260040161069e9796959493929190611698565b60206040518083038185885af11580156106bc573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906106e19190611744565b507ffa14b57aae01dabbdf4c90231f1f49bb52566fa986bb22b81214a82d0e8d973183604051610711919061178e565b60405180910390a1505050505050505050565b61072c610e9c565b61073582610f41565b61073f8282610f49565b5050565b600061074d61100b565b5060008051602061186583398151915290565b610768611054565b6107726000611086565b565b7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b031690565b6107aa611054565b600180546001600160a01b0319166001600160a01b0392909216919091179055565b6107d4611054565b600380546001600160a01b0319166001600160a01b0383169081179091556040519081527f266bbe7a56974619c1a655bf40e2622705681de7ad5b9ad8f776b574816ef878906020015b60405180910390a150565b610831610774565b6001600160a01b0316336001600160a01b0316148061085a57506001546001600160a01b031633145b6108765760405162461bcd60e51b81526004016105439061160c565b600083838360006040516020016108909493929190611653565b60408051601f198184030181529181528151602092830120600081815292839052912060028101549192509060ff1615156001146109065760405162461bcd60e51b81526020600482015260136024820152722a3930b739b332b9103737ba103337bab7321760691b6044820152606401610543565b60408051600580825260c082019092526000916020820160a080368337019050509050856001600160801b0316816000815181106109465761094661179c565b602002602001018181525050608086901c6001600160801b0316816001815181106109735761097361179c565b6020026020010181815250508160000154816002815181106109975761099761179c565b602002602001018181525050836001600160801b0316816003815181106109c0576109c061179c565b602002602001018181525050608084901c6001600160801b0316816004815181106109ed576109ed61179c565b602090810291909101015260065460025460048054604051633e3aa6c560e01b81526001600160a01b0390941693633e3aa6c5933493610a319391928891016117b2565b604080518083038185885af1158015610a4e573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190610a739190611807565b50507ffa14b57aae01dabbdf4c90231f1f49bb52566fa986bb22b81214a82d0e8d973182604051610aa4919061178e565b60405180910390a1505050505050565b610abc610774565b6001600160a01b0316336001600160a01b03161480610ae557506001546001600160a01b031633145b610b015760405162461bcd60e51b81526004016105439061160c565b81600003610b515760405162461bcd60e51b815260206004820152601c60248201527f496e76616c69642064657374696e6174696f6e20616464726573732e000000006044820152606401610543565b60003411610bb25760405162461bcd60e51b815260206004820152602860248201527f496e76616c696420616d6f756e742c2073686f756c6420626520686967686572604482015267103a3430b710181760c11b6064820152608401610543565b600083833484604051602001610bcb9493929190611653565b60408051601f19818403018152918152815160209283012060008181529283905291206002015490915060ff1615610c455760405162461bcd60e51b815260206004820152601b60248201527f5472616e7366657220616c72656164792070726f6365737365642e00000000006044820152606401610543565b6040518060800160405280848152602001348152602001600115158152602001836001811115610c7757610c776113e9565b90526000828152602081815260409182902083518155908301516001808301919091559183015160028201805491151560ff1983168117825560608601519394919261ff001990911661ffff199091161790610100908490811115610cde57610cde6113e9565b021790555050604051600091506001600160a01b0385169034908381818185875af1925050503d8060008114610d30576040519150601f19603f3d011682016040523d82523d6000602084013e610d35565b606091505b5050905080610d795760405162461bcd60e51b815260206004820152601060248201526f2a3930b739b332b9103330b4b632b21760811b6044820152606401610543565b847fa021626d9973eaecfbeb0e17352f56e3e9b32891f48c11cc1c2c248a2559f79a33600080868152602001908152602001600020604051610dbc92919061182b565b60405180910390a25050505050565b610dd3611054565b60028190556040518181527f770ea1f0ec3952d2a87b139d66a1ac5d469acba670449df142953a082c7e4e809060200161081e565b610e10611054565b60048190556040518181527f531414f0fe764471786064a701ebc067e829c6ea0aa005fc180afb5c75d5e7d29060200161081e565b610e4d611054565b6001600160a01b038116610e7757604051631e4fbdf760e01b815260006004820152602401610543565b610e8081611086565b50565b610e8b6110f7565b610e8081611140565b6107726110f7565b306001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161480610f2357507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316610f17600080516020611865833981519152546001600160a01b031690565b6001600160a01b031614155b156107725760405163703e46dd60e11b815260040160405180910390fd5b610e80611054565b816001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015610fa3575060408051601f3d908101601f19168201909252610fa091810190611744565b60015b610fcb57604051634c9c8ce360e01b81526001600160a01b0383166004820152602401610543565b6000805160206118658339815191528114610ffc57604051632a87526960e21b815260048101829052602401610543565b6110068383611148565b505050565b306001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146107725760405163703e46dd60e11b815260040160405180910390fd5b3361105d610774565b6001600160a01b0316146107725760405163118cdaa760e01b8152336004820152602401610543565b7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930080546001600160a01b031981166001600160a01b03848116918217845560405192169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3505050565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0054600160401b900460ff1661077257604051631afcd79f60e31b815260040160405180910390fd5b610e4d6110f7565b6111518261119e565b6040516001600160a01b038316907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a2805115611196576110068282611203565b61073f61127b565b806001600160a01b03163b6000036111d457604051634c9c8ce360e01b81526001600160a01b0382166004820152602401610543565b60008051602061186583398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b6060600080846001600160a01b0316846040516112209190611848565b600060405180830381855af49150503d806000811461125b576040519150601f19603f3d011682016040523d82523d6000602084013e611260565b606091505b509150915061127085838361129a565b925050505b92915050565b34156107725760405163b398979f60e01b815260040160405180910390fd5b6060826112af576112aa826112f9565b6112f2565b81511580156112c657506001600160a01b0384163b155b156112ef57604051639996b31560e01b81526001600160a01b0385166004820152602401610543565b50805b9392505050565b8051156113095780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b80356001600160a01b038116811461133957600080fd5b919050565b600080600080600060a0868803121561135657600080fd5b61135f86611322565b9450602086013593506040860135925061137b60608701611322565b915061138960808701611322565b90509295509295909350565b600080600080600060a086880312156113ad57600080fd5b505083359560208501359550604085013594606081013594506080013592509050565b6000602082840312156113e257600080fd5b5035919050565b634e487b7160e01b600052602160045260246000fd5b6002811061141d57634e487b7160e01b600052602160045260246000fd5b9052565b8481526020810184905282151560408201526080810161144460608301846113ff565b95945050505050565b634e487b7160e01b600052604160045260246000fd5b6000806040838503121561147657600080fd5b61147f83611322565b9150602083013567ffffffffffffffff8082111561149c57600080fd5b818501915085601f8301126114b057600080fd5b8135818111156114c2576114c261144d565b604051601f8201601f19908116603f011681019083821181831017156114ea576114ea61144d565b8160405282815288602084870101111561150357600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b60006020828403121561153757600080fd5b6112f282611322565b60005b8381101561155b578181015183820152602001611543565b50506000910152565b6000815180845261157c816020860160208601611540565b601f01601f19169290920160200192915050565b6020815260006112f26020830184611564565b6000806000606084860312156115b857600080fd5b505081359360208301359350604090920135919050565b6000806000606084860312156115e457600080fd5b833592506020840135915060408401356002811061160157600080fd5b809150509250925092565b60208082526027908201527f4f6e6c79204f776e6572206f72204d4d2063616e2063616c6c207468697320666040820152663ab731ba34b7b760c91b606082015260800190565b84815283602082015282604082015260006002831061168257634e487b7160e01b600052602160045260246000fd5b5060f89190911b60608201526061019392505050565b60018060a01b038816815260006020888184015260e060408401526116c060e0840189611564565b87606085015286608085015283810360a08501528086518083528383019150838160051b84010184890160005b8381101561171b57601f19868403018552611709838351611564565b948701949250908601906001016116ed565b50506001600160a01b03881660c088015294506117389350505050565b98975050505050505050565b60006020828403121561175657600080fd5b5051919050565b8054825260018101546020830152600281015460ff8116151560408401526110066060840160ff8360081c166113ff565b60808101611275828461175d565b634e487b7160e01b600052603260045260246000fd5b6000606082018583526020858185015260606040850152818551808452608086019150828701935060005b818110156117f9578451835293830193918301916001016117dd565b509098975050505050505050565b6000806040838503121561181a57600080fd5b505080516020909101519092909150565b6001600160a01b038316815260a081016112f2602083018461175d565b6000825161185a818460208701611540565b919091019291505056fe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbca26469706673582212205650497c1c47e61f69b1b2641b596da321a6c987272e95d3305e223efd2c094264736f6c63430008140033","sourceMap":"494:6220:49:-:0;;;1171:4:34;1128:48;;1497:53:49;;;;;;;;;-1:-1:-1;1521:22:49;:20;:22::i;:::-;494:6220;;7711:422:33;8870:21;7900:15;;;;;;;7896:76;;;7938:23;;-1:-1:-1;;;7938:23:33;;;;;;;;;;;7896:76;7985:14;;-1:-1:-1;;;;;7985:14:33;;;:34;7981:146;;8035:33;;-1:-1:-1;;;;;;8035:33:33;-1:-1:-1;;;;;8035:33:33;;;;;8087:29;;158:50:54;;;8087:29:33;;146:2:54;131:18;8087:29:33;;;;;;;7981:146;7760:373;7711:422::o;14:200:54:-;494:6220:49;;;;;;;;;;;;;;;;;;;;;;","linkReferences":{}},"deployedBytecode":{"object":"0x6080604052600436106101145760003560e01c8063942b8aea116100a0578063d71b8af011610064578063d71b8af01461030a578063d788f4c91461031d578063f04193c814610333578063f12ba5c714610353578063f2fde38b1461037357600080fd5b8063942b8aea14610259578063a713961114610279578063acfefa5214610299578063ad3cb1cc146102b9578063c1f9789a146102f757600080fd5b80633c64f04b116100e75780633c64f04b146101af5780634f1ef2861461020757806352d1902d1461021a578063715018a61461022f5780638da5cb5b1461024457600080fd5b806303b54d52146101195780630b5e4f1a1461013b5780631519e9611461014e5780631f21f9af14610177575b600080fd5b34801561012557600080fd5b5061013961013436600461133e565b610393565b005b610139610149366004611395565b6104f6565b34801561015a57600080fd5b5061016460025481565b6040519081526020015b60405180910390f35b34801561018357600080fd5b50600154610197906001600160a01b031681565b6040516001600160a01b03909116815260200161016e565b3480156101bb57600080fd5b506101f76101ca3660046113d0565b60006020819052908152604090208054600182015460029092015490919060ff8082169161010090041684565b60405161016e9493929190611421565b610139610215366004611463565b610724565b34801561022657600080fd5b50610164610743565b34801561023b57600080fd5b50610139610760565b34801561025057600080fd5b50610197610774565b34801561026557600080fd5b50600354610197906001600160a01b031681565b34801561028557600080fd5b50610139610294366004611525565b6107a2565b3480156102a557600080fd5b506101396102b4366004611525565b6107cc565b3480156102c557600080fd5b506102ea604051806040016040528060058152602001640352e302e360dc1b81525081565b60405161016e9190611590565b6101396103053660046115a3565b610829565b6101396103183660046115cf565b610ab4565b34801561032957600080fd5b5061016460045481565b34801561033f57600080fd5b5061013961034e3660046113d0565b610dcb565b34801561035f57600080fd5b5061013961036e3660046113d0565b610e08565b34801561037f57600080fd5b5061013961038e366004611525565b610e45565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a008054600160401b810460ff16159067ffffffffffffffff166000811580156103d95750825b905060008267ffffffffffffffff1660011480156103f65750303b155b905081158015610404575080155b156104225760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff19166001178555831561044c57845460ff60401b1916600160401b1785555b61045533610e83565b61045d610e94565b600680546001600160a01b03808d166001600160a01b0319928316179092556005805489841690831617905560028b905560048a905560018054928a169290911691909117905583156104ea57845460ff60401b19168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50505050505050505050565b6104fe610774565b6001600160a01b0316336001600160a01b0316148061052757506001546001600160a01b031633145b61054c5760405162461bcd60e51b81526004016105439061160c565b60405180910390fd5b600085858560016040516020016105669493929190611653565b60408051601f198184030181529181528151602092830120600081815292839052912060028101549192509060ff1615156001146105dc5760405162461bcd60e51b81526020600482015260136024820152722a3930b739b332b9103737ba103337bab7321760691b6044820152606401610543565b8054600182015460408051602481018b905260448101939093526064808401929092528051808403909201825260849092018252602080820180516001600160e01b031663a516873960e01b9081179091526005546003548551600080825294810190965291946001600160a01b039182169363eb672419933493169186908c908c908461067a565b60608152602001906001900390816106655790505b50336040518963ffffffff1660e01b815260040161069e9796959493929190611698565b60206040518083038185885af11580156106bc573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906106e19190611744565b507ffa14b57aae01dabbdf4c90231f1f49bb52566fa986bb22b81214a82d0e8d973183604051610711919061178e565b60405180910390a1505050505050505050565b61072c610e9c565b61073582610f41565b61073f8282610f49565b5050565b600061074d61100b565b5060008051602061186583398151915290565b610768611054565b6107726000611086565b565b7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b031690565b6107aa611054565b600180546001600160a01b0319166001600160a01b0392909216919091179055565b6107d4611054565b600380546001600160a01b0319166001600160a01b0383169081179091556040519081527f266bbe7a56974619c1a655bf40e2622705681de7ad5b9ad8f776b574816ef878906020015b60405180910390a150565b610831610774565b6001600160a01b0316336001600160a01b0316148061085a57506001546001600160a01b031633145b6108765760405162461bcd60e51b81526004016105439061160c565b600083838360006040516020016108909493929190611653565b60408051601f198184030181529181528151602092830120600081815292839052912060028101549192509060ff1615156001146109065760405162461bcd60e51b81526020600482015260136024820152722a3930b739b332b9103737ba103337bab7321760691b6044820152606401610543565b60408051600580825260c082019092526000916020820160a080368337019050509050856001600160801b0316816000815181106109465761094661179c565b602002602001018181525050608086901c6001600160801b0316816001815181106109735761097361179c565b6020026020010181815250508160000154816002815181106109975761099761179c565b602002602001018181525050836001600160801b0316816003815181106109c0576109c061179c565b602002602001018181525050608084901c6001600160801b0316816004815181106109ed576109ed61179c565b602090810291909101015260065460025460048054604051633e3aa6c560e01b81526001600160a01b0390941693633e3aa6c5933493610a319391928891016117b2565b604080518083038185885af1158015610a4e573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190610a739190611807565b50507ffa14b57aae01dabbdf4c90231f1f49bb52566fa986bb22b81214a82d0e8d973182604051610aa4919061178e565b60405180910390a1505050505050565b610abc610774565b6001600160a01b0316336001600160a01b03161480610ae557506001546001600160a01b031633145b610b015760405162461bcd60e51b81526004016105439061160c565b81600003610b515760405162461bcd60e51b815260206004820152601c60248201527f496e76616c69642064657374696e6174696f6e20616464726573732e000000006044820152606401610543565b60003411610bb25760405162461bcd60e51b815260206004820152602860248201527f496e76616c696420616d6f756e742c2073686f756c6420626520686967686572604482015267103a3430b710181760c11b6064820152608401610543565b600083833484604051602001610bcb9493929190611653565b60408051601f19818403018152918152815160209283012060008181529283905291206002015490915060ff1615610c455760405162461bcd60e51b815260206004820152601b60248201527f5472616e7366657220616c72656164792070726f6365737365642e00000000006044820152606401610543565b6040518060800160405280848152602001348152602001600115158152602001836001811115610c7757610c776113e9565b90526000828152602081815260409182902083518155908301516001808301919091559183015160028201805491151560ff1983168117825560608601519394919261ff001990911661ffff199091161790610100908490811115610cde57610cde6113e9565b021790555050604051600091506001600160a01b0385169034908381818185875af1925050503d8060008114610d30576040519150601f19603f3d011682016040523d82523d6000602084013e610d35565b606091505b5050905080610d795760405162461bcd60e51b815260206004820152601060248201526f2a3930b739b332b9103330b4b632b21760811b6044820152606401610543565b847fa021626d9973eaecfbeb0e17352f56e3e9b32891f48c11cc1c2c248a2559f79a33600080868152602001908152602001600020604051610dbc92919061182b565b60405180910390a25050505050565b610dd3611054565b60028190556040518181527f770ea1f0ec3952d2a87b139d66a1ac5d469acba670449df142953a082c7e4e809060200161081e565b610e10611054565b60048190556040518181527f531414f0fe764471786064a701ebc067e829c6ea0aa005fc180afb5c75d5e7d29060200161081e565b610e4d611054565b6001600160a01b038116610e7757604051631e4fbdf760e01b815260006004820152602401610543565b610e8081611086565b50565b610e8b6110f7565b610e8081611140565b6107726110f7565b306001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161480610f2357507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316610f17600080516020611865833981519152546001600160a01b031690565b6001600160a01b031614155b156107725760405163703e46dd60e11b815260040160405180910390fd5b610e80611054565b816001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015610fa3575060408051601f3d908101601f19168201909252610fa091810190611744565b60015b610fcb57604051634c9c8ce360e01b81526001600160a01b0383166004820152602401610543565b6000805160206118658339815191528114610ffc57604051632a87526960e21b815260048101829052602401610543565b6110068383611148565b505050565b306001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146107725760405163703e46dd60e11b815260040160405180910390fd5b3361105d610774565b6001600160a01b0316146107725760405163118cdaa760e01b8152336004820152602401610543565b7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930080546001600160a01b031981166001600160a01b03848116918217845560405192169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3505050565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0054600160401b900460ff1661077257604051631afcd79f60e31b815260040160405180910390fd5b610e4d6110f7565b6111518261119e565b6040516001600160a01b038316907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a2805115611196576110068282611203565b61073f61127b565b806001600160a01b03163b6000036111d457604051634c9c8ce360e01b81526001600160a01b0382166004820152602401610543565b60008051602061186583398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b6060600080846001600160a01b0316846040516112209190611848565b600060405180830381855af49150503d806000811461125b576040519150601f19603f3d011682016040523d82523d6000602084013e611260565b606091505b509150915061127085838361129a565b925050505b92915050565b34156107725760405163b398979f60e01b815260040160405180910390fd5b6060826112af576112aa826112f9565b6112f2565b81511580156112c657506001600160a01b0384163b155b156112ef57604051639996b31560e01b81526001600160a01b0385166004820152602401610543565b50805b9392505050565b8051156113095780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b80356001600160a01b038116811461133957600080fd5b919050565b600080600080600060a0868803121561135657600080fd5b61135f86611322565b9450602086013593506040860135925061137b60608701611322565b915061138960808701611322565b90509295509295909350565b600080600080600060a086880312156113ad57600080fd5b505083359560208501359550604085013594606081013594506080013592509050565b6000602082840312156113e257600080fd5b5035919050565b634e487b7160e01b600052602160045260246000fd5b6002811061141d57634e487b7160e01b600052602160045260246000fd5b9052565b8481526020810184905282151560408201526080810161144460608301846113ff565b95945050505050565b634e487b7160e01b600052604160045260246000fd5b6000806040838503121561147657600080fd5b61147f83611322565b9150602083013567ffffffffffffffff8082111561149c57600080fd5b818501915085601f8301126114b057600080fd5b8135818111156114c2576114c261144d565b604051601f8201601f19908116603f011681019083821181831017156114ea576114ea61144d565b8160405282815288602084870101111561150357600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b60006020828403121561153757600080fd5b6112f282611322565b60005b8381101561155b578181015183820152602001611543565b50506000910152565b6000815180845261157c816020860160208601611540565b601f01601f19169290920160200192915050565b6020815260006112f26020830184611564565b6000806000606084860312156115b857600080fd5b505081359360208301359350604090920135919050565b6000806000606084860312156115e457600080fd5b833592506020840135915060408401356002811061160157600080fd5b809150509250925092565b60208082526027908201527f4f6e6c79204f776e6572206f72204d4d2063616e2063616c6c207468697320666040820152663ab731ba34b7b760c91b606082015260800190565b84815283602082015282604082015260006002831061168257634e487b7160e01b600052602160045260246000fd5b5060f89190911b60608201526061019392505050565b60018060a01b038816815260006020888184015260e060408401526116c060e0840189611564565b87606085015286608085015283810360a08501528086518083528383019150838160051b84010184890160005b8381101561171b57601f19868403018552611709838351611564565b948701949250908601906001016116ed565b50506001600160a01b03881660c088015294506117389350505050565b98975050505050505050565b60006020828403121561175657600080fd5b5051919050565b8054825260018101546020830152600281015460ff8116151560408401526110066060840160ff8360081c166113ff565b60808101611275828461175d565b634e487b7160e01b600052603260045260246000fd5b6000606082018583526020858185015260606040850152818551808452608086019150828701935060005b818110156117f9578451835293830193918301916001016117dd565b509098975050505050505050565b6000806040838503121561181a57600080fd5b505080516020909101519092909150565b6001600160a01b038316815260a081016112f2602083018461175d565b6000825161185a818460208701611540565b919091019291505056fe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbca26469706673582212205650497c1c47e61f69b1b2641b596da321a6c987272e95d3305e223efd2c094264736f6c63430008140033","sourceMap":"494:6220:49:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1618:649;;;;;;;;;;-1:-1:-1;1618:649:49;;;;;:::i;:::-;;:::i;:::-;;4209:1200;;;;;;:::i;:::-;;:::i;1278:36::-;;;;;;;;;;;;;;;;;;;1274:25:54;;;1262:2;1247:18;1278:36:49;;;;;;;;1246:26;;;;;;;;;;-1:-1:-1;1246:26:49;;;;-1:-1:-1;;;;;1246:26:49;;;;;;-1:-1:-1;;;;;1583:32:54;;;1565:51;;1553:2;1538:18;1246:26:49;1419:203:54;1191:49:49;;;;;;;;;;-1:-1:-1;1191:49:49;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;4161:214:34:-;;;;;;:::i;:::-;;:::i;3708:134::-;;;;;;;;;;;;;:::i;3155:101:32:-;;;;;;;;;;;;;:::i;2441:144::-;;;;;;;;;;;;;:::i;1320:34:49:-;;;;;;;;;;-1:-1:-1;1320:34:49;;;;-1:-1:-1;;;;;1320:34:49;;;6357:106;;;;;;;;;;-1:-1:-1;6357:106:49;;;;;:::i;:::-;;:::i;5651:218::-;;;;;;;;;;-1:-1:-1;5651:218:49;;;;;:::i;:::-;;:::i;1819:58:34:-;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;1819:58:34;;;;;;;;;;;;:::i;3193:908:49:-;;;;;;:::i;:::-;;:::i;2390:754::-;;;;;;:::i;:::-;;:::i;1360:49::-;;;;;;;;;;;;;;;;5415:230;;;;;;;;;;-1:-1:-1;5415:230:49;;;;;:::i;:::-;;:::i;6039:285::-;;;;;;;;;;-1:-1:-1;6039:285:49;;;;;:::i;:::-;;:::i;3405:215:32:-;;;;;;;;;;-1:-1:-1;3405:215:32;;;;;:::i;:::-;;:::i;1618:649:49:-;8870:21:33;4302:15;;-1:-1:-1;;;4302:15:33;;;;4301:16;;4348:14;;4158:30;4726:16;;:34;;;;;4746:14;4726:34;4706:54;;4770:17;4790:11;:16;;4805:1;4790:16;:50;;;;-1:-1:-1;4818:4:33;4810:25;:30;4790:50;4770:70;;4856:12;4855:13;:30;;;;;4873:12;4872:13;4855:30;4851:91;;;4908:23;;-1:-1:-1;;;4908:23:33;;;;;;;;;;;4851:91;4951:18;;-1:-1:-1;;4951:18:33;4968:1;4951:18;;;4979:67;;;;5013:22;;-1:-1:-1;;;;5013:22:33;-1:-1:-1;;;5013:22:33;;;4979:67;1859:26:49::1;1874:10;1859:14;:26::i;:::-;1895:24;:22;:24::i;:::-;1930:12;:46:::0;;-1:-1:-1;;;;;1930:46:49;;::::1;-1:-1:-1::0;;;;;;1930:46:49;;::::1;;::::0;;;1986:14:::1;:46:::0;;;;::::1;::::0;;::::1;;::::0;;2043:21:::1;:46:::0;;;-1:-1:-1;2099:72:49;;;1930:46;2234:26;;;;::::1;::::0;;;::::1;::::0;;;::::1;::::0;;5066:101:33;;;;5100:23;;-1:-1:-1;;;;5100:23:33;;;5142:14;;-1:-1:-1;5940:50:54;;5142:14:33;;5928:2:54;5913:18;5142:14:33;;;;;;;5066:101;4092:1081;;;;;1618:649:49;;;;;:::o;4209:1200::-;6524:7;:5;:7::i;:::-;-1:-1:-1;;;;;6510:21:49;:10;-1:-1:-1;;;;;6510:21:49;;:50;;;-1:-1:-1;6549:11:49;;-1:-1:-1;;;;;6549:11:49;6535:10;:25;6510:50;6502:102;;;;-1:-1:-1;;;6502:102:49;;;;;;;:::i;:::-;;;;;;;;;4412:13:::1;4455:7;4464:11;4477:6;4485:12;4438:60;;;;;;;;;;;:::i;:::-;;::::0;;-1:-1:-1;;4438:60:49;;::::1;::::0;;;;;;4428:71;;4438:60:::1;4428:71:::0;;::::1;::::0;4509:33:::1;4545:16:::0;;;;;;;;;4579:19:::1;::::0;::::1;::::0;4428:71;;-1:-1:-1;4545:16:49;4579:19:::1;;:27;;:19:::0;:27:::1;4571:59;;;::::0;-1:-1:-1;;;4571:59:49;;7165:2:54;4571:59:49::1;::::0;::::1;7147:21:54::0;7204:2;7184:18;;;7177:30;-1:-1:-1;;;7223:18:54;;;7216:49;7282:18;;4571:59:49::1;6963:343:54::0;4571:59:49::1;4860:24:::0;;4898:19:::1;::::0;::::1;::::0;4781:146:::1;::::0;;::::1;::::0;::::1;7513:25:54::0;;;7554:18;;;7547:34;;;;7597:18;;;;7590:34;;;;4781:146:49;;;;;;;;;;7486:18:54;;;;4781:146:49;;::::1;::::0;;::::1;::::0;;-1:-1:-1;;;;;4781:146:49::1;-1:-1:-1::0;;;4781:146:49;;::::1;::::0;;;5022:14:::1;::::0;5089:19:::1;::::0;5270:14;;-1:-1:-1;5270:14:49;;;;;::::1;::::0;;;4681:28;;-1:-1:-1;;;;;5022:14:49;;::::1;::::0;:35:::1;::::0;5065:9:::1;::::0;5089:19:::1;::::0;4781:146;;5210:8;;5233:22;;-1:-1:-1;5270:14:49::1;::::0;::::1;;;;;;;;;;;;;;;;;;5321:10;5022:338;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;5376:26;5389:12;5376:26;;;;;;:::i;:::-;;;;;;;;4402:1007;;;;4209:1200:::0;;;;;:::o;4161:214:34:-;2655:13;:11;:13::i;:::-;4276:36:::1;4294:17;4276;:36::i;:::-;4322:46;4344:17;4363:4;4322:21;:46::i;:::-;4161:214:::0;;:::o;3708:134::-;3777:7;2926:20;:18;:20::i;:::-;-1:-1:-1;;;;;;;;;;;;3708:134:34;:::o;3155:101:32:-;2334:13;:11;:13::i;:::-;3219:30:::1;3246:1;3219:18;:30::i;:::-;3155:101::o:0;2441:144::-;1313:22;2570:8;-1:-1:-1;;;;;2570:8:32;;2441:144::o;6357:106:49:-;2334:13:32;:11;:13::i;:::-;6430:11:49::1;:26:::0;;-1:-1:-1;;;;;;6430:26:49::1;-1:-1:-1::0;;;;;6430:26:49;;;::::1;::::0;;;::::1;::::0;;6357:106::o;5651:218::-;2334:13:32;:11;:13::i;:::-;5744:19:49::1;:44:::0;;-1:-1:-1;;;;;;5744:44:49::1;-1:-1:-1::0;;;;;5744:44:49;::::1;::::0;;::::1;::::0;;;5803:51:::1;::::0;1565::54;;;5803::49::1;::::0;1553:2:54;1538:18;5803:51:49::1;;;;;;;;5651:218:::0;:::o;3193:908::-;6524:7;:5;:7::i;:::-;-1:-1:-1;;;;;6510:21:49;:10;-1:-1:-1;;;;;6510:21:49;;:50;;;-1:-1:-1;6549:11:49;;-1:-1:-1;;;;;6549:11:49;6535:10;:25;6510:50;6502:102;;;;-1:-1:-1;;;6502:102:49;;;;;;;:::i;:::-;3310:13:::1;3353:7;3362:11;3375:6;3383:14;3336:62;;;;;;;;;;;:::i;:::-;;::::0;;-1:-1:-1;;3336:62:49;;::::1;::::0;;;;;;3326:73;;3336:62:::1;3326:73:::0;;::::1;::::0;3409:33:::1;3445:16:::0;;;;;;;;;3479:19:::1;::::0;::::1;::::0;3326:73;;-1:-1:-1;3445:16:49;3479:19:::1;;:27;;:19:::0;:27:::1;3471:59;;;::::0;-1:-1:-1;;;3471:59:49;;7165:2:54;3471:59:49::1;::::0;::::1;7147:21:54::0;7204:2;7184:18;;;7177:30;-1:-1:-1;;;7223:18:54;;;7216:49;7282:18;;3471:59:49::1;6963:343:54::0;3471:59:49::1;3568:16;::::0;;3582:1:::1;3568:16:::0;;;;;::::1;::::0;;;3541:24:::1;::::0;3568:16:::1;::::0;::::1;::::0;;::::1;::::0;::::1;;::::0;-1:-1:-1;3568:16:49::1;3541:43;;3664:7;-1:-1:-1::0;;;;;3643:29:49::1;:7;3651:1;3643:10;;;;;;;;:::i;:::-;;;;;;:29;;;::::0;::::1;3721:3;3710:7;:14;;-1:-1:-1::0;;;;;3689:36:49::1;:7;3697:1;3689:10;;;;;;;;:::i;:::-;;;;;;:36;;;::::0;::::1;3756:12;:24;;;3743:7;3751:1;3743:10;;;;;;;;:::i;:::-;;;;;;:37;;;::::0;::::1;3811:6;-1:-1:-1::0;;;;;3790:28:49::1;:7;3798:1;3790:10;;;;;;;;:::i;:::-;;;;;;:28;;;::::0;::::1;3866:3;3856:6;:13;;-1:-1:-1::0;;;;;3835:35:49::1;:7;3843:1;3835:10;;;;;;;;:::i;:::-;;::::0;;::::1;::::0;;;;;:35;3901:12:::1;::::0;3961:21:::1;::::0;3996:34:::1;::::0;;3901:151:::1;::::0;-1:-1:-1;;;3901:151:49;;-1:-1:-1;;;;;3901:12:49;;::::1;::::0;:28:::1;::::0;3937:9:::1;::::0;3901:151:::1;::::0;3961:21;;4044:7;;3901:151:::1;;:::i;:::-;;::::0;::::1;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;4068:26;4081:12;4068:26;;;;;;:::i;:::-;;;;;;;;3300:801;;;3193:908:::0;;;:::o;2390:754::-;6524:7;:5;:7::i;:::-;-1:-1:-1;;;;;6510:21:49;:10;-1:-1:-1;;;;;6510:21:49;;:50;;;-1:-1:-1;6549:11:49;;-1:-1:-1;;;;;6549:11:49;6535:10;:25;6510:50;6502:102;;;;-1:-1:-1;;;6502:102:49;;;;;;;:::i;:::-;2510:11:::1;2525:1;2510:16:::0;2502:57:::1;;;::::0;-1:-1:-1;;;2502:57:49;;11169:2:54;2502:57:49::1;::::0;::::1;11151:21:54::0;11208:2;11188:18;;;11181:30;11247;11227:18;;;11220:58;11295:18;;2502:57:49::1;10967:352:54::0;2502:57:49::1;2589:1;2577:9;:13;2569:66;;;::::0;-1:-1:-1;;;2569:66:49;;11526:2:54;2569:66:49::1;::::0;::::1;11508:21:54::0;11565:2;11545:18;;;11538:30;11604:34;11584:18;;;11577:62;-1:-1:-1;;;11655:18:54;;;11648:38;11703:19;;2569:66:49::1;11324:404:54::0;2569:66:49::1;2646:13;2689:7;2698:11;2711:9;2722:7;2672:58;;;;;;;;;;;:::i;:::-;;::::0;;-1:-1:-1;;2672:58:49;;::::1;::::0;;;;;;2662:69;;2672:58:::1;2662:69:::0;;::::1;::::0;2749:9:::1;:16:::0;;;;;;;;;:23:::1;;::::0;2662:69;;-1:-1:-1;2749:23:49::1;;:32;2741:72;;;::::0;-1:-1:-1;;;2741:72:49;;11935:2:54;2741:72:49::1;::::0;::::1;11917:21:54::0;11974:2;11954:18;;;11947:30;12013:29;11993:18;;;11986:57;12060:18;;2741:72:49::1;11733:351:54::0;2741:72:49::1;2843:91;;;;;;;;2870:11;2843:91;;;;2891:9;2843:91;;;;2910:4;2843:91;;;;;;2925:7;2843:91;;;;;;;;:::i;:::-;::::0;;2824:9:::1;:16:::0;;;::::1;::::0;;;;;;;;:110;;;;;;::::1;::::0;::::1;::::0;;::::1;::::0;;;;;;::::1;::::0;::::1;::::0;::::1;::::0;;;::::1;;-1:-1:-1::0;;2824:110:49;::::1;::::0;::::1;::::0;;::::1;::::0;::::1;::::0;:16;;:110;;-1:-1:-1;;2824:110:49;;;-1:-1:-1;;2824:110:49;;;;;::::1;::::0;;;;::::1;;;;;;:::i;:::-;;;::::0;;-1:-1:-1;;2963:65:49::1;::::0;2946:12:::1;::::0;-1:-1:-1;;;;;;2963:43:49;::::1;::::0;3014:9:::1;::::0;2946:12;2963:65;2946:12;2963:65;3014:9;2963:43;:65:::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2945:83;;;3047:7;3039:36;;;::::0;-1:-1:-1;;;3039:36:49;;12501:2:54;3039:36:49::1;::::0;::::1;12483:21:54::0;12540:2;12520:18;;;12513:30;-1:-1:-1;;;12559:18:54;;;12552:46;12615:18;;3039:36:49::1;12299:340:54::0;3039:36:49::1;3099:7;3090:47;3108:10;3120:9;:16:::0;3130:5:::1;3120:16;;;;;;;;;;;3090:47;;;;;;;:::i;:::-;;;;;;;;2492:652;;2390:754:::0;;;:::o;5415:230::-;2334:13:32;:11;:13::i;:::-;5512:21:49::1;:48:::0;;;5575:55:::1;::::0;1274:25:54;;;5575:55:49::1;::::0;1262:2:54;1247:18;5575:55:49::1;1128:177:54::0;6039:285:49;2334:13:32;:11;:13::i;:::-;6156:34:49::1;:74:::0;;;6245:72:::1;::::0;1274:25:54;;;6245:72:49::1;::::0;1262:2:54;1247:18;6245:72:49::1;1128:177:54::0;3405:215:32;2334:13;:11;:13::i;:::-;-1:-1:-1;;;;;3489:22:32;::::1;3485:91;;3534:31;::::0;-1:-1:-1;;;3534:31:32;;3562:1:::1;3534:31;::::0;::::1;1565:51:54::0;1538:18;;3534:31:32::1;1419:203:54::0;3485:91:32::1;3585:28;3604:8;3585:18;:28::i;:::-;3405:215:::0;:::o;1847:127::-;6931:20:33;:18;:20::i;:::-;1929:38:32::1;1954:12;1929:24;:38::i;2970:67:34:-:0;6931:20:33;:18;:20::i;4603:312:34:-;4683:4;-1:-1:-1;;;;;4692:6:34;4675:23;;;:120;;;4789:6;-1:-1:-1;;;;;4753:42:34;:32;-1:-1:-1;;;;;;;;;;;2036:53:38;-1:-1:-1;;;;;2036:53:38;;1958:138;4753:32:34;-1:-1:-1;;;;;4753:42:34;;;4675:120;4658:251;;;4869:29;;-1:-1:-1;;;4869:29:34;;;;;;;;;;;6628:84:49;2334:13:32;:11;:13::i;6057:538:34:-;6174:17;-1:-1:-1;;;;;6156:50:34;;:52;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;6156:52:34;;;;;;;;-1:-1:-1;;6156:52:34;;;;;;;;;;;;:::i;:::-;;;6152:437;;6518:60;;-1:-1:-1;;;6518:60:34;;-1:-1:-1;;;;;1583:32:54;;6518:60:34;;;1565:51:54;1538:18;;6518:60:34;1419:203:54;6152:437:34;-1:-1:-1;;;;;;;;;;;6250:40:34;;6246:120;;6317:34;;-1:-1:-1;;;6317:34:34;;;;;1274:25:54;;;1247:18;;6317:34:34;1128:177:54;6246:120:34;6379:54;6409:17;6428:4;6379:29;:54::i;:::-;6209:235;6057:538;;:::o;5032:213::-;5106:4;-1:-1:-1;;;;;5115:6:34;5098:23;;5094:145;;5199:29;;-1:-1:-1;;;5199:29:34;;;;;;;;;;;2658:162:32;966:10:35;2717:7:32;:5;:7::i;:::-;-1:-1:-1;;;;;2717:23:32;;2713:101;;2763:40;;-1:-1:-1;;;2763:40:32;;966:10:35;2763:40:32;;;1565:51:54;1538:18;;2763:40:32;1419:203:54;3774:248:32;1313:22;3923:8;;-1:-1:-1;;;;;;3941:19:32;;-1:-1:-1;;;;;3941:19:32;;;;;;;;3975:40;;3923:8;;;;;3975:40;;3847:24;;3975:40;3837:185;;3774:248;:::o;7084:141:33:-;8870:21;8560:40;-1:-1:-1;;;8560:40:33;;;;7146:73;;7191:17;;-1:-1:-1;;;7191:17:33;;;;;;;;;;;1980:235:32;6931:20:33;:18;:20::i;2781:335:38:-;2872:37;2891:17;2872:18;:37::i;:::-;2924:27;;-1:-1:-1;;;;;2924:27:38;;;;;;;;2966:11;;:15;2962:148;;2997:53;3026:17;3045:4;2997:28;:53::i;2962:148::-;3081:18;:16;:18::i;2188:281::-;2265:17;-1:-1:-1;;;;;2265:29:38;;2298:1;2265:34;2261:119;;2322:47;;-1:-1:-1;;;2322:47:38;;-1:-1:-1;;;;;1583:32:54;;2322:47:38;;;1565:51:54;1538:18;;2322:47:38;1419:203:54;2261:119:38;-1:-1:-1;;;;;;;;;;;2389:73:38;;-1:-1:-1;;;;;;2389:73:38;-1:-1:-1;;;;;2389:73:38;;;;;;;;;;2188:281::o;4106:253:42:-;4189:12;4214;4228:23;4255:6;-1:-1:-1;;;;;4255:19:42;4275:4;4255:25;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4213:67;;;;4297:55;4324:6;4332:7;4341:10;4297:26;:55::i;:::-;4290:62;;;;4106:253;;;;;:::o;6603:122:38:-;6653:9;:13;6649:70;;6689:19;;-1:-1:-1;;;6689:19:38;;;;;;;;;;;4625:582:42;4769:12;4798:7;4793:408;;4821:19;4829:10;4821:7;:19::i;:::-;4793:408;;;5045:17;;:22;:49;;;;-1:-1:-1;;;;;;5071:18:42;;;:23;5045:49;5041:119;;;5121:24;;-1:-1:-1;;;5121:24:42;;-1:-1:-1;;;;;1583:32:54;;5121:24:42;;;1565:51:54;1538:18;;5121:24:42;1419:203:54;5041:119:42;-1:-1:-1;5180:10:42;4793:408;4625:582;;;;;:::o;5743:516::-;5874:17;;:21;5870:383;;6102:10;6096:17;6158:15;6145:10;6141:2;6137:19;6130:44;5870:383;6225:17;;-1:-1:-1;;;6225:17:42;;;;;;;;;;;14:173:54;82:20;;-1:-1:-1;;;;;131:31:54;;121:42;;111:70;;177:1;174;167:12;111:70;14:173;;;:::o;192:472::-;287:6;295;303;311;319;372:3;360:9;351:7;347:23;343:33;340:53;;;389:1;386;379:12;340:53;412:29;431:9;412:29;:::i;:::-;402:39;;488:2;477:9;473:18;460:32;450:42;;539:2;528:9;524:18;511:32;501:42;;562:38;596:2;585:9;581:18;562:38;:::i;:::-;552:48;;619:39;653:3;642:9;638:19;619:39;:::i;:::-;609:49;;192:472;;;;;;;;:::o;669:454::-;764:6;772;780;788;796;849:3;837:9;828:7;824:23;820:33;817:53;;;866:1;863;856:12;817:53;-1:-1:-1;;889:23:54;;;959:2;944:18;;931:32;;-1:-1:-1;1010:2:54;995:18;;982:32;;1061:2;1046:18;;1033:32;;-1:-1:-1;1112:3:54;1097:19;1084:33;;-1:-1:-1;669:454:54;-1:-1:-1;669:454:54:o;1627:180::-;1686:6;1739:2;1727:9;1718:7;1714:23;1710:32;1707:52;;;1755:1;1752;1745:12;1707:52;-1:-1:-1;1778:23:54;;1627:180;-1:-1:-1;1627:180:54:o;1812:127::-;1873:10;1868:3;1864:20;1861:1;1854:31;1904:4;1901:1;1894:15;1928:4;1925:1;1918:15;1944:233;2021:1;2014:5;2011:12;2001:143;;2066:10;2061:3;2057:20;2054:1;2047:31;2101:4;2098:1;2091:15;2129:4;2126:1;2119:15;2001:143;2153:18;;1944:233::o;2182:425::-;2416:25;;;2472:2;2457:18;;2450:34;;;2527:14;;2520:22;2515:2;2500:18;;2493:50;2403:3;2388:19;;2552:49;2597:2;2582:18;;2574:6;2552:49;:::i;:::-;2182:425;;;;;;;:::o;2612:127::-;2673:10;2668:3;2664:20;2661:1;2654:31;2704:4;2701:1;2694:15;2728:4;2725:1;2718:15;2744:995;2821:6;2829;2882:2;2870:9;2861:7;2857:23;2853:32;2850:52;;;2898:1;2895;2888:12;2850:52;2921:29;2940:9;2921:29;:::i;:::-;2911:39;;3001:2;2990:9;2986:18;2973:32;3024:18;3065:2;3057:6;3054:14;3051:34;;;3081:1;3078;3071:12;3051:34;3119:6;3108:9;3104:22;3094:32;;3164:7;3157:4;3153:2;3149:13;3145:27;3135:55;;3186:1;3183;3176:12;3135:55;3222:2;3209:16;3244:2;3240;3237:10;3234:36;;;3250:18;;:::i;:::-;3325:2;3319:9;3293:2;3379:13;;-1:-1:-1;;3375:22:54;;;3399:2;3371:31;3367:40;3355:53;;;3423:18;;;3443:22;;;3420:46;3417:72;;;3469:18;;:::i;:::-;3509:10;3505:2;3498:22;3544:2;3536:6;3529:18;3584:7;3579:2;3574;3570;3566:11;3562:20;3559:33;3556:53;;;3605:1;3602;3595:12;3556:53;3661:2;3656;3652;3648:11;3643:2;3635:6;3631:15;3618:46;3706:1;3701:2;3696;3688:6;3684:15;3680:24;3673:35;3727:6;3717:16;;;;;;;2744:995;;;;;:::o;3926:186::-;3985:6;4038:2;4026:9;4017:7;4013:23;4009:32;4006:52;;;4054:1;4051;4044:12;4006:52;4077:29;4096:9;4077:29;:::i;4117:250::-;4202:1;4212:113;4226:6;4223:1;4220:13;4212:113;;;4302:11;;;4296:18;4283:11;;;4276:39;4248:2;4241:10;4212:113;;;-1:-1:-1;;4359:1:54;4341:16;;4334:27;4117:250::o;4372:271::-;4414:3;4452:5;4446:12;4479:6;4474:3;4467:19;4495:76;4564:6;4557:4;4552:3;4548:14;4541:4;4534:5;4530:16;4495:76;:::i;:::-;4625:2;4604:15;-1:-1:-1;;4600:29:54;4591:39;;;;4632:4;4587:50;;4372:271;-1:-1:-1;;4372:271:54:o;4648:220::-;4797:2;4786:9;4779:21;4760:4;4817:45;4858:2;4847:9;4843:18;4835:6;4817:45;:::i;4873:316::-;4950:6;4958;4966;5019:2;5007:9;4998:7;4994:23;4990:32;4987:52;;;5035:1;5032;5025:12;4987:52;-1:-1:-1;;5058:23:54;;;5128:2;5113:18;;5100:32;;-1:-1:-1;5179:2:54;5164:18;;;5151:32;;4873:316;-1:-1:-1;4873:316:54:o;5194:403::-;5282:6;5290;5298;5351:2;5339:9;5330:7;5326:23;5322:32;5319:52;;;5367:1;5364;5357:12;5319:52;5403:9;5390:23;5380:33;;5460:2;5449:9;5445:18;5432:32;5422:42;;5514:2;5503:9;5499:18;5486:32;5547:1;5540:5;5537:12;5527:40;;5563:1;5560;5553:12;5527:40;5586:5;5576:15;;;5194:403;;;;;:::o;6001:::-;6203:2;6185:21;;;6242:2;6222:18;;;6215:30;6281:34;6276:2;6261:18;;6254:62;-1:-1:-1;;;6347:2:54;6332:18;;6325:37;6394:3;6379:19;;6001:403::o;6409:549::-;6643:6;6638:3;6631:19;6680:6;6675:2;6670:3;6666:12;6659:28;6717:6;6712:2;6707:3;6703:12;6696:28;6613:3;6754:1;6746:6;6743:13;6733:144;;6799:10;6794:3;6790:20;6787:1;6780:31;6834:4;6831:1;6824:15;6862:4;6859:1;6852:15;6733:144;-1:-1:-1;6911:3:54;6907:16;;;;6902:2;6893:12;;6886:38;6949:2;6940:12;;6409:549;-1:-1:-1;;;6409:549:54:o;7635:1330::-;8055:1;8051;8046:3;8042:11;8038:19;8030:6;8026:32;8015:9;8008:51;7989:4;8078:2;8116:6;8111:2;8100:9;8096:18;8089:34;8159:3;8154:2;8143:9;8139:18;8132:31;8186:46;8227:3;8216:9;8212:19;8204:6;8186:46;:::i;:::-;8268:6;8263:2;8252:9;8248:18;8241:34;8312:6;8306:3;8295:9;8291:19;8284:35;8368:9;8360:6;8356:22;8350:3;8339:9;8335:19;8328:51;8399:6;8434;8428:13;8465:6;8457;8450:22;8500:2;8492:6;8488:15;8481:22;;8559:2;8549:6;8546:1;8542:14;8534:6;8530:27;8526:36;8597:2;8589:6;8585:15;8618:1;8628:252;8642:6;8639:1;8636:13;8628:252;;;8732:2;8728:7;8719:6;8711;8707:19;8703:33;8698:3;8691:46;8760:40;8793:6;8784;8778:13;8760:40;:::i;:::-;8858:12;;;;8750:50;-1:-1:-1;8823:15:54;;;;8664:1;8657:9;8628:252;;;-1:-1:-1;;;;;;;1376:31:54;;8954:3;8939:19;;1364:44;8897:6;-1:-1:-1;8912:47:54;;-1:-1:-1;;;;1310:104:54;8912:47;7635:1330;;;;;;;;;;:::o;8970:184::-;9040:6;9093:2;9081:9;9072:7;9068:23;9064:32;9061:52;;;9109:1;9106;9099:12;9061:52;-1:-1:-1;9132:16:54;;8970:184;-1:-1:-1;8970:184:54:o;9159:359::-;9255:5;9249:12;9244:3;9237:25;9311:4;9304:5;9300:16;9294:23;9287:4;9282:3;9278:14;9271:47;9361:4;9354:5;9350:16;9344:23;9428:4;9417:9;9413:20;9406:28;9399:36;9392:4;9387:3;9383:14;9376:60;9445:67;9506:4;9501:3;9497:14;9490:4;9478:9;9475:1;9471:17;9467:28;9445:67;:::i;9523:277::-;9720:3;9705:19;;9733:61;9709:9;9776:6;9733:61;:::i;9805:127::-;9866:10;9861:3;9857:20;9854:1;9847:31;9897:4;9894:1;9887:15;9921:4;9918:1;9911:15;9937:775;10135:4;10183:2;10172:9;10168:18;10213:6;10202:9;10195:25;10239:2;10277:6;10272:2;10261:9;10257:18;10250:34;10320:2;10315;10304:9;10300:18;10293:30;10343:6;10378;10372:13;10409:6;10401;10394:22;10447:3;10436:9;10432:19;10425:26;;10486:2;10478:6;10474:15;10460:29;;10507:1;10517:169;10531:6;10528:1;10525:13;10517:169;;;10592:13;;10580:26;;10661:15;;;;10626:12;;;;10553:1;10546:9;10517:169;;;-1:-1:-1;10703:3:54;;9937:775;-1:-1:-1;;;;;;;;9937:775:54:o;10717:245::-;10796:6;10804;10857:2;10845:9;10836:7;10832:23;10828:32;10825:52;;;10873:1;10870;10863:12;10825:52;-1:-1:-1;;10896:16:54;;10952:2;10937:18;;;10931:25;10896:16;;10931:25;;-1:-1:-1;10717:245:54:o;12644:370::-;-1:-1:-1;;;;;12896:32:54;;12878:51;;12865:3;12850:19;;12938:70;13004:2;12989:18;;12981:6;12938:70;:::i;13019:287::-;13148:3;13186:6;13180:13;13202:66;13261:6;13256:3;13249:4;13241:6;13237:17;13202:66;:::i;:::-;13284:16;;;;;13019:287;-1:-1:-1;;13019:287:54:o","linkReferences":{},"immutableReferences":{"47070":[{"start":3751,"length":32},{"start":3792,"length":32},{"start":4118,"length":32}]}},"methodIdentifiers":{"StarknetEscrowAddress()":"1519e961","StarknetEscrowClaimPaymentSelector()":"d788f4c9","UPGRADE_INTERFACE_VERSION()":"ad3cb1cc","ZKSyncEscrowAddress()":"942b8aea","claimPayment(uint256,uint256,uint256)":"c1f9789a","claimPaymentZKSync(uint256,uint256,uint256,uint256,uint256)":"0b5e4f1a","initialize(address,uint256,uint256,address,address)":"03b54d52","marketMaker()":"1f21f9af","owner()":"8da5cb5b","proxiableUUID()":"52d1902d","renounceOwnership()":"715018a6","setMMAddress(address)":"a7139611","setStarknetClaimPaymentSelector(uint256)":"f12ba5c7","setStarknetEscrowAddress(uint256)":"f04193c8","setZKSyncEscrowAddress(address)":"acfefa52","transfer(uint256,uint256,uint8)":"d71b8af0","transferOwnership(address)":"f2fde38b","transfers(bytes32)":"3c64f04b","upgradeToAndCall(address,bytes)":"4f1ef286"},"rawMetadata":"{\"compiler\":{\"version\":\"0.8.20+commit.a1b79de6\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"AddressEmptyCode\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"implementation\",\"type\":\"address\"}],\"name\":\"ERC1967InvalidImplementation\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ERC1967NonPayable\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedInnerCall\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidInitialization\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotInitializing\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"OwnableInvalidOwner\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"OwnableUnauthorizedAccount\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UUPSUnauthorizedCallContext\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"slot\",\"type\":\"bytes32\"}],\"name\":\"UUPSUnsupportedProxiableUUID\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"destAddress\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"isUsed\",\"type\":\"bool\"},{\"internalType\":\"enum PaymentRegistry.Chain\",\"name\":\"chainId\",\"type\":\"uint8\"}],\"indexed\":false,\"internalType\":\"struct PaymentRegistry.TransferInfo\",\"name\":\"transferInfo\",\"type\":\"tuple\"}],\"name\":\"ClaimPayment\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"version\",\"type\":\"uint64\"}],\"name\":\"Initialized\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newEscrowClaimPaymentSelector\",\"type\":\"uint256\"}],\"name\":\"ModifiedStarknetClaimPaymentSelector\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newEscrowAddress\",\"type\":\"uint256\"}],\"name\":\"ModifiedStarknetEscrowAddress\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newEscrowAddress\",\"type\":\"address\"}],\"name\":\"ModifiedZKSyncEscrowAddress\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"orderId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"srcAddress\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"destAddress\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"isUsed\",\"type\":\"bool\"},{\"internalType\":\"enum PaymentRegistry.Chain\",\"name\":\"chainId\",\"type\":\"uint8\"}],\"indexed\":false,\"internalType\":\"struct PaymentRegistry.TransferInfo\",\"name\":\"transferInfo\",\"type\":\"tuple\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"implementation\",\"type\":\"address\"}],\"name\":\"Upgraded\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"StarknetEscrowAddress\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"StarknetEscrowClaimPaymentSelector\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"UPGRADE_INTERFACE_VERSION\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"ZKSyncEscrowAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"orderId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAddress\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"claimPayment\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"orderId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAddress\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"gasPerPubdataByteLimit\",\"type\":\"uint256\"}],\"name\":\"claimPaymentZKSync\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"snMessaging\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"StarknetEscrowAddress_\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"StarknetEscrowClaimPaymentSelector_\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"marketMaker_\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"ZKSyncMailboxAddress\",\"type\":\"address\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"marketMaker\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"proxiableUUID\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newMMAddress\",\"type\":\"address\"}],\"name\":\"setMMAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"NewStarknetEscrowClaimPaymentSelector\",\"type\":\"uint256\"}],\"name\":\"setStarknetClaimPaymentSelector\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newStarknetEscrowAddress\",\"type\":\"uint256\"}],\"name\":\"setStarknetEscrowAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newZKSyncEscrowAddress\",\"type\":\"address\"}],\"name\":\"setZKSyncEscrowAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"orderId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAddress\",\"type\":\"uint256\"},{\"internalType\":\"enum PaymentRegistry.Chain\",\"name\":\"chainId\",\"type\":\"uint8\"}],\"name\":\"transfer\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"transfers\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"destAddress\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"isUsed\",\"type\":\"bool\"},{\"internalType\":\"enum PaymentRegistry.Chain\",\"name\":\"chainId\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newImplementation\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"upgradeToAndCall\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"errors\":{\"AddressEmptyCode(address)\":[{\"details\":\"There's no code at `target` (it is not a contract).\"}],\"ERC1967InvalidImplementation(address)\":[{\"details\":\"The `implementation` of the proxy is invalid.\"}],\"ERC1967NonPayable()\":[{\"details\":\"An upgrade function sees `msg.value > 0` that may be lost.\"}],\"FailedInnerCall()\":[{\"details\":\"A call to an address target failed. The target may have reverted.\"}],\"InvalidInitialization()\":[{\"details\":\"The contract is already initialized.\"}],\"NotInitializing()\":[{\"details\":\"The contract is not initializing.\"}],\"OwnableInvalidOwner(address)\":[{\"details\":\"The owner is not a valid owner account. (eg. `address(0)`)\"}],\"OwnableUnauthorizedAccount(address)\":[{\"details\":\"The caller account is not authorized to perform an operation.\"}],\"UUPSUnauthorizedCallContext()\":[{\"details\":\"The call is from an unauthorized context.\"}],\"UUPSUnsupportedProxiableUUID(bytes32)\":[{\"details\":\"The storage `slot` is unsupported as a UUID.\"}]},\"events\":{\"Initialized(uint64)\":{\"details\":\"Triggered when the contract has been initialized or reinitialized.\"},\"Upgraded(address)\":{\"details\":\"Emitted when the implementation is upgraded.\"}},\"kind\":\"dev\",\"methods\":{\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"proxiableUUID()\":{\"details\":\"Implementation of the ERC-1822 {proxiableUUID} function. This returns the storage slot used by the implementation. It is used to validate the implementation's compatibility when performing an upgrade. IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier.\"},\"renounceOwnership()\":{\"details\":\"Leaves the contract without owner. It will not be possible to call `onlyOwner` functions. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby disabling any functionality that is only available to the owner.\"},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"},\"upgradeToAndCall(address,bytes)\":{\"custom:oz-upgrades-unsafe-allow-reachable\":\"delegatecall\",\"details\":\"Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call encoded in `data`. Calls {_authorizeUpgrade}. Emits an {Upgraded} event.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/PaymentRegistry.sol\":\"PaymentRegistry\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[\":@matterlabs/interfaces/=lib/era-contracts/l1-contracts/contracts/zksync/interfaces/\",\":@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/\",\":@openzeppelin/contracts/=lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/\",\":ds-test/=lib/forge-std/lib/ds-test/src/\",\":era-contracts/=lib/era-contracts/\",\":erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/\",\":forge-std/=lib/forge-std/src/\",\":openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/\",\":openzeppelin-contracts/=lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/\",\":starknet/=lib/starknet/\"]},\"sources\":{\"lib/era-contracts/l1-contracts/contracts/common/libraries/UncheckedMath.sol\":{\"keccak256\":\"0x0d8dd71e77c1d25bac04d19e77c0859109648e013b658fb91b3f876f083d58ad\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://89f31e4b7849059fec7c917e61afb8f7af2cbb763c01ad0c9c326f86b9037b41\",\"dweb:/ipfs/QmRnrLH4WJ7UnrNmHre9rGVW8t3HYrsY59CrFBYfr6TK6k\"]},\"lib/era-contracts/l1-contracts/contracts/zksync/Storage.sol\":{\"keccak256\":\"0x43a3f4b2e43014892ddd393ec81ade21d5ccdeb7bb8171141878a4ec035c9458\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://29bae2244558feb34bc393ca0ff70c6d3d636947711a150ceaff246d32fa0a46\",\"dweb:/ipfs/QmUPiwprXNV2bJ8CDgUKQtciWFVYYAbBb8SpUYEYhbHGbs\"]},\"lib/era-contracts/l1-contracts/contracts/zksync/interfaces/IAdmin.sol\":{\"keccak256\":\"0xd9845b35414f4b37a3680f36168662ab8b2e355056bdd96bf7d7d4c499849371\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://eb4babe8901e74523ecbebbf192429d9ad3cf9628cc762df98f3a046f40f938a\",\"dweb:/ipfs/QmTadxmp6oexsvZVrhGscSSnZSqL43PEorN4pekzUeL5vy\"]},\"lib/era-contracts/l1-contracts/contracts/zksync/interfaces/IBase.sol\":{\"keccak256\":\"0x5477656c5eef9a9b275dc6784438256ef4e06db048781b01d84fb72e0d60c655\",\"license\":\"UNLICENSED\",\"urls\":[\"bzz-raw://56bc6517aa13539743be67abb214d5934301c31f7b40c6f7fad67c7aec3c5796\",\"dweb:/ipfs/QmdVdQ8iCsDK9C8krQseWCGNB64AMrKTn1ZF8LLDAq96Et\"]},\"lib/era-contracts/l1-contracts/contracts/zksync/interfaces/IExecutor.sol\":{\"keccak256\":\"0xb580f8687e05fe01afb00b2b77e43a24567993c83fc5b38831f5884e51be292b\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://e73dc57c64af937a6aedba62245bd2fae3a84958f0a9abb70a9df0d02c3f34f8\",\"dweb:/ipfs/QmSVaVAPkQvjVXCjK5XrP2VN4zXY9HuTME8Jyx14FJg4XV\"]},\"lib/era-contracts/l1-contracts/contracts/zksync/interfaces/IGetters.sol\":{\"keccak256\":\"0x8b19758b2fe3996f13d9527fcf0d60b838a2a33b16d7a4ddfc79bd64b731f3bc\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://b66cb276ed200456705b23d2e9a7822c3b1746ed4bfda93d94c4528c2b408538\",\"dweb:/ipfs/QmY5uN8mbZZtip6J94XYt6g6xXMpszNRMxEBsDu3mUKaJm\"]},\"lib/era-contracts/l1-contracts/contracts/zksync/interfaces/IMailbox.sol\":{\"keccak256\":\"0x985178de1704e015af86ad465874cea585229a29ebb6595589292cd3683a77c6\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://d5fb1365a5122c0033615bde0439badcdd5fa61fa60a72507ef53a8459c5eeaa\",\"dweb:/ipfs/QmeDiRjUZSDKQsFryHP2ePczKzTRfsAofMTzUTiiqgLQ93\"]},\"lib/era-contracts/l1-contracts/contracts/zksync/interfaces/IVerifier.sol\":{\"keccak256\":\"0x82fb9aa76bde8914827fe1c60a4f424d915d00ee52ac2ee8f5e408e6313714f2\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://cc915ba7c7f5176d246e6aaa17b09792c8dfddbc9b6826d2be2a38c65a427c0a\",\"dweb:/ipfs/QmUDA9nzF3ot3nLPP865841dKWyQhYtHsNnRb73fGndKoj\"]},\"lib/era-contracts/l1-contracts/contracts/zksync/interfaces/IZkSync.sol\":{\"keccak256\":\"0x91bd2b2dacaf33f4558315452dcf8d939e69c4e24bf6062b305aa48f99c1eaf3\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://fda8ff69a1e4dd806aebcde89e99a62ae255d173864a7ff9037f43ee43571931\",\"dweb:/ipfs/QmNQ3VAtToTyYJUBzSb1pz4jRYXPsHseEq2Z624rALGMxy\"]},\"lib/era-contracts/l1-contracts/contracts/zksync/libraries/Diamond.sol\":{\"keccak256\":\"0xea7462be367bdeca41c027dec9a632f28716c33c01d99eefd8de992da2b73992\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7ca0ff34b359dd2d36e098b6d2cc089dea8da03f2ac77d23a823201b91111e0a\",\"dweb:/ipfs/QmVMMH6ckapWMHk1NzfE9TT6st2w8Fjoes3wSfGYdfjVXV\"]},\"lib/era-contracts/l1-contracts/contracts/zksync/libraries/PriorityQueue.sol\":{\"keccak256\":\"0x26f86ed98f0f9d29d03c2a30af5f71cae753a15f21ed615022460c9f735ebfcd\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7bc52833de251772dd0980870756d8d877169094037de4f8319a5925ecb28c43\",\"dweb:/ipfs/QmVrVFZkiZ49F6ftS1U3ummX1NHX3y8V96vKG6eD5N8H1T\"]},\"lib/openzeppelin-contracts-upgradeable/contracts/access/OwnableUpgradeable.sol\":{\"keccak256\":\"0xc163fcf9bb10138631a9ba5564df1fa25db9adff73bd9ee868a8ae1858fe093a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://9706d43a0124053d9880f6e31a59f31bc0a6a3dc1acd66ce0a16e1111658c5f6\",\"dweb:/ipfs/QmUFmfowzkRwGtDu36cXV9SPTBHJ3n7dG9xQiK5B28jTf2\"]},\"lib/openzeppelin-contracts-upgradeable/contracts/proxy/utils/Initializable.sol\":{\"keccak256\":\"0x631188737069917d2f909d29ce62c4d48611d326686ba6683e26b72a23bfac0b\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7a61054ae84cd6c4d04c0c4450ba1d6de41e27e0a2c4f1bcdf58f796b401c609\",\"dweb:/ipfs/QmUvtdp7X1mRVyC3CsHrtPbgoqWaXHp3S1ZR24tpAQYJWM\"]},\"lib/openzeppelin-contracts-upgradeable/contracts/proxy/utils/UUPSUpgradeable.sol\":{\"keccak256\":\"0x490959f972df54829d0ffacb71fa025429d9b7b9ebd118f418b41e9c0041ef73\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://1883bc1a16a88922abccd415d1b41caf00c38ee581ae3e5976018d9c17d2c4b7\",\"dweb:/ipfs/QmP2vzQM8RR8ce675KhuZEaUicAPRMUbPLwBsTpxByvn18\"]},\"lib/openzeppelin-contracts-upgradeable/contracts/utils/ContextUpgradeable.sol\":{\"keccak256\":\"0xdbef5f0c787055227243a7318ef74c8a5a1108ca3a07f2b3a00ef67769e1e397\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://08e39f23d5b4692f9a40803e53a8156b72b4c1f9902a88cd65ba964db103dab9\",\"dweb:/ipfs/QmPKn6EYDgpga7KtpkA8wV2yJCYGMtc9K4LkJfhKX2RVSV\"]},\"lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/interfaces/draft-IERC1822.sol\":{\"keccak256\":\"0xf5c04a8bf51755681f7db413095377dfd1a05b98b6326fb1da0e9a297057caf0\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://f57690465f41860906cf84e6970baaacae9d05b8311674812e6b502bb510441e\",\"dweb:/ipfs/Qme5swSUieatWond1BHyZaEztdLAPu67KcoQTeY4pH5wVd\"]},\"lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/proxy/ERC1967/ERC1967Utils.sol\":{\"keccak256\":\"0xf5769456c75195b708e2b006c58f7f349b79752ad13d7c70ec1db05739972b22\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://d363b2bdfba6d28207d661c3b3c23beeab6405a8960ef444f8c61c2afe997600\",\"dweb:/ipfs/QmNcgJD5RL25RKtShX32WTRp1xRfPyThThA7CajTnXMjMA\"]},\"lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/proxy/beacon/IBeacon.sol\":{\"keccak256\":\"0xc59a78b07b44b2cf2e8ab4175fca91e8eca1eee2df7357b8d2a8833e5ea1f64c\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://5aa4f07e65444784c29cd7bfcc2341b34381e4e5b5da9f0c5bd00d7f430e66fa\",\"dweb:/ipfs/QmWRMh4Q9DpaU9GvsiXmDdoNYMyyece9if7hnfLz7uqzWM\"]},\"lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/utils/Address.sol\":{\"keccak256\":\"0xaf28a975a78550e45f65e559a3ad6a5ad43b9b8a37366999abd1b7084eb70721\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://b7bd24e224f67f65bfadf85dc2929fa965456bb2415478bd0125471b5ce35245\",\"dweb:/ipfs/QmRaydGr8BTHs1kvaZfsNU69pKzUAGFrvABn1KiRSbE51y\"]},\"lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/utils/StorageSlot.sol\":{\"keccak256\":\"0x70d9a9cf8d5cc830d7396505ef8eb9686bd0c60a29c6644bd6cc278f9bab8ebe\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://719abb402c11be12355088da587ffd971fee1b035b5aa6b1ba3b1a9493d3c1d7\",\"dweb:/ipfs/QmanHMFVDqVtZAFFaH1CeGQWoHWsFnWHH75fCrguwi77Hq\"]},\"lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/utils/math/SafeCast.sol\":{\"keccak256\":\"0xe19a4d5f31d2861e7344e8e535e2feafb913d806d3e2b5fe7782741a2a7094fe\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://4aed79c0fa6f0546ed02f2f683e8f77f0fd2ed7eb34d8bbf3d373c9a6d95b13c\",\"dweb:/ipfs/QmWqVz6UAVqmnWU5pqYPt1o6iDEZyPaBraAA3rKfTTSfYj\"]},\"lib/starknet/IStarknetMessaging.sol\":{\"keccak256\":\"0x40014108e2795fd544af0f6322882e99cc3f0872990d504c1ccebce2afea9617\",\"license\":\"Apache-2.0.\",\"urls\":[\"bzz-raw://d3eec1c3f47243734573b4ac3fc42db2eee4d110d8c39be16fbc6f93498e318d\",\"dweb:/ipfs/QmdYdJFPdEPUFQATa24jNvL59GtdoJeym1w7EARyCq8CvY\"]},\"lib/starknet/IStarknetMessagingEvents.sol\":{\"keccak256\":\"0x71171b10854a020b53b175ed9dc068a56675e2b80f823c0f841ae18977b96e8c\",\"license\":\"Apache-2.0.\",\"urls\":[\"bzz-raw://70d345e80b4fbbceba9bc0b64be0688710434a5b5d6eb4a60fae808d2bcc03d9\",\"dweb:/ipfs/QmQBdERT6NHiC2cDvTwS7aob1CwuuqQZvZt5ibGzvYawvB\"]},\"src/PaymentRegistry.sol\":{\"keccak256\":\"0x268f685c8a7311ed7ea369307b1c5ad289cad87692757af703b258b6ba84c174\",\"license\":\"Apache-2.0\",\"urls\":[\"bzz-raw://beb6946827b8911ed671edc1680642c5af4820972b444f3b4d4b480681b37168\",\"dweb:/ipfs/QmXZyC4bo2tVoYTYtFSxRvsxYdByKhyXPTatPiJmAd8QRt\"]}},\"version\":1}","metadata":{"compiler":{"version":"0.8.20+commit.a1b79de6"},"language":"Solidity","output":{"abi":[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"type":"error","name":"AddressEmptyCode"},{"inputs":[{"internalType":"address","name":"implementation","type":"address"}],"type":"error","name":"ERC1967InvalidImplementation"},{"inputs":[],"type":"error","name":"ERC1967NonPayable"},{"inputs":[],"type":"error","name":"FailedInnerCall"},{"inputs":[],"type":"error","name":"InvalidInitialization"},{"inputs":[],"type":"error","name":"NotInitializing"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"type":"error","name":"OwnableInvalidOwner"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"type":"error","name":"OwnableUnauthorizedAccount"},{"inputs":[],"type":"error","name":"UUPSUnauthorizedCallContext"},{"inputs":[{"internalType":"bytes32","name":"slot","type":"bytes32"}],"type":"error","name":"UUPSUnsupportedProxiableUUID"},{"inputs":[{"internalType":"struct PaymentRegistry.TransferInfo","name":"transferInfo","type":"tuple","components":[{"internalType":"uint256","name":"destAddress","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bool","name":"isUsed","type":"bool"},{"internalType":"enum PaymentRegistry.Chain","name":"chainId","type":"uint8"}],"indexed":false}],"type":"event","name":"ClaimPayment","anonymous":false},{"inputs":[{"internalType":"uint64","name":"version","type":"uint64","indexed":false}],"type":"event","name":"Initialized","anonymous":false},{"inputs":[{"internalType":"uint256","name":"newEscrowClaimPaymentSelector","type":"uint256","indexed":false}],"type":"event","name":"ModifiedStarknetClaimPaymentSelector","anonymous":false},{"inputs":[{"internalType":"uint256","name":"newEscrowAddress","type":"uint256","indexed":false}],"type":"event","name":"ModifiedStarknetEscrowAddress","anonymous":false},{"inputs":[{"internalType":"address","name":"newEscrowAddress","type":"address","indexed":false}],"type":"event","name":"ModifiedZKSyncEscrowAddress","anonymous":false},{"inputs":[{"internalType":"address","name":"previousOwner","type":"address","indexed":true},{"internalType":"address","name":"newOwner","type":"address","indexed":true}],"type":"event","name":"OwnershipTransferred","anonymous":false},{"inputs":[{"internalType":"uint256","name":"orderId","type":"uint256","indexed":true},{"internalType":"address","name":"srcAddress","type":"address","indexed":false},{"internalType":"struct PaymentRegistry.TransferInfo","name":"transferInfo","type":"tuple","components":[{"internalType":"uint256","name":"destAddress","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bool","name":"isUsed","type":"bool"},{"internalType":"enum PaymentRegistry.Chain","name":"chainId","type":"uint8"}],"indexed":false}],"type":"event","name":"Transfer","anonymous":false},{"inputs":[{"internalType":"address","name":"implementation","type":"address","indexed":true}],"type":"event","name":"Upgraded","anonymous":false},{"inputs":[],"stateMutability":"view","type":"function","name":"StarknetEscrowAddress","outputs":[{"internalType":"uint256","name":"","type":"uint256"}]},{"inputs":[],"stateMutability":"view","type":"function","name":"StarknetEscrowClaimPaymentSelector","outputs":[{"internalType":"uint256","name":"","type":"uint256"}]},{"inputs":[],"stateMutability":"view","type":"function","name":"UPGRADE_INTERFACE_VERSION","outputs":[{"internalType":"string","name":"","type":"string"}]},{"inputs":[],"stateMutability":"view","type":"function","name":"ZKSyncEscrowAddress","outputs":[{"internalType":"address","name":"","type":"address"}]},{"inputs":[{"internalType":"uint256","name":"orderId","type":"uint256"},{"internalType":"uint256","name":"destAddress","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"stateMutability":"payable","type":"function","name":"claimPayment"},{"inputs":[{"internalType":"uint256","name":"orderId","type":"uint256"},{"internalType":"uint256","name":"destAddress","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint256","name":"gasPerPubdataByteLimit","type":"uint256"}],"stateMutability":"payable","type":"function","name":"claimPaymentZKSync"},{"inputs":[{"internalType":"address","name":"snMessaging","type":"address"},{"internalType":"uint256","name":"StarknetEscrowAddress_","type":"uint256"},{"internalType":"uint256","name":"StarknetEscrowClaimPaymentSelector_","type":"uint256"},{"internalType":"address","name":"marketMaker_","type":"address"},{"internalType":"address","name":"ZKSyncMailboxAddress","type":"address"}],"stateMutability":"nonpayable","type":"function","name":"initialize"},{"inputs":[],"stateMutability":"view","type":"function","name":"marketMaker","outputs":[{"internalType":"address","name":"","type":"address"}]},{"inputs":[],"stateMutability":"view","type":"function","name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}]},{"inputs":[],"stateMutability":"view","type":"function","name":"proxiableUUID","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}]},{"inputs":[],"stateMutability":"nonpayable","type":"function","name":"renounceOwnership"},{"inputs":[{"internalType":"address","name":"newMMAddress","type":"address"}],"stateMutability":"nonpayable","type":"function","name":"setMMAddress"},{"inputs":[{"internalType":"uint256","name":"NewStarknetEscrowClaimPaymentSelector","type":"uint256"}],"stateMutability":"nonpayable","type":"function","name":"setStarknetClaimPaymentSelector"},{"inputs":[{"internalType":"uint256","name":"newStarknetEscrowAddress","type":"uint256"}],"stateMutability":"nonpayable","type":"function","name":"setStarknetEscrowAddress"},{"inputs":[{"internalType":"address","name":"newZKSyncEscrowAddress","type":"address"}],"stateMutability":"nonpayable","type":"function","name":"setZKSyncEscrowAddress"},{"inputs":[{"internalType":"uint256","name":"orderId","type":"uint256"},{"internalType":"uint256","name":"destAddress","type":"uint256"},{"internalType":"enum PaymentRegistry.Chain","name":"chainId","type":"uint8"}],"stateMutability":"payable","type":"function","name":"transfer"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"stateMutability":"nonpayable","type":"function","name":"transferOwnership"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function","name":"transfers","outputs":[{"internalType":"uint256","name":"destAddress","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bool","name":"isUsed","type":"bool"},{"internalType":"enum PaymentRegistry.Chain","name":"chainId","type":"uint8"}]},{"inputs":[{"internalType":"address","name":"newImplementation","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"stateMutability":"payable","type":"function","name":"upgradeToAndCall"}],"devdoc":{"kind":"dev","methods":{"owner()":{"details":"Returns the address of the current owner."},"proxiableUUID()":{"details":"Implementation of the ERC-1822 {proxiableUUID} function. This returns the storage slot used by the implementation. It is used to validate the implementation's compatibility when performing an upgrade. IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier."},"renounceOwnership()":{"details":"Leaves the contract without owner. It will not be possible to call `onlyOwner` functions. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby disabling any functionality that is only available to the owner."},"transferOwnership(address)":{"details":"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner."},"upgradeToAndCall(address,bytes)":{"custom:oz-upgrades-unsafe-allow-reachable":"delegatecall","details":"Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call encoded in `data`. Calls {_authorizeUpgrade}. Emits an {Upgraded} event."}},"version":1},"userdoc":{"kind":"user","methods":{},"version":1}},"settings":{"remappings":["@matterlabs/interfaces/=lib/era-contracts/l1-contracts/contracts/zksync/interfaces/","@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/","@openzeppelin/contracts/=lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/","ds-test/=lib/forge-std/lib/ds-test/src/","era-contracts/=lib/era-contracts/","erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/","forge-std/=lib/forge-std/src/","openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/","openzeppelin-contracts/=lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/","starknet/=lib/starknet/"],"optimizer":{"enabled":true,"runs":200},"metadata":{"bytecodeHash":"ipfs"},"compilationTarget":{"src/PaymentRegistry.sol":"PaymentRegistry"},"evmVersion":"paris","libraries":{}},"sources":{"lib/era-contracts/l1-contracts/contracts/common/libraries/UncheckedMath.sol":{"keccak256":"0x0d8dd71e77c1d25bac04d19e77c0859109648e013b658fb91b3f876f083d58ad","urls":["bzz-raw://89f31e4b7849059fec7c917e61afb8f7af2cbb763c01ad0c9c326f86b9037b41","dweb:/ipfs/QmRnrLH4WJ7UnrNmHre9rGVW8t3HYrsY59CrFBYfr6TK6k"],"license":"MIT"},"lib/era-contracts/l1-contracts/contracts/zksync/Storage.sol":{"keccak256":"0x43a3f4b2e43014892ddd393ec81ade21d5ccdeb7bb8171141878a4ec035c9458","urls":["bzz-raw://29bae2244558feb34bc393ca0ff70c6d3d636947711a150ceaff246d32fa0a46","dweb:/ipfs/QmUPiwprXNV2bJ8CDgUKQtciWFVYYAbBb8SpUYEYhbHGbs"],"license":"MIT"},"lib/era-contracts/l1-contracts/contracts/zksync/interfaces/IAdmin.sol":{"keccak256":"0xd9845b35414f4b37a3680f36168662ab8b2e355056bdd96bf7d7d4c499849371","urls":["bzz-raw://eb4babe8901e74523ecbebbf192429d9ad3cf9628cc762df98f3a046f40f938a","dweb:/ipfs/QmTadxmp6oexsvZVrhGscSSnZSqL43PEorN4pekzUeL5vy"],"license":"MIT"},"lib/era-contracts/l1-contracts/contracts/zksync/interfaces/IBase.sol":{"keccak256":"0x5477656c5eef9a9b275dc6784438256ef4e06db048781b01d84fb72e0d60c655","urls":["bzz-raw://56bc6517aa13539743be67abb214d5934301c31f7b40c6f7fad67c7aec3c5796","dweb:/ipfs/QmdVdQ8iCsDK9C8krQseWCGNB64AMrKTn1ZF8LLDAq96Et"],"license":"UNLICENSED"},"lib/era-contracts/l1-contracts/contracts/zksync/interfaces/IExecutor.sol":{"keccak256":"0xb580f8687e05fe01afb00b2b77e43a24567993c83fc5b38831f5884e51be292b","urls":["bzz-raw://e73dc57c64af937a6aedba62245bd2fae3a84958f0a9abb70a9df0d02c3f34f8","dweb:/ipfs/QmSVaVAPkQvjVXCjK5XrP2VN4zXY9HuTME8Jyx14FJg4XV"],"license":"MIT"},"lib/era-contracts/l1-contracts/contracts/zksync/interfaces/IGetters.sol":{"keccak256":"0x8b19758b2fe3996f13d9527fcf0d60b838a2a33b16d7a4ddfc79bd64b731f3bc","urls":["bzz-raw://b66cb276ed200456705b23d2e9a7822c3b1746ed4bfda93d94c4528c2b408538","dweb:/ipfs/QmY5uN8mbZZtip6J94XYt6g6xXMpszNRMxEBsDu3mUKaJm"],"license":"MIT"},"lib/era-contracts/l1-contracts/contracts/zksync/interfaces/IMailbox.sol":{"keccak256":"0x985178de1704e015af86ad465874cea585229a29ebb6595589292cd3683a77c6","urls":["bzz-raw://d5fb1365a5122c0033615bde0439badcdd5fa61fa60a72507ef53a8459c5eeaa","dweb:/ipfs/QmeDiRjUZSDKQsFryHP2ePczKzTRfsAofMTzUTiiqgLQ93"],"license":"MIT"},"lib/era-contracts/l1-contracts/contracts/zksync/interfaces/IVerifier.sol":{"keccak256":"0x82fb9aa76bde8914827fe1c60a4f424d915d00ee52ac2ee8f5e408e6313714f2","urls":["bzz-raw://cc915ba7c7f5176d246e6aaa17b09792c8dfddbc9b6826d2be2a38c65a427c0a","dweb:/ipfs/QmUDA9nzF3ot3nLPP865841dKWyQhYtHsNnRb73fGndKoj"],"license":"MIT"},"lib/era-contracts/l1-contracts/contracts/zksync/interfaces/IZkSync.sol":{"keccak256":"0x91bd2b2dacaf33f4558315452dcf8d939e69c4e24bf6062b305aa48f99c1eaf3","urls":["bzz-raw://fda8ff69a1e4dd806aebcde89e99a62ae255d173864a7ff9037f43ee43571931","dweb:/ipfs/QmNQ3VAtToTyYJUBzSb1pz4jRYXPsHseEq2Z624rALGMxy"],"license":"MIT"},"lib/era-contracts/l1-contracts/contracts/zksync/libraries/Diamond.sol":{"keccak256":"0xea7462be367bdeca41c027dec9a632f28716c33c01d99eefd8de992da2b73992","urls":["bzz-raw://7ca0ff34b359dd2d36e098b6d2cc089dea8da03f2ac77d23a823201b91111e0a","dweb:/ipfs/QmVMMH6ckapWMHk1NzfE9TT6st2w8Fjoes3wSfGYdfjVXV"],"license":"MIT"},"lib/era-contracts/l1-contracts/contracts/zksync/libraries/PriorityQueue.sol":{"keccak256":"0x26f86ed98f0f9d29d03c2a30af5f71cae753a15f21ed615022460c9f735ebfcd","urls":["bzz-raw://7bc52833de251772dd0980870756d8d877169094037de4f8319a5925ecb28c43","dweb:/ipfs/QmVrVFZkiZ49F6ftS1U3ummX1NHX3y8V96vKG6eD5N8H1T"],"license":"MIT"},"lib/openzeppelin-contracts-upgradeable/contracts/access/OwnableUpgradeable.sol":{"keccak256":"0xc163fcf9bb10138631a9ba5564df1fa25db9adff73bd9ee868a8ae1858fe093a","urls":["bzz-raw://9706d43a0124053d9880f6e31a59f31bc0a6a3dc1acd66ce0a16e1111658c5f6","dweb:/ipfs/QmUFmfowzkRwGtDu36cXV9SPTBHJ3n7dG9xQiK5B28jTf2"],"license":"MIT"},"lib/openzeppelin-contracts-upgradeable/contracts/proxy/utils/Initializable.sol":{"keccak256":"0x631188737069917d2f909d29ce62c4d48611d326686ba6683e26b72a23bfac0b","urls":["bzz-raw://7a61054ae84cd6c4d04c0c4450ba1d6de41e27e0a2c4f1bcdf58f796b401c609","dweb:/ipfs/QmUvtdp7X1mRVyC3CsHrtPbgoqWaXHp3S1ZR24tpAQYJWM"],"license":"MIT"},"lib/openzeppelin-contracts-upgradeable/contracts/proxy/utils/UUPSUpgradeable.sol":{"keccak256":"0x490959f972df54829d0ffacb71fa025429d9b7b9ebd118f418b41e9c0041ef73","urls":["bzz-raw://1883bc1a16a88922abccd415d1b41caf00c38ee581ae3e5976018d9c17d2c4b7","dweb:/ipfs/QmP2vzQM8RR8ce675KhuZEaUicAPRMUbPLwBsTpxByvn18"],"license":"MIT"},"lib/openzeppelin-contracts-upgradeable/contracts/utils/ContextUpgradeable.sol":{"keccak256":"0xdbef5f0c787055227243a7318ef74c8a5a1108ca3a07f2b3a00ef67769e1e397","urls":["bzz-raw://08e39f23d5b4692f9a40803e53a8156b72b4c1f9902a88cd65ba964db103dab9","dweb:/ipfs/QmPKn6EYDgpga7KtpkA8wV2yJCYGMtc9K4LkJfhKX2RVSV"],"license":"MIT"},"lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/interfaces/draft-IERC1822.sol":{"keccak256":"0xf5c04a8bf51755681f7db413095377dfd1a05b98b6326fb1da0e9a297057caf0","urls":["bzz-raw://f57690465f41860906cf84e6970baaacae9d05b8311674812e6b502bb510441e","dweb:/ipfs/Qme5swSUieatWond1BHyZaEztdLAPu67KcoQTeY4pH5wVd"],"license":"MIT"},"lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/proxy/ERC1967/ERC1967Utils.sol":{"keccak256":"0xf5769456c75195b708e2b006c58f7f349b79752ad13d7c70ec1db05739972b22","urls":["bzz-raw://d363b2bdfba6d28207d661c3b3c23beeab6405a8960ef444f8c61c2afe997600","dweb:/ipfs/QmNcgJD5RL25RKtShX32WTRp1xRfPyThThA7CajTnXMjMA"],"license":"MIT"},"lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/proxy/beacon/IBeacon.sol":{"keccak256":"0xc59a78b07b44b2cf2e8ab4175fca91e8eca1eee2df7357b8d2a8833e5ea1f64c","urls":["bzz-raw://5aa4f07e65444784c29cd7bfcc2341b34381e4e5b5da9f0c5bd00d7f430e66fa","dweb:/ipfs/QmWRMh4Q9DpaU9GvsiXmDdoNYMyyece9if7hnfLz7uqzWM"],"license":"MIT"},"lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/utils/Address.sol":{"keccak256":"0xaf28a975a78550e45f65e559a3ad6a5ad43b9b8a37366999abd1b7084eb70721","urls":["bzz-raw://b7bd24e224f67f65bfadf85dc2929fa965456bb2415478bd0125471b5ce35245","dweb:/ipfs/QmRaydGr8BTHs1kvaZfsNU69pKzUAGFrvABn1KiRSbE51y"],"license":"MIT"},"lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/utils/StorageSlot.sol":{"keccak256":"0x70d9a9cf8d5cc830d7396505ef8eb9686bd0c60a29c6644bd6cc278f9bab8ebe","urls":["bzz-raw://719abb402c11be12355088da587ffd971fee1b035b5aa6b1ba3b1a9493d3c1d7","dweb:/ipfs/QmanHMFVDqVtZAFFaH1CeGQWoHWsFnWHH75fCrguwi77Hq"],"license":"MIT"},"lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/utils/math/SafeCast.sol":{"keccak256":"0xe19a4d5f31d2861e7344e8e535e2feafb913d806d3e2b5fe7782741a2a7094fe","urls":["bzz-raw://4aed79c0fa6f0546ed02f2f683e8f77f0fd2ed7eb34d8bbf3d373c9a6d95b13c","dweb:/ipfs/QmWqVz6UAVqmnWU5pqYPt1o6iDEZyPaBraAA3rKfTTSfYj"],"license":"MIT"},"lib/starknet/IStarknetMessaging.sol":{"keccak256":"0x40014108e2795fd544af0f6322882e99cc3f0872990d504c1ccebce2afea9617","urls":["bzz-raw://d3eec1c3f47243734573b4ac3fc42db2eee4d110d8c39be16fbc6f93498e318d","dweb:/ipfs/QmdYdJFPdEPUFQATa24jNvL59GtdoJeym1w7EARyCq8CvY"],"license":"Apache-2.0."},"lib/starknet/IStarknetMessagingEvents.sol":{"keccak256":"0x71171b10854a020b53b175ed9dc068a56675e2b80f823c0f841ae18977b96e8c","urls":["bzz-raw://70d345e80b4fbbceba9bc0b64be0688710434a5b5d6eb4a60fae808d2bcc03d9","dweb:/ipfs/QmQBdERT6NHiC2cDvTwS7aob1CwuuqQZvZt5ibGzvYawvB"],"license":"Apache-2.0."},"src/PaymentRegistry.sol":{"keccak256":"0x268f685c8a7311ed7ea369307b1c5ad289cad87692757af703b258b6ba84c174","urls":["bzz-raw://beb6946827b8911ed671edc1680642c5af4820972b444f3b4d4b480681b37168","dweb:/ipfs/QmXZyC4bo2tVoYTYtFSxRvsxYdByKhyXPTatPiJmAd8QRt"],"license":"Apache-2.0"}},"version":1},"id":49} \ No newline at end of file +{"abi":[{"type":"constructor","inputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"StarknetChainId","inputs":[],"outputs":[{"name":"","type":"uint128","internalType":"uint128"}],"stateMutability":"view"},{"type":"function","name":"StarknetEscrowAddress","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"StarknetEscrowClaimPaymentBatchSelector","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"StarknetEscrowClaimPaymentSelector","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"UPGRADE_INTERFACE_VERSION","inputs":[],"outputs":[{"name":"","type":"string","internalType":"string"}],"stateMutability":"view"},{"type":"function","name":"ZKSyncChainId","inputs":[],"outputs":[{"name":"","type":"uint128","internalType":"uint128"}],"stateMutability":"view"},{"type":"function","name":"ZKSyncEscrowAddress","inputs":[],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"view"},{"type":"function","name":"ZKSyncEscrowClaimPaymentBatchSelector","inputs":[],"outputs":[{"name":"","type":"bytes4","internalType":"bytes4"}],"stateMutability":"view"},{"type":"function","name":"ZKSyncEscrowClaimPaymentSelector","inputs":[],"outputs":[{"name":"","type":"bytes4","internalType":"bytes4"}],"stateMutability":"view"},{"type":"function","name":"claimPaymentBatchStarknet","inputs":[{"name":"orderIds","type":"uint256[]","internalType":"uint256[]"},{"name":"destAddresses","type":"address[]","internalType":"address[]"},{"name":"amounts","type":"uint256[]","internalType":"uint256[]"}],"outputs":[],"stateMutability":"payable"},{"type":"function","name":"claimPaymentBatchZKSync","inputs":[{"name":"orderIds","type":"uint256[]","internalType":"uint256[]"},{"name":"destAddresses","type":"address[]","internalType":"address[]"},{"name":"amounts","type":"uint256[]","internalType":"uint256[]"},{"name":"gasLimit","type":"uint256","internalType":"uint256"},{"name":"gasPerPubdataByteLimit","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"payable"},{"type":"function","name":"claimPaymentStarknet","inputs":[{"name":"orderId","type":"uint256","internalType":"uint256"},{"name":"destAddress","type":"address","internalType":"address"},{"name":"amount","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"payable"},{"type":"function","name":"claimPaymentZKSync","inputs":[{"name":"orderId","type":"uint256","internalType":"uint256"},{"name":"destAddress","type":"address","internalType":"address"},{"name":"amount","type":"uint256","internalType":"uint256"},{"name":"gasLimit","type":"uint256","internalType":"uint256"},{"name":"gasPerPubdataByteLimit","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"payable"},{"type":"function","name":"initialize","inputs":[{"name":"snMessaging","type":"address","internalType":"address"},{"name":"StarknetEscrowClaimPaymentSelector_","type":"uint256","internalType":"uint256"},{"name":"StarknetEscrowClaimPaymentBatchSelector_","type":"uint256","internalType":"uint256"},{"name":"marketMaker_","type":"address","internalType":"address"},{"name":"ZKSyncDiamondProxyAddress","type":"address","internalType":"address"},{"name":"ZKSyncEscrowClaimPaymentSelector_","type":"bytes4","internalType":"bytes4"},{"name":"ZKSyncEscrowClaimPaymentBatchSelector_","type":"bytes4","internalType":"bytes4"},{"name":"StarknetChainId_","type":"uint128","internalType":"uint128"},{"name":"ZKSyncChainId_","type":"uint128","internalType":"uint128"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"marketMaker","inputs":[],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"view"},{"type":"function","name":"owner","inputs":[],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"view"},{"type":"function","name":"proxiableUUID","inputs":[],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"type":"function","name":"renounceOwnership","inputs":[],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"setMMAddress","inputs":[{"name":"newMMAddress","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"setStarknetClaimPaymentBatchSelector","inputs":[{"name":"NewStarknetEscrowClaimPaymentBatchSelector","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"setStarknetClaimPaymentSelector","inputs":[{"name":"NewStarknetEscrowClaimPaymentSelector","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"setStarknetEscrowAddress","inputs":[{"name":"newStarknetEscrowAddress","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"setZKSyncEscrowAddress","inputs":[{"name":"newZKSyncEscrowAddress","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"setZKSyncEscrowClaimPaymentBatchSelector","inputs":[{"name":"NewZKSyncEscrowClaimPaymentBatchSelector","type":"bytes4","internalType":"bytes4"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"setZKSyncEscrowClaimPaymentSelector","inputs":[{"name":"NewZKSyncEscrowClaimPaymentSelector","type":"bytes4","internalType":"bytes4"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"transfer","inputs":[{"name":"orderId","type":"uint256","internalType":"uint256"},{"name":"destAddress","type":"address","internalType":"address"},{"name":"chainId","type":"uint128","internalType":"uint128"}],"outputs":[],"stateMutability":"payable"},{"type":"function","name":"transferOwnership","inputs":[{"name":"newOwner","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"transfers","inputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"view"},{"type":"function","name":"upgradeToAndCall","inputs":[{"name":"newImplementation","type":"address","internalType":"address"},{"name":"data","type":"bytes","internalType":"bytes"}],"outputs":[],"stateMutability":"payable"},{"type":"event","name":"ClaimPayment","inputs":[{"name":"orderId","type":"uint256","indexed":true,"internalType":"uint256"},{"name":"destAddress","type":"address","indexed":false,"internalType":"address"},{"name":"amount","type":"uint256","indexed":false,"internalType":"uint256"},{"name":"chainId","type":"uint128","indexed":false,"internalType":"uint128"}],"anonymous":false},{"type":"event","name":"ClaimPaymentBatch","inputs":[{"name":"orderIds","type":"uint256[]","indexed":false,"internalType":"uint256[]"},{"name":"destAddresses","type":"address[]","indexed":false,"internalType":"address[]"},{"name":"amounts","type":"uint256[]","indexed":false,"internalType":"uint256[]"},{"name":"chainId","type":"uint128","indexed":false,"internalType":"uint128"}],"anonymous":false},{"type":"event","name":"Initialized","inputs":[{"name":"version","type":"uint64","indexed":false,"internalType":"uint64"}],"anonymous":false},{"type":"event","name":"ModifiedStarknetClaimPaymentBatchSelector","inputs":[{"name":"newEscrowClaimPaymentBatchSelector","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false},{"type":"event","name":"ModifiedStarknetClaimPaymentSelector","inputs":[{"name":"newEscrowClaimPaymentSelector","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false},{"type":"event","name":"ModifiedStarknetEscrowAddress","inputs":[{"name":"newEscrowAddress","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false},{"type":"event","name":"ModifiedZKSyncClaimPaymentBatchSelector","inputs":[{"name":"newZKSyncEscrowClaimPaymentBatchSelector","type":"bytes4","indexed":false,"internalType":"bytes4"}],"anonymous":false},{"type":"event","name":"ModifiedZKSyncClaimPaymentSelector","inputs":[{"name":"newZKSyncEscrowClaimPaymentSelector","type":"bytes4","indexed":false,"internalType":"bytes4"}],"anonymous":false},{"type":"event","name":"ModifiedZKSyncEscrowAddress","inputs":[{"name":"newEscrowAddress","type":"address","indexed":false,"internalType":"address"}],"anonymous":false},{"type":"event","name":"OwnershipTransferred","inputs":[{"name":"previousOwner","type":"address","indexed":true,"internalType":"address"},{"name":"newOwner","type":"address","indexed":true,"internalType":"address"}],"anonymous":false},{"type":"event","name":"Transfer","inputs":[{"name":"orderId","type":"uint256","indexed":true,"internalType":"uint256"},{"name":"srcAddress","type":"address","indexed":false,"internalType":"address"},{"name":"destAddress","type":"address","indexed":false,"internalType":"address"},{"name":"amount","type":"uint256","indexed":false,"internalType":"uint256"},{"name":"chainId","type":"uint128","indexed":false,"internalType":"uint128"}],"anonymous":false},{"type":"event","name":"Upgraded","inputs":[{"name":"implementation","type":"address","indexed":true,"internalType":"address"}],"anonymous":false},{"type":"error","name":"AddressEmptyCode","inputs":[{"name":"target","type":"address","internalType":"address"}]},{"type":"error","name":"ERC1967InvalidImplementation","inputs":[{"name":"implementation","type":"address","internalType":"address"}]},{"type":"error","name":"ERC1967NonPayable","inputs":[]},{"type":"error","name":"FailedInnerCall","inputs":[]},{"type":"error","name":"InvalidInitialization","inputs":[]},{"type":"error","name":"NotInitializing","inputs":[]},{"type":"error","name":"OwnableInvalidOwner","inputs":[{"name":"owner","type":"address","internalType":"address"}]},{"type":"error","name":"OwnableUnauthorizedAccount","inputs":[{"name":"account","type":"address","internalType":"address"}]},{"type":"error","name":"UUPSUnauthorizedCallContext","inputs":[]},{"type":"error","name":"UUPSUnsupportedProxiableUUID","inputs":[{"name":"slot","type":"bytes32","internalType":"bytes32"}]}],"bytecode":{"object":"0x60a0604052306080523480156200001557600080fd5b506200002062000026565b620000da565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000900460ff1615620000775760405163f92ee8a960e01b815260040160405180910390fd5b80546001600160401b0390811614620000d75780546001600160401b0319166001600160401b0390811782556040519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50565b60805161255b62000104600039600081816117ba015281816117e30152611929015261255b6000f3fe6080604052600436106101c25760003560e01c80638c23704d116100f7578063afc69b3c11610095578063d788f4c911610064578063d788f4c914610503578063f04193c814610519578063f12ba5c714610539578063f2fde38b1461055957600080fd5b8063afc69b3c14610490578063b2321572146104b0578063bf9551bf146104c3578063cb8a48c5146104e357600080fd5b8063a7139611116100d1578063a7139611146103f8578063abd43fdd14610418578063acfefa5214610432578063ad3cb1cc1461045257600080fd5b80638c23704d146103b05780638da5cb5b146103c3578063942b8aea146103d857600080fd5b80634f1ef286116101645780636af0abfa1161013e5780636af0abfa14610329578063715018a61461036157806376b5eddc1461037657806383c013871461038957600080fd5b80634f1ef286146102c657806352d1902d146102d95780636835abf4146102ee57600080fd5b80631f21f9af116101a05780631f21f9af14610218578063383bfee4146102505780633c5035dc146102665780633c64f04b1461028657600080fd5b80630a21f170146101c75780631519e961146101dc5780631885d25e14610205575b600080fd5b6101da6101d5366004611cad565b610579565b005b3480156101e857600080fd5b506101f260025481565b6040519081526020015b60405180910390f35b6101da610213366004611d63565b610927565b34801561022457600080fd5b50600154610238906001600160a01b031681565b6040516001600160a01b0390911681526020016101fc565b34801561025c57600080fd5b506101f260055481565b34801561027257600080fd5b506101da610281366004611dc7565b610b51565b34801561029257600080fd5b506102b66102a1366004611e61565b60006020819052908152604090205460ff1681565b60405190151581526020016101fc565b6101da6102d4366004611e90565b610d7e565b3480156102e557600080fd5b506101f2610d9d565b3480156102fa57600080fd5b5060065461031090640100000000900460e01b81565b6040516001600160e01b031990911681526020016101fc565b34801561033557600080fd5b50600854610349906001600160801b031681565b6040516001600160801b0390911681526020016101fc565b34801561036d57600080fd5b506101da610dba565b6101da610384366004611f52565b610dce565b34801561039557600080fd5b5060085461034990600160801b90046001600160801b031681565b6101da6103be366004611f8e565b611015565b3480156103cf57600080fd5b506102386111dc565b3480156103e457600080fd5b50600354610238906001600160a01b031681565b34801561040457600080fd5b506101da610413366004611fd4565b61120a565b34801561042457600080fd5b506006546103109060e01b81565b34801561043e57600080fd5b506101da61044d366004611fd4565b611234565b34801561045e57600080fd5b50610483604051806040016040528060058152602001640352e302e360dc1b81525081565b6040516101fc919061203f565b34801561049c57600080fd5b506101da6104ab366004612052565b611291565b6101da6104be36600461206d565b6112fd565b3480156104cf57600080fd5b506101da6104de366004612052565b6115a7565b3480156104ef57600080fd5b506101da6104fe366004611e61565b611605565b34801561050f57600080fd5b506101f260045481565b34801561052557600080fd5b506101da610534366004611e61565b611642565b34801561054557600080fd5b506101da610554366004611e61565b61167f565b34801561056557600080fd5b506101da610574366004611fd4565b6116bc565b6105816111dc565b6001600160a01b0316336001600160a01b031614806105aa57506001546001600160a01b031633145b6105cf5760405162461bcd60e51b81526004016105c690612116565b60405180910390fd5b8483146105ee5760405162461bcd60e51b81526004016105c69061215d565b84811461060d5760405162461bcd60e51b81526004016105c69061215d565b600061061a86600561219d565b6106259060016121b4565b67ffffffffffffffff81111561063d5761063d611e7a565b604051908082528060200260200182016040528015610666578160200160208202803683370190505b5090508686905081600081518110610680576106806121c7565b60200260200101818152505060005b63ffffffff811687111561085057600088888363ffffffff168181106106b7576106b76121c7565b905060200201359050600087878463ffffffff168181106106da576106da6121c7565b90506020020160208101906106ef9190611fd4565b9050600086868563ffffffff1681811061070b5761070b6121c7565b90506020020135905061071f8383836116fa565b600061072c8560056121dd565b610737906001612205565b9050836001600160801b0316868263ffffffff168151811061075b5761075b6121c7565b6020908102919091010152608084901c86610777836001612205565b63ffffffff168151811061078d5761078d6121c7565b60209081029190910101526001600160a01b038316866107ae836002612205565b63ffffffff16815181106107c4576107c46121c7565b60209081029190910101526001600160801b038216866107e5836003612205565b63ffffffff16815181106107fb576107fb6121c7565b6020908102919091010152608082901c86610817836004612205565b63ffffffff168151811061082d5761082d6121c7565b60200260200101818152505050505050808061084890612229565b91505061068f565b50600754600254600554604051633e3aa6c560e01b81526001600160a01b0390931692633e3aa6c592349261088992879060040161224c565b604080518083038185885af11580156108a6573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906108cb91906122a1565b50506008546040517fb9492e7bf9b06708266caa2b61513011b6164e9a5613a98b4b28822330685b3691610916918a918a918a918a918a918a916001600160801b039091169061233e565b60405180910390a150505050505050565b61092f6111dc565b6001600160a01b0316336001600160a01b0316148061095857506001546001600160a01b031633145b6109745760405162461bcd60e51b81526004016105c690612116565b61097f8383836116fa565b60408051600580825260c082019092526000916020820160a080368337019050509050836001600160801b0316816000815181106109bf576109bf6121c7565b602002602001018181525050608084901c6001600160801b0316816001815181106109ec576109ec6121c7565b602002602001018181525050826001600160a01b031681600281518110610a1557610a156121c7565b602002602001018181525050816001600160801b031681600381518110610a3e57610a3e6121c7565b602002602001018181525050608082901c6001600160801b031681600481518110610a6b57610a6b6121c7565b602090810291909101015260075460025460048054604051633e3aa6c560e01b81526001600160a01b0390941693633e3aa6c5933493610aaf93919288910161224c565b604080518083038185885af1158015610acc573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190610af191906122a1565b5050600854604080516001600160a01b0386168152602081018590526001600160801b039092169082015284907f9b37aa3b3ccd712d4f1f38e0d3633191b3279bc495a91348d5e6e6e862e08a7c9060600160405180910390a250505050565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a008054600160401b810460ff16159067ffffffffffffffff16600081158015610b975750825b905060008267ffffffffffffffff166001148015610bb45750303b155b905081158015610bc2575080155b15610be05760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff191660011785558315610c0a57845460ff60401b1916600160401b1785555b610c1333611796565b610c1b6117a7565b8d600760006101000a8154816001600160a01b0302191690836001600160a01b0316021790555089600660086101000a8154816001600160a01b0302191690836001600160a01b031602179055508c6004819055508b60058190555088600660006101000a81548163ffffffff021916908360e01c021790555087600660046101000a81548163ffffffff021916908360e01c021790555086600860006101000a8154816001600160801b0302191690836001600160801b0316021790555085600860106101000a8154816001600160801b0302191690836001600160801b031602179055508a600160006101000a8154816001600160a01b0302191690836001600160a01b031602179055508315610d6e57845460ff60401b19168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b5050505050505050505050505050565b610d866117af565b610d8f82611854565b610d99828261185c565b5050565b6000610da761191e565b5060008051602061250683398151915290565b610dc2611967565b610dcc6000611999565b565b610dd66111dc565b6001600160a01b0316336001600160a01b03161480610dff57506001546001600160a01b031633145b610e1b5760405162461bcd60e51b81526004016105c690612116565b60003411610e7c5760405162461bcd60e51b815260206004820152602860248201527f496e76616c696420616d6f756e742c2073686f756c6420626520686967686572604482015267103a3430b710181760c11b60648201526084016105c6565b600083833484604051602001610e959493929190612398565b60408051601f19818403018152918152815160209283012060008181529283905291205490915060ff1615610f0c5760405162461bcd60e51b815260206004820152601b60248201527f5472616e7366657220616c72656164792070726f6365737365642e000000000060448201526064016105c6565b600081815260208190526040808220805460ff19166001179055516001600160a01b0385169034908381818185875af1925050503d8060008114610f6c576040519150601f19603f3d011682016040523d82523d6000602084013e610f71565b606091505b5050905080610fb55760405162461bcd60e51b815260206004820152601060248201526f2a3930b739b332b9103330b4b632b21760811b60448201526064016105c6565b604080513381526001600160a01b038616602082015234818301526001600160801b0385166060820152905186917f518415589d99aa369fd185c0e5c8e121cc117d365eea9d4f322ffa352b82ff36919081900360800190a25050505050565b61101d6111dc565b6001600160a01b0316336001600160a01b0316148061104657506001546001600160a01b031633145b6110625760405162461bcd60e51b81526004016105c690612116565b61106d858585611a0a565b60065460408051602481018890526001600160a01b03878116604483015260648083018890528351808403909101815260849092018352602080830180516001600160e01b031660e087901b6001600160e01b031916179052600354845160008082529281019095529294600160401b900482169363eb6724199334931691908690899089908461110e565b60608152602001906001900390816110f95790505b50336040518963ffffffff1660e01b815260040161113297969594939291906123db565b60206040518083038185885af1158015611150573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906111759190612487565b50600854604080516001600160a01b038816815260208101879052600160801b9092046001600160801b03169082015286907f9b37aa3b3ccd712d4f1f38e0d3633191b3279bc495a91348d5e6e6e862e08a7c9060600160405180910390a2505050505050565b7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b031690565b611212611967565b600180546001600160a01b0319166001600160a01b0392909216919091179055565b61123c611967565b600380546001600160a01b0319166001600160a01b0383169081179091556040519081527f266bbe7a56974619c1a655bf40e2622705681de7ad5b9ad8f776b574816ef878906020015b60405180910390a150565b611299611967565b6006805467ffffffff00000000191664010000000060e084811c820292909217928390556040516001600160e01b03199190930490911b1681527f15b3668254acd82e4dfcf164d2fa3ccde6feddcd4d860ce5214a3f849a14ee1790602001611286565b6113056111dc565b6001600160a01b0316336001600160a01b0316148061132e57506001546001600160a01b031633145b61134a5760405162461bcd60e51b81526004016105c690612116565b8685146113695760405162461bcd60e51b81526004016105c69061215d565b8683146113885760405162461bcd60e51b81526004016105c69061215d565b60005b63ffffffff811688111561141e5761140c89898363ffffffff168181106113b4576113b46121c7565b9050602002013588888463ffffffff168181106113d3576113d36121c7565b90506020020160208101906113e89190611fd4565b87878563ffffffff16818110611400576114006121c7565b90506020020135611a0a565b8061141681612229565b91505061138b565b50600654604051600091640100000000900460e01b9061144c908b908b908b908b908b908b906024016124a0565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526006546003549192506001600160a01b03600160401b90910481169163eb672419913491166000858888836040519080825280602002602001820160405280156114dc57816020015b60608152602001906001900390816114c75790505b50336040518963ffffffff1660e01b815260040161150097969594939291906123db565b60206040518083038185885af115801561151e573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906115439190612487565b507fb9492e7bf9b06708266caa2b61513011b6164e9a5613a98b4b28822330685b36898989898989600860109054906101000a90046001600160801b0316604051611594979695949392919061233e565b60405180910390a1505050505050505050565b6115af611967565b6006805460e083811c63ffffffff19909216919091179182905560405191901b6001600160e01b03191681527fac25fa2892bb4bfc20f31e7dd94d1aed6c743ba4b9ea3987ecbdc546f96f8a7090602001611286565b61160d611967565b60058190556040518181527f8472b958091d499bf08adc8eadec9eadfc6f9f6c592220bb4b563c47c38f645b90602001611286565b61164a611967565b60028190556040518181527f770ea1f0ec3952d2a87b139d66a1ac5d469acba670449df142953a082c7e4e8090602001611286565b611687611967565b60048190556040518181527f531414f0fe764471786064a701ebc067e829c6ea0aa005fc180afb5c75d5e7d290602001611286565b6116c4611967565b6001600160a01b0381166116ee57604051631e4fbdf760e01b8152600060048201526024016105c6565b6116f781611999565b50565b60085460405160009161171f918691869186916001600160801b031690602001612398565b60408051601f19818403018152918152815160209283012060008181529283905291205490915060ff1615156001146117905760405162461bcd60e51b81526020600482015260136024820152722a3930b739b332b9103737ba103337bab7321760691b60448201526064016105c6565b50505050565b61179e611a36565b6116f781611a7f565b610dcc611a36565b306001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016148061183657507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031661182a600080516020612506833981519152546001600160a01b031690565b6001600160a01b031614155b15610dcc5760405163703e46dd60e11b815260040160405180910390fd5b6116f7611967565b816001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa9250505080156118b6575060408051601f3d908101601f191682019092526118b391810190612487565b60015b6118de57604051634c9c8ce360e01b81526001600160a01b03831660048201526024016105c6565b600080516020612506833981519152811461190f57604051632a87526960e21b8152600481018290526024016105c6565b6119198383611a87565b505050565b306001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610dcc5760405163703e46dd60e11b815260040160405180910390fd5b336119706111dc565b6001600160a01b031614610dcc5760405163118cdaa760e01b81523360048201526024016105c6565b7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930080546001600160a01b031981166001600160a01b03848116918217845560405192169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3505050565b60085460405160009161171f91869186918691600160801b90046001600160801b031690602001612398565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0054600160401b900460ff16610dcc57604051631afcd79f60e31b815260040160405180910390fd5b6116c4611a36565b611a9082611add565b6040516001600160a01b038316907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a2805115611ad5576119198282611b42565b610d99611bba565b806001600160a01b03163b600003611b1357604051634c9c8ce360e01b81526001600160a01b03821660048201526024016105c6565b60008051602061250683398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b6060600080846001600160a01b031684604051611b5f91906124e9565b600060405180830381855af49150503d8060008114611b9a576040519150601f19603f3d011682016040523d82523d6000602084013e611b9f565b606091505b5091509150611baf858383611bd9565b925050505b92915050565b3415610dcc5760405163b398979f60e01b815260040160405180910390fd5b606082611bee57611be982611c38565b611c31565b8151158015611c0557506001600160a01b0384163b155b15611c2e57604051639996b31560e01b81526001600160a01b03851660048201526024016105c6565b50805b9392505050565b805115611c485780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b60008083601f840112611c7357600080fd5b50813567ffffffffffffffff811115611c8b57600080fd5b6020830191508360208260051b8501011115611ca657600080fd5b9250929050565b60008060008060008060608789031215611cc657600080fd5b863567ffffffffffffffff80821115611cde57600080fd5b611cea8a838b01611c61565b90985096506020890135915080821115611d0357600080fd5b611d0f8a838b01611c61565b90965094506040890135915080821115611d2857600080fd5b50611d3589828a01611c61565b979a9699509497509295939492505050565b80356001600160a01b0381168114611d5e57600080fd5b919050565b600080600060608486031215611d7857600080fd5b83359250611d8860208501611d47565b9150604084013590509250925092565b80356001600160e01b031981168114611d5e57600080fd5b80356001600160801b0381168114611d5e57600080fd5b60008060008060008060008060006101208a8c031215611de657600080fd5b611def8a611d47565b985060208a0135975060408a01359650611e0b60608b01611d47565b9550611e1960808b01611d47565b9450611e2760a08b01611d98565b9350611e3560c08b01611d98565b9250611e4360e08b01611db0565b9150611e526101008b01611db0565b90509295985092959850929598565b600060208284031215611e7357600080fd5b5035919050565b634e487b7160e01b600052604160045260246000fd5b60008060408385031215611ea357600080fd5b611eac83611d47565b9150602083013567ffffffffffffffff80821115611ec957600080fd5b818501915085601f830112611edd57600080fd5b813581811115611eef57611eef611e7a565b604051601f8201601f19908116603f01168101908382118183101715611f1757611f17611e7a565b81604052828152886020848701011115611f3057600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b600080600060608486031215611f6757600080fd5b83359250611f7760208501611d47565b9150611f8560408501611db0565b90509250925092565b600080600080600060a08688031215611fa657600080fd5b85359450611fb660208701611d47565b94979496505050506040830135926060810135926080909101359150565b600060208284031215611fe657600080fd5b611c3182611d47565b60005b8381101561200a578181015183820152602001611ff2565b50506000910152565b6000815180845261202b816020860160208601611fef565b601f01601f19169290920160200192915050565b602081526000611c316020830184612013565b60006020828403121561206457600080fd5b611c3182611d98565b60008060008060008060008060a0898b03121561208957600080fd5b883567ffffffffffffffff808211156120a157600080fd5b6120ad8c838d01611c61565b909a50985060208b01359150808211156120c657600080fd5b6120d28c838d01611c61565b909850965060408b01359150808211156120eb57600080fd5b506120f88b828c01611c61565b999c989b509699959896976060870135966080013595509350505050565b60208082526027908201527f4f6e6c79204f776e6572206f72204d4d2063616e2063616c6c207468697320666040820152663ab731ba34b7b760c91b606082015260800190565b60208082526010908201526f24b73b30b634b2103632b733ba34399760811b604082015260600190565b634e487b7160e01b600052601160045260246000fd5b8082028115828204841417611bb457611bb4612187565b80820180821115611bb457611bb4612187565b634e487b7160e01b600052603260045260246000fd5b63ffffffff8181168382160280821691908281146121fd576121fd612187565b505092915050565b63ffffffff81811683821601908082111561222257612222612187565b5092915050565b600063ffffffff80831681810361224257612242612187565b6001019392505050565b6000606082018583526020858185015260606040850152818551808452608086019150828701935060005b8181101561229357845183529383019391830191600101612277565b509098975050505050505050565b600080604083850312156122b457600080fd5b505080516020909101519092909150565b81835260006001600160fb1b038311156122de57600080fd5b8260051b80836020870137939093016020019392505050565b8183526000602080850194508260005b85811015612333576001600160a01b0361232083611d47565b1687529582019590820190600101612307565b509495945050505050565b60808152600061235260808301898b6122c5565b828103602084015261236581888a6122f7565b9050828103604084015261237a8186886122c5565b9150506001600160801b038316606083015298975050505050505050565b93845260609290921b6bffffffffffffffffffffffff19166020840152603483015260801b6fffffffffffffffffffffffffffffffff1916605482015260640190565b60018060a01b038816815260006020888184015260e0604084015261240360e0840189612013565b87606085015286608085015283810360a08501528086518083528383019150838160051b84010184890160005b8381101561245e57601f1986840301855261244c838351612013565b94870194925090860190600101612430565b50506001600160a01b03881660c0880152945061247b9350505050565b98975050505050505050565b60006020828403121561249957600080fd5b5051919050565b6060815260006124b460608301888a6122c5565b82810360208401526124c78187896122f7565b905082810360408401526124dc8185876122c5565b9998505050505050505050565b600082516124fb818460208701611fef565b919091019291505056fe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbca2646970667358221220d3a1f8a1c63893b5cd3d144d14b2f87f28ba0fa4c31ddad304646cfca448b31464736f6c63430008140033","sourceMap":"494:10475:49:-:0;;;1171:4:34;1128:48;;2092:53:49;;;;;;;;;-1:-1:-1;2116:22:49;:20;:22::i;:::-;494:10475;;7711:422:33;8870:21;7900:15;;;;;;;7896:76;;;7938:23;;-1:-1:-1;;;7938:23:33;;;;;;;;;;;7896:76;7985:14;;-1:-1:-1;;;;;7985:14:33;;;:34;7981:146;;8035:33;;-1:-1:-1;;;;;;8035:33:33;-1:-1:-1;;;;;8035:33:33;;;;;8087:29;;158:50:53;;;8087:29:33;;146:2:53;131:18;8087:29:33;;;;;;;7981:146;7760:373;7711:422::o;14:200:53:-;494:10475:49;;;;;;;;;;;;;;;;;;;;;;","linkReferences":{}},"deployedBytecode":{"object":"0x6080604052600436106101c25760003560e01c80638c23704d116100f7578063afc69b3c11610095578063d788f4c911610064578063d788f4c914610503578063f04193c814610519578063f12ba5c714610539578063f2fde38b1461055957600080fd5b8063afc69b3c14610490578063b2321572146104b0578063bf9551bf146104c3578063cb8a48c5146104e357600080fd5b8063a7139611116100d1578063a7139611146103f8578063abd43fdd14610418578063acfefa5214610432578063ad3cb1cc1461045257600080fd5b80638c23704d146103b05780638da5cb5b146103c3578063942b8aea146103d857600080fd5b80634f1ef286116101645780636af0abfa1161013e5780636af0abfa14610329578063715018a61461036157806376b5eddc1461037657806383c013871461038957600080fd5b80634f1ef286146102c657806352d1902d146102d95780636835abf4146102ee57600080fd5b80631f21f9af116101a05780631f21f9af14610218578063383bfee4146102505780633c5035dc146102665780633c64f04b1461028657600080fd5b80630a21f170146101c75780631519e961146101dc5780631885d25e14610205575b600080fd5b6101da6101d5366004611cad565b610579565b005b3480156101e857600080fd5b506101f260025481565b6040519081526020015b60405180910390f35b6101da610213366004611d63565b610927565b34801561022457600080fd5b50600154610238906001600160a01b031681565b6040516001600160a01b0390911681526020016101fc565b34801561025c57600080fd5b506101f260055481565b34801561027257600080fd5b506101da610281366004611dc7565b610b51565b34801561029257600080fd5b506102b66102a1366004611e61565b60006020819052908152604090205460ff1681565b60405190151581526020016101fc565b6101da6102d4366004611e90565b610d7e565b3480156102e557600080fd5b506101f2610d9d565b3480156102fa57600080fd5b5060065461031090640100000000900460e01b81565b6040516001600160e01b031990911681526020016101fc565b34801561033557600080fd5b50600854610349906001600160801b031681565b6040516001600160801b0390911681526020016101fc565b34801561036d57600080fd5b506101da610dba565b6101da610384366004611f52565b610dce565b34801561039557600080fd5b5060085461034990600160801b90046001600160801b031681565b6101da6103be366004611f8e565b611015565b3480156103cf57600080fd5b506102386111dc565b3480156103e457600080fd5b50600354610238906001600160a01b031681565b34801561040457600080fd5b506101da610413366004611fd4565b61120a565b34801561042457600080fd5b506006546103109060e01b81565b34801561043e57600080fd5b506101da61044d366004611fd4565b611234565b34801561045e57600080fd5b50610483604051806040016040528060058152602001640352e302e360dc1b81525081565b6040516101fc919061203f565b34801561049c57600080fd5b506101da6104ab366004612052565b611291565b6101da6104be36600461206d565b6112fd565b3480156104cf57600080fd5b506101da6104de366004612052565b6115a7565b3480156104ef57600080fd5b506101da6104fe366004611e61565b611605565b34801561050f57600080fd5b506101f260045481565b34801561052557600080fd5b506101da610534366004611e61565b611642565b34801561054557600080fd5b506101da610554366004611e61565b61167f565b34801561056557600080fd5b506101da610574366004611fd4565b6116bc565b6105816111dc565b6001600160a01b0316336001600160a01b031614806105aa57506001546001600160a01b031633145b6105cf5760405162461bcd60e51b81526004016105c690612116565b60405180910390fd5b8483146105ee5760405162461bcd60e51b81526004016105c69061215d565b84811461060d5760405162461bcd60e51b81526004016105c69061215d565b600061061a86600561219d565b6106259060016121b4565b67ffffffffffffffff81111561063d5761063d611e7a565b604051908082528060200260200182016040528015610666578160200160208202803683370190505b5090508686905081600081518110610680576106806121c7565b60200260200101818152505060005b63ffffffff811687111561085057600088888363ffffffff168181106106b7576106b76121c7565b905060200201359050600087878463ffffffff168181106106da576106da6121c7565b90506020020160208101906106ef9190611fd4565b9050600086868563ffffffff1681811061070b5761070b6121c7565b90506020020135905061071f8383836116fa565b600061072c8560056121dd565b610737906001612205565b9050836001600160801b0316868263ffffffff168151811061075b5761075b6121c7565b6020908102919091010152608084901c86610777836001612205565b63ffffffff168151811061078d5761078d6121c7565b60209081029190910101526001600160a01b038316866107ae836002612205565b63ffffffff16815181106107c4576107c46121c7565b60209081029190910101526001600160801b038216866107e5836003612205565b63ffffffff16815181106107fb576107fb6121c7565b6020908102919091010152608082901c86610817836004612205565b63ffffffff168151811061082d5761082d6121c7565b60200260200101818152505050505050808061084890612229565b91505061068f565b50600754600254600554604051633e3aa6c560e01b81526001600160a01b0390931692633e3aa6c592349261088992879060040161224c565b604080518083038185885af11580156108a6573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906108cb91906122a1565b50506008546040517fb9492e7bf9b06708266caa2b61513011b6164e9a5613a98b4b28822330685b3691610916918a918a918a918a918a918a916001600160801b039091169061233e565b60405180910390a150505050505050565b61092f6111dc565b6001600160a01b0316336001600160a01b0316148061095857506001546001600160a01b031633145b6109745760405162461bcd60e51b81526004016105c690612116565b61097f8383836116fa565b60408051600580825260c082019092526000916020820160a080368337019050509050836001600160801b0316816000815181106109bf576109bf6121c7565b602002602001018181525050608084901c6001600160801b0316816001815181106109ec576109ec6121c7565b602002602001018181525050826001600160a01b031681600281518110610a1557610a156121c7565b602002602001018181525050816001600160801b031681600381518110610a3e57610a3e6121c7565b602002602001018181525050608082901c6001600160801b031681600481518110610a6b57610a6b6121c7565b602090810291909101015260075460025460048054604051633e3aa6c560e01b81526001600160a01b0390941693633e3aa6c5933493610aaf93919288910161224c565b604080518083038185885af1158015610acc573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190610af191906122a1565b5050600854604080516001600160a01b0386168152602081018590526001600160801b039092169082015284907f9b37aa3b3ccd712d4f1f38e0d3633191b3279bc495a91348d5e6e6e862e08a7c9060600160405180910390a250505050565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a008054600160401b810460ff16159067ffffffffffffffff16600081158015610b975750825b905060008267ffffffffffffffff166001148015610bb45750303b155b905081158015610bc2575080155b15610be05760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff191660011785558315610c0a57845460ff60401b1916600160401b1785555b610c1333611796565b610c1b6117a7565b8d600760006101000a8154816001600160a01b0302191690836001600160a01b0316021790555089600660086101000a8154816001600160a01b0302191690836001600160a01b031602179055508c6004819055508b60058190555088600660006101000a81548163ffffffff021916908360e01c021790555087600660046101000a81548163ffffffff021916908360e01c021790555086600860006101000a8154816001600160801b0302191690836001600160801b0316021790555085600860106101000a8154816001600160801b0302191690836001600160801b031602179055508a600160006101000a8154816001600160a01b0302191690836001600160a01b031602179055508315610d6e57845460ff60401b19168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b5050505050505050505050505050565b610d866117af565b610d8f82611854565b610d99828261185c565b5050565b6000610da761191e565b5060008051602061250683398151915290565b610dc2611967565b610dcc6000611999565b565b610dd66111dc565b6001600160a01b0316336001600160a01b03161480610dff57506001546001600160a01b031633145b610e1b5760405162461bcd60e51b81526004016105c690612116565b60003411610e7c5760405162461bcd60e51b815260206004820152602860248201527f496e76616c696420616d6f756e742c2073686f756c6420626520686967686572604482015267103a3430b710181760c11b60648201526084016105c6565b600083833484604051602001610e959493929190612398565b60408051601f19818403018152918152815160209283012060008181529283905291205490915060ff1615610f0c5760405162461bcd60e51b815260206004820152601b60248201527f5472616e7366657220616c72656164792070726f6365737365642e000000000060448201526064016105c6565b600081815260208190526040808220805460ff19166001179055516001600160a01b0385169034908381818185875af1925050503d8060008114610f6c576040519150601f19603f3d011682016040523d82523d6000602084013e610f71565b606091505b5050905080610fb55760405162461bcd60e51b815260206004820152601060248201526f2a3930b739b332b9103330b4b632b21760811b60448201526064016105c6565b604080513381526001600160a01b038616602082015234818301526001600160801b0385166060820152905186917f518415589d99aa369fd185c0e5c8e121cc117d365eea9d4f322ffa352b82ff36919081900360800190a25050505050565b61101d6111dc565b6001600160a01b0316336001600160a01b0316148061104657506001546001600160a01b031633145b6110625760405162461bcd60e51b81526004016105c690612116565b61106d858585611a0a565b60065460408051602481018890526001600160a01b03878116604483015260648083018890528351808403909101815260849092018352602080830180516001600160e01b031660e087901b6001600160e01b031916179052600354845160008082529281019095529294600160401b900482169363eb6724199334931691908690899089908461110e565b60608152602001906001900390816110f95790505b50336040518963ffffffff1660e01b815260040161113297969594939291906123db565b60206040518083038185885af1158015611150573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906111759190612487565b50600854604080516001600160a01b038816815260208101879052600160801b9092046001600160801b03169082015286907f9b37aa3b3ccd712d4f1f38e0d3633191b3279bc495a91348d5e6e6e862e08a7c9060600160405180910390a2505050505050565b7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b031690565b611212611967565b600180546001600160a01b0319166001600160a01b0392909216919091179055565b61123c611967565b600380546001600160a01b0319166001600160a01b0383169081179091556040519081527f266bbe7a56974619c1a655bf40e2622705681de7ad5b9ad8f776b574816ef878906020015b60405180910390a150565b611299611967565b6006805467ffffffff00000000191664010000000060e084811c820292909217928390556040516001600160e01b03199190930490911b1681527f15b3668254acd82e4dfcf164d2fa3ccde6feddcd4d860ce5214a3f849a14ee1790602001611286565b6113056111dc565b6001600160a01b0316336001600160a01b0316148061132e57506001546001600160a01b031633145b61134a5760405162461bcd60e51b81526004016105c690612116565b8685146113695760405162461bcd60e51b81526004016105c69061215d565b8683146113885760405162461bcd60e51b81526004016105c69061215d565b60005b63ffffffff811688111561141e5761140c89898363ffffffff168181106113b4576113b46121c7565b9050602002013588888463ffffffff168181106113d3576113d36121c7565b90506020020160208101906113e89190611fd4565b87878563ffffffff16818110611400576114006121c7565b90506020020135611a0a565b8061141681612229565b91505061138b565b50600654604051600091640100000000900460e01b9061144c908b908b908b908b908b908b906024016124a0565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526006546003549192506001600160a01b03600160401b90910481169163eb672419913491166000858888836040519080825280602002602001820160405280156114dc57816020015b60608152602001906001900390816114c75790505b50336040518963ffffffff1660e01b815260040161150097969594939291906123db565b60206040518083038185885af115801561151e573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906115439190612487565b507fb9492e7bf9b06708266caa2b61513011b6164e9a5613a98b4b28822330685b36898989898989600860109054906101000a90046001600160801b0316604051611594979695949392919061233e565b60405180910390a1505050505050505050565b6115af611967565b6006805460e083811c63ffffffff19909216919091179182905560405191901b6001600160e01b03191681527fac25fa2892bb4bfc20f31e7dd94d1aed6c743ba4b9ea3987ecbdc546f96f8a7090602001611286565b61160d611967565b60058190556040518181527f8472b958091d499bf08adc8eadec9eadfc6f9f6c592220bb4b563c47c38f645b90602001611286565b61164a611967565b60028190556040518181527f770ea1f0ec3952d2a87b139d66a1ac5d469acba670449df142953a082c7e4e8090602001611286565b611687611967565b60048190556040518181527f531414f0fe764471786064a701ebc067e829c6ea0aa005fc180afb5c75d5e7d290602001611286565b6116c4611967565b6001600160a01b0381166116ee57604051631e4fbdf760e01b8152600060048201526024016105c6565b6116f781611999565b50565b60085460405160009161171f918691869186916001600160801b031690602001612398565b60408051601f19818403018152918152815160209283012060008181529283905291205490915060ff1615156001146117905760405162461bcd60e51b81526020600482015260136024820152722a3930b739b332b9103737ba103337bab7321760691b60448201526064016105c6565b50505050565b61179e611a36565b6116f781611a7f565b610dcc611a36565b306001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016148061183657507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031661182a600080516020612506833981519152546001600160a01b031690565b6001600160a01b031614155b15610dcc5760405163703e46dd60e11b815260040160405180910390fd5b6116f7611967565b816001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa9250505080156118b6575060408051601f3d908101601f191682019092526118b391810190612487565b60015b6118de57604051634c9c8ce360e01b81526001600160a01b03831660048201526024016105c6565b600080516020612506833981519152811461190f57604051632a87526960e21b8152600481018290526024016105c6565b6119198383611a87565b505050565b306001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610dcc5760405163703e46dd60e11b815260040160405180910390fd5b336119706111dc565b6001600160a01b031614610dcc5760405163118cdaa760e01b81523360048201526024016105c6565b7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930080546001600160a01b031981166001600160a01b03848116918217845560405192169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3505050565b60085460405160009161171f91869186918691600160801b90046001600160801b031690602001612398565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0054600160401b900460ff16610dcc57604051631afcd79f60e31b815260040160405180910390fd5b6116c4611a36565b611a9082611add565b6040516001600160a01b038316907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a2805115611ad5576119198282611b42565b610d99611bba565b806001600160a01b03163b600003611b1357604051634c9c8ce360e01b81526001600160a01b03821660048201526024016105c6565b60008051602061250683398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b6060600080846001600160a01b031684604051611b5f91906124e9565b600060405180830381855af49150503d8060008114611b9a576040519150601f19603f3d011682016040523d82523d6000602084013e611b9f565b606091505b5091509150611baf858383611bd9565b925050505b92915050565b3415610dcc5760405163b398979f60e01b815260040160405180910390fd5b606082611bee57611be982611c38565b611c31565b8151158015611c0557506001600160a01b0384163b155b15611c2e57604051639996b31560e01b81526001600160a01b03851660048201526024016105c6565b50805b9392505050565b805115611c485780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b60008083601f840112611c7357600080fd5b50813567ffffffffffffffff811115611c8b57600080fd5b6020830191508360208260051b8501011115611ca657600080fd5b9250929050565b60008060008060008060608789031215611cc657600080fd5b863567ffffffffffffffff80821115611cde57600080fd5b611cea8a838b01611c61565b90985096506020890135915080821115611d0357600080fd5b611d0f8a838b01611c61565b90965094506040890135915080821115611d2857600080fd5b50611d3589828a01611c61565b979a9699509497509295939492505050565b80356001600160a01b0381168114611d5e57600080fd5b919050565b600080600060608486031215611d7857600080fd5b83359250611d8860208501611d47565b9150604084013590509250925092565b80356001600160e01b031981168114611d5e57600080fd5b80356001600160801b0381168114611d5e57600080fd5b60008060008060008060008060006101208a8c031215611de657600080fd5b611def8a611d47565b985060208a0135975060408a01359650611e0b60608b01611d47565b9550611e1960808b01611d47565b9450611e2760a08b01611d98565b9350611e3560c08b01611d98565b9250611e4360e08b01611db0565b9150611e526101008b01611db0565b90509295985092959850929598565b600060208284031215611e7357600080fd5b5035919050565b634e487b7160e01b600052604160045260246000fd5b60008060408385031215611ea357600080fd5b611eac83611d47565b9150602083013567ffffffffffffffff80821115611ec957600080fd5b818501915085601f830112611edd57600080fd5b813581811115611eef57611eef611e7a565b604051601f8201601f19908116603f01168101908382118183101715611f1757611f17611e7a565b81604052828152886020848701011115611f3057600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b600080600060608486031215611f6757600080fd5b83359250611f7760208501611d47565b9150611f8560408501611db0565b90509250925092565b600080600080600060a08688031215611fa657600080fd5b85359450611fb660208701611d47565b94979496505050506040830135926060810135926080909101359150565b600060208284031215611fe657600080fd5b611c3182611d47565b60005b8381101561200a578181015183820152602001611ff2565b50506000910152565b6000815180845261202b816020860160208601611fef565b601f01601f19169290920160200192915050565b602081526000611c316020830184612013565b60006020828403121561206457600080fd5b611c3182611d98565b60008060008060008060008060a0898b03121561208957600080fd5b883567ffffffffffffffff808211156120a157600080fd5b6120ad8c838d01611c61565b909a50985060208b01359150808211156120c657600080fd5b6120d28c838d01611c61565b909850965060408b01359150808211156120eb57600080fd5b506120f88b828c01611c61565b999c989b509699959896976060870135966080013595509350505050565b60208082526027908201527f4f6e6c79204f776e6572206f72204d4d2063616e2063616c6c207468697320666040820152663ab731ba34b7b760c91b606082015260800190565b60208082526010908201526f24b73b30b634b2103632b733ba34399760811b604082015260600190565b634e487b7160e01b600052601160045260246000fd5b8082028115828204841417611bb457611bb4612187565b80820180821115611bb457611bb4612187565b634e487b7160e01b600052603260045260246000fd5b63ffffffff8181168382160280821691908281146121fd576121fd612187565b505092915050565b63ffffffff81811683821601908082111561222257612222612187565b5092915050565b600063ffffffff80831681810361224257612242612187565b6001019392505050565b6000606082018583526020858185015260606040850152818551808452608086019150828701935060005b8181101561229357845183529383019391830191600101612277565b509098975050505050505050565b600080604083850312156122b457600080fd5b505080516020909101519092909150565b81835260006001600160fb1b038311156122de57600080fd5b8260051b80836020870137939093016020019392505050565b8183526000602080850194508260005b85811015612333576001600160a01b0361232083611d47565b1687529582019590820190600101612307565b509495945050505050565b60808152600061235260808301898b6122c5565b828103602084015261236581888a6122f7565b9050828103604084015261237a8186886122c5565b9150506001600160801b038316606083015298975050505050505050565b93845260609290921b6bffffffffffffffffffffffff19166020840152603483015260801b6fffffffffffffffffffffffffffffffff1916605482015260640190565b60018060a01b038816815260006020888184015260e0604084015261240360e0840189612013565b87606085015286608085015283810360a08501528086518083528383019150838160051b84010184890160005b8381101561245e57601f1986840301855261244c838351612013565b94870194925090860190600101612430565b50506001600160a01b03881660c0880152945061247b9350505050565b98975050505050505050565b60006020828403121561249957600080fd5b5051919050565b6060815260006124b460608301888a6122c5565b82810360208401526124c78187896122f7565b905082810360408401526124dc8185876122c5565b9998505050505050505050565b600082516124fb818460208701611fef565b919091019291505056fe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbca2646970667358221220d3a1f8a1c63893b5cd3d144d14b2f87f28ba0fa4c31ddad304646cfca448b31464736f6c63430008140033","sourceMap":"494:10475:49:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4838:1365;;;;;;:::i;:::-;;:::i;:::-;;1499:36;;;;;;;;;;;;;;;;;;;1625:25:53;;;1613:2;1598:18;1499:36:49;;;;;;;;4000:832;;;;;;:::i;:::-;;:::i;1467:26::-;;;;;;;;;;-1:-1:-1;1467:26:49;;;;-1:-1:-1;;;;;1467:26:49;;;;;;-1:-1:-1;;;;;2439:32:53;;;2421:51;;2409:2;2394:18;1467:26:49;2275:203:53;1636:54:49;;;;;;;;;;;;;;;;2213:1088;;;;;;;;;;-1:-1:-1;2213:1088:49;;;;;:::i;:::-;;:::i;1420:41::-;;;;;;;;;;-1:-1:-1;1420:41:49;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;3977:14:53;;3970:22;3952:41;;3940:2;3925:18;1420:41:49;3812:187:53;4161:214:34;;;;;;:::i;:::-;;:::i;3708:134::-;;;;;;;;;;;;;:::i;1748:51:49:-;;;;;;;;;;-1:-1:-1;1748:51:49;;;;;;;;;;;;;;-1:-1:-1;;;;;;5480:33:53;;;5462:52;;5450:2;5435:18;1748:51:49;5318:202:53;2021:30:49;;;;;;;;;;-1:-1:-1;2021:30:49;;;;-1:-1:-1;;;;;2021:30:49;;;;;;-1:-1:-1;;;;;5689:47:53;;;5671:66;;5659:2;5644:18;2021:30:49;5525:218:53;3155:101:32;;;;;;;;;;;;;:::i;3344:650:49:-;;;;;;:::i;:::-;;:::i;2057:28::-;;;;;;;;;;-1:-1:-1;2057:28:49;;;;-1:-1:-1;;;2057:28:49;;-1:-1:-1;;;;;2057:28:49;;;6495:887;;;;;;:::i;:::-;;:::i;2441:144:32:-;;;;;;;;;;;;;:::i;1541:34:49:-;;;;;;;;;;-1:-1:-1;1541:34:49;;;;-1:-1:-1;;;;;1541:34:49;;;10612:106;;;;;;;;;;-1:-1:-1;10612:106:49;;;;;:::i;:::-;;:::i;1696:46::-;;;;;;;;;;-1:-1:-1;1696:46:49;;;;;;;;9155:218;;;;;;;;;;-1:-1:-1;9155:218:49;;;;;:::i;:::-;;:::i;1819:58:34:-;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;1819:58:34;;;;;;;;;;;;:::i;10275:308:49:-;;;;;;;;;;-1:-1:-1;10275:308:49;;;;;:::i;:::-;;:::i;7388:1198::-;;;;;;:::i;:::-;;:::i;9991:278::-;;;;;;;;;;-1:-1:-1;9991:278:49;;;;;:::i;:::-;;:::i;9670:315::-;;;;;;;;;;-1:-1:-1;9670:315:49;;;;;:::i;:::-;;:::i;1581:49::-;;;;;;;;;;;;;;;;8919:230;;;;;;;;;;-1:-1:-1;8919:230:49;;;;;:::i;:::-;;:::i;9379:285::-;;;;;;;;;;-1:-1:-1;9379:285:49;;;;;:::i;:::-;;:::i;3405:215:32:-;;;;;;;;;;-1:-1:-1;3405:215:32;;;;;:::i;:::-;;:::i;4838:1365:49:-;10779:7;:5;:7::i;:::-;-1:-1:-1;;;;;10765:21:49;:10;-1:-1:-1;;;;;10765:21:49;;:50;;;-1:-1:-1;10804:11:49;;-1:-1:-1;;;;;10804:11:49;10790:10;:25;10765:50;10757:102;;;;-1:-1:-1;;;10757:102:49;;;;;;;:::i;:::-;;;;;;;;;5045:39;;::::1;5037:68;;;;-1:-1:-1::0;;;5037:68:49::1;;;;;;;:::i;:::-;5123:33:::0;;::::1;5115:62;;;;-1:-1:-1::0;;;5115:62:49::1;;;;;;;:::i;:::-;5188:24;5229:19;5233:8:::0;5229:1:::1;:19;:::i;:::-;:23;::::0;5251:1:::1;5229:23;:::i;:::-;5215:38;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;-1:-1:-1;5215:38:49::1;;5188:65;;5277:8;;:15;;5264:7;5272:1;5264:10;;;;;;;;:::i;:::-;;;;;;:28;;;::::0;::::1;5308:10;5303:643;5324:21;::::0;::::1;::::0;-1:-1:-1;5303:643:49::1;;;5368:15;5386:8;;5395:3;5386:13;;;;;;;;;:::i;:::-;;;;;;;5368:31;;5413:19;5435:13;;5449:3;5435:18;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;5413:40;;5467:14;5484:7;;5492:3;5484:12;;;;;;;;;:::i;:::-;;;;;;;5467:29;;5511:59;5541:7;5550:11;5563:6;5511:29;:59::i;:::-;5585:15;5607:7;5611:3:::0;5607:1:::1;:7;:::i;:::-;5603:11;::::0;:1:::1;:11;:::i;:::-;5585:29;;5656:7;-1:-1:-1::0;;;;;5628:36:49::1;:7;5636:8;5628:17;;;;;;;;;;:::i;:::-;;::::0;;::::1;::::0;;;;;:36;5728:3:::1;5717:14:::0;;::::1;5685:7:::0;5693:12:::1;:8:::0;5704:1:::1;5693:12;:::i;:::-;5685:21;;;;;;;;;;:::i;:::-;;::::0;;::::1;::::0;;;;;:47;-1:-1:-1;;;;;5778:29:49;::::1;5754:7:::0;5762:12:::1;:8:::0;5773:1:::1;5762:12;:::i;:::-;5754:21;;;;;;;;;;:::i;:::-;;::::0;;::::1;::::0;;;;;:53;-1:-1:-1;;;;;5821:39:49;::::1;:7:::0;5829:12:::1;:8:::0;5840:1:::1;5829:12;:::i;:::-;5821:21;;;;;;;;;;:::i;:::-;;::::0;;::::1;::::0;;;;;:39;5923:3:::1;5913:13:::0;;::::1;5881:7:::0;5889:12:::1;:8:::0;5900:1:::1;5889:12;:::i;:::-;5881:21;;;;;;;;;;:::i;:::-;;;;;;:46;;;::::0;::::1;5354:592;;;;5347:5;;;;;:::i;:::-;;;;5303:643;;;-1:-1:-1::0;5956:12:49::1;::::0;6016:21:::1;::::0;6051:39:::1;::::0;5956:156:::1;::::0;-1:-1:-1;;;5956:156:49;;-1:-1:-1;;;;;5956:12:49;;::::1;::::0;:28:::1;::::0;5992:9:::1;::::0;5956:156:::1;::::0;6104:7;;5956:156:::1;;;:::i;:::-;;::::0;::::1;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1::0;;6180:15:49::1;::::0;6128:68:::1;::::0;::::1;::::0;::::1;::::0;6146:8;;;;6156:13;;;;6171:7;;;;-1:-1:-1;;;;;6180:15:49;;::::1;::::0;6128:68:::1;:::i;:::-;;;;;;;;5027:1176;4838:1365:::0;;;;;;:::o;4000:832::-;10779:7;:5;:7::i;:::-;-1:-1:-1;;;;;10765:21:49;:10;-1:-1:-1;;;;;10765:21:49;;:50;;;-1:-1:-1;10804:11:49;;-1:-1:-1;;;;;10804:11:49;10790:10;:25;10765:50;10757:102;;;;-1:-1:-1;;;10757:102:49;;;;;;;:::i;:::-;4125:59:::1;4155:7;4164:11;4177:6;4125:29;:59::i;:::-;4222:16;::::0;;4236:1:::1;4222:16:::0;;;;;::::1;::::0;;;4195:24:::1;::::0;4222:16:::1;::::0;::::1;::::0;;::::1;::::0;::::1;;::::0;-1:-1:-1;4222:16:49::1;4195:43;;4350:7;-1:-1:-1::0;;;;;4329:29:49::1;:7;4337:1;4329:10;;;;;;;;:::i;:::-;;;;;;:29;;;::::0;::::1;4407:3;4396:7;:14;;-1:-1:-1::0;;;;;4375:36:49::1;:7;4383:1;4375:10;;;;;;;;:::i;:::-;;;;;;:36;;;::::0;::::1;4458:11;-1:-1:-1::0;;;;;4442:29:49::1;4429:7;4437:1;4429:10;;;;;;;;:::i;:::-;;;;;;:42;;;::::0;::::1;4502:6;-1:-1:-1::0;;;;;4481:28:49::1;:7;4489:1;4481:10;;;;;;;;:::i;:::-;;;;;;:28;;;::::0;::::1;4557:3;4547:6;:13;;-1:-1:-1::0;;;;;4526:35:49::1;:7;4534:1;4526:10;;;;;;;;:::i;:::-;;::::0;;::::1;::::0;;;;;:35;4599:12:::1;::::0;4659:21:::1;::::0;4694:34:::1;::::0;;4599:151:::1;::::0;-1:-1:-1;;;4599:151:49;;-1:-1:-1;;;;;4599:12:49;;::::1;::::0;:28:::1;::::0;4635:9:::1;::::0;4599:151:::1;::::0;4659:21;;4742:7;;4599:151:::1;;:::i;:::-;;::::0;::::1;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1::0;;4809:15:49::1;::::0;4766:59:::1;::::0;;-1:-1:-1;;;;;13942:32:53;;13924:51;;14006:2;13991:18;;13984:34;;;-1:-1:-1;;;;;4809:15:49;;::::1;14034:18:53::0;;;14027:75;4779:7:49;;4766:59:::1;::::0;13912:2:53;13897:18;4766:59:49::1;;;;;;;4115:717;4000:832:::0;;;:::o;2213:1088::-;8870:21:33;4302:15;;-1:-1:-1;;;4302:15:33;;;;4301:16;;4348:14;;4158:30;4726:16;;:34;;;;;4746:14;4726:34;4706:54;;4770:17;4790:11;:16;;4805:1;4790:16;:50;;;;-1:-1:-1;4818:4:33;4810:25;:30;4790:50;4770:70;;4856:12;4855:13;:30;;;;;4873:12;4872:13;4855:30;4851:91;;;4908:23;;-1:-1:-1;;;4908:23:33;;;;;;;;;;;4851:91;4951:18;;-1:-1:-1;;4951:18:33;4968:1;4951:18;;;4979:67;;;;5013:22;;-1:-1:-1;;;;5013:22:33;-1:-1:-1;;;5013:22:33;;;4979:67;2648:26:49::1;2663:10;2648:14;:26::i;:::-;2684:24;:22;:24::i;:::-;2753:11;2719:12;;:46;;;;;-1:-1:-1::0;;;;;2719:46:49::1;;;;;-1:-1:-1::0;;;;;2719:46:49::1;;;;;;2805:25;2775:19;;:56;;;;;-1:-1:-1::0;;;;;2775:56:49::1;;;;;-1:-1:-1::0;;;;;2775:56:49::1;;;;;;2879:35;2842:34;:72;;;;2966:40;2924:39;:82;;;;3051:33;3016:32;;:68;;;;;;;;;;;;;;;;;;3134:38;3094:37;;:78;;;;;;;;;;;;;;;;;;3201:16;3183:15;;:34;;;;;-1:-1:-1::0;;;;;3183:34:49::1;;;;;-1:-1:-1::0;;;;;3183:34:49::1;;;;;;3243:14;3227:13;;:30;;;;;-1:-1:-1::0;;;;;3227:30:49::1;;;;;-1:-1:-1::0;;;;;3227:30:49::1;;;;;;3282:12;3268:11;;:26;;;;;-1:-1:-1::0;;;;;3268:26:49::1;;;;;-1:-1:-1::0;;;;;3268:26:49::1;;;;;;5070:14:33::0;5066:101;;;5100:23;;-1:-1:-1;;;;5100:23:33;;;5142:14;;-1:-1:-1;14266:50:53;;5142:14:33;;14254:2:53;14239:18;5142:14:33;;;;;;;5066:101;4092:1081;;;;;2213:1088:49;;;;;;;;;:::o;4161:214:34:-;2655:13;:11;:13::i;:::-;4276:36:::1;4294:17;4276;:36::i;:::-;4322:46;4344:17;4363:4;4322:21;:46::i;:::-;4161:214:::0;;:::o;3708:134::-;3777:7;2926:20;:18;:20::i;:::-;-1:-1:-1;;;;;;;;;;;;3708:134:34;:::o;3155:101:32:-;2334:13;:11;:13::i;:::-;3219:30:::1;3246:1;3219:18;:30::i;:::-;3155:101::o:0;3344:650:49:-;10779:7;:5;:7::i;:::-;-1:-1:-1;;;;;10765:21:49;:10;-1:-1:-1;;;;;10765:21:49;;:50;;;-1:-1:-1;10804:11:49;;-1:-1:-1;;;;;10804:11:49;10790:10;:25;10765:50;10757:102;;;;-1:-1:-1;;;10757:102:49;;;;;;;:::i;:::-;3478:1:::1;3466:9;:13;3458:66;;;::::0;-1:-1:-1;;;3458:66:49;;14529:2:53;3458:66:49::1;::::0;::::1;14511:21:53::0;14568:2;14548:18;;;14541:30;14607:34;14587:18;;;14580:62;-1:-1:-1;;;14658:18:53;;;14651:38;14706:19;;3458:66:49::1;14327:404:53::0;3458:66:49::1;3535:13;3578:7;3587:11;3600:9;3611:7;3561:58;;;;;;;;;;;:::i;:::-;;::::0;;-1:-1:-1;;3561:58:49;;::::1;::::0;;;;;;3551:69;;3561:58:::1;3551:69:::0;;::::1;::::0;3639:9:::1;:16:::0;;;;;;;;;;3551:69;;-1:-1:-1;3639:16:49::1;;:25;3631:65;;;::::0;-1:-1:-1;;;3631:65:49;;15424:2:53;3631:65:49::1;::::0;::::1;15406:21:53::0;15463:2;15443:18;;;15436:30;15502:29;15482:18;;;15475:57;15549:18;;3631:65:49::1;15222:351:53::0;3631:65:49::1;3706:9;:16:::0;;;::::1;::::0;;;;;;;:23;;-1:-1:-1;;3706:23:49::1;3725:4;3706:23;::::0;;3793:47;-1:-1:-1;;;;;3793:25:49;::::1;::::0;3826:9:::1;::::0;3706;3793:47;3706:9;3793:47;3826:9;3793:25;:47:::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3775:65;;;3871:7;3863:36;;;::::0;-1:-1:-1;;;3863:36:49;;15990:2:53;3863:36:49::1;::::0;::::1;15972:21:53::0;16029:2;16009:18;;;16002:30;-1:-1:-1;;;16048:18:53;;;16041:46;16104:18;;3863:36:49::1;15788:340:53::0;3863:36:49::1;3914:62;::::0;;3932:10:::1;16402:34:53::0;;-1:-1:-1;;;;;16472:15:53;;16467:2;16452:18;;16445:43;3957:9:49::1;16504:18:53::0;;;16497:34;-1:-1:-1;;;;;16567:47:53;;16562:2;16547:18;;16540:75;3914:62:49;;3923:7;;3914:62:::1;::::0;;;;;16351:3:53;3914:62:49;;::::1;3448:546;;3344:650:::0;;;:::o;6495:887::-;10779:7;:5;:7::i;:::-;-1:-1:-1;;;;;10765:21:49;:10;-1:-1:-1;;;;;10765:21:49;;:50;;;-1:-1:-1;10804:11:49;;-1:-1:-1;;;;;10804:11:49;10790:10;:25;10765:50;10757:102;;;;-1:-1:-1;;;10757:102:49;;;;;;;:::i;:::-;6698:57:::1;6726:7;6735:11;6748:6;6698:27;:57::i;:::-;6829:32;::::0;6793:144:::1;::::0;;::::1;::::0;::::1;16828:25:53::0;;;-1:-1:-1;;;;;16889:32:53;;;16869:18;;;16862:60;16938:18;;;;16931:34;;;6793:144:49;;;;;;;;;;16801:18:53;;;;6793:144:49;;::::1;::::0;;::::1;::::0;;-1:-1:-1;;;;;6793:144:49::1;6829:32;::::0;;::::1;-1:-1:-1::0;;;;;;6793:144:49::1;;::::0;;7020:19:::1;::::0;7201:14;;-1:-1:-1;7201:14:49;;;;;::::1;::::0;;;6793:144;;-1:-1:-1;;;6948:19:49;::::1;::::0;::::1;::::0;:40:::1;::::0;6996:9:::1;::::0;7020:19:::1;::::0;-1:-1:-1;6793:144:49;;7141:8;;7164:22;;-1:-1:-1;7201:14:49::1;::::0;::::1;;;;;;;;;;;;;;;;;;7252:10;6948:343;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1::0;7350:13:49::1;::::0;7307:57:::1;::::0;;-1:-1:-1;;;;;13942:32:53;;13924:51;;14006:2;13991:18;;13984:34;;;-1:-1:-1;;;7350:13:49;;::::1;-1:-1:-1::0;;;;;7350:13:49::1;14034:18:53::0;;;14027:75;7320:7:49;;7307:57:::1;::::0;13912:2:53;13897:18;7307:57:49::1;;;;;;;6688:694;6495:887:::0;;;;;:::o;2441:144:32:-;1313:22;2570:8;-1:-1:-1;;;;;2570:8:32;;2441:144::o;10612:106:49:-;2334:13:32;:11;:13::i;:::-;10685:11:49::1;:26:::0;;-1:-1:-1;;;;;;10685:26:49::1;-1:-1:-1::0;;;;;10685:26:49;;;::::1;::::0;;;::::1;::::0;;10612:106::o;9155:218::-;2334:13:32;:11;:13::i;:::-;9248:19:49::1;:44:::0;;-1:-1:-1;;;;;;9248:44:49::1;-1:-1:-1::0;;;;;9248:44:49;::::1;::::0;;::::1;::::0;;;9307:51:::1;::::0;2421::53;;;9307::49::1;::::0;2409:2:53;2394:18;9307:51:49::1;;;;;;;;9155:218:::0;:::o;10275:308::-;2334:13:32;:11;:13::i;:::-;10403:37:49::1;:80:::0;;-1:-1:-1;;10403:80:49::1;::::0;::::1;::::0;;::::1;::::0;::::1;::::0;;;::::1;::::0;;;;10498:78:::1;::::0;-1:-1:-1;;;;;;10538:37:49;;;::::1;::::0;;::::1;5480:33:53::0;5462:52;;10498:78:49::1;::::0;5450:2:53;5435:18;10498:78:49::1;5318:202:53::0;7388:1198:49;10779:7;:5;:7::i;:::-;-1:-1:-1;;;;;10765:21:49;:10;-1:-1:-1;;;;;10765:21:49;;:50;;;-1:-1:-1;10804:11:49;;-1:-1:-1;;;;;10804:11:49;10790:10;:25;10765:50;10757:102;;;;-1:-1:-1;;;10757:102:49;;;;;;;:::i;:::-;7658:39;;::::1;7650:68;;;;-1:-1:-1::0;;;7650:68:49::1;;;;;;;:::i;:::-;7736:33:::0;;::::1;7728:62;;;;-1:-1:-1::0;;;7728:62:49::1;;;;;;;:::i;:::-;7806:10;7801:152;7822:21;::::0;::::1;::::0;-1:-1:-1;7801:152:49::1;;;7866:76;7894:8;;7903:3;7894:13;;;;;;;;;:::i;:::-;;;;;;;7909;;7923:3;7909:18;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;7929:7;;7937:3;7929:12;;;;;;;;;:::i;:::-;;;;;;;7866:27;:76::i;:::-;7845:5:::0;::::1;::::0;::::1;:::i;:::-;;;;7801:152;;;-1:-1:-1::0;8026:37:49::1;::::0;7990:153:::1;::::0;7963:24:::1;::::0;8026:37;;::::1;;;::::0;7990:153:::1;::::0;8077:8;;;;8099:13;;;;8126:7;;;;7990:153:::1;;;:::i;:::-;;::::0;;-1:-1:-1;;7990:153:49;;::::1;::::0;;;;;;::::1;::::0;::::1;::::0;;-1:-1:-1;;;;;7990:153:49::1;-1:-1:-1::0;;;;;;7990:153:49;;::::1;::::0;;;::::1;::::0;;;8154:19:::1;::::0;8226::::1;::::0;7990:153;;-1:-1:-1;;;;;;;;;8154:19:49;;::::1;::::0;::::1;::::0;:40:::1;::::0;8202:9:::1;::::0;8226:19:::1;-1:-1:-1::0;7990:153:49;8347:8;8370:22;-1:-1:-1;8407:14:49::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8458:10;8154:343;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;8513:66;8531:8;;8541:13;;8556:7;;8565:13;;;;;;;;;-1:-1:-1::0;;;;;8565:13:49::1;8513:66;;;;;;;;;;;;:::i;:::-;;;;;;;;7640:946;7388:1198:::0;;;;;;;;:::o;9991:278::-;2334:13:32;:11;:13::i;:::-;10109:32:49::1;:70:::0;;::::1;::::0;;::::1;-1:-1:-1::0;;10109:70:49;;::::1;::::0;;;::::1;::::0;;;;10194:68:::1;::::0;10229:32;;::::1;-1:-1:-1::0;;;;;;5480:33:53;5462:52;;10194:68:49::1;::::0;5450:2:53;5435:18;10194:68:49::1;5318:202:53::0;9670:315:49;2334:13:32;:11;:13::i;:::-;9797:39:49::1;:84:::0;;;9896:82:::1;::::0;1625:25:53;;;9896:82:49::1;::::0;1613:2:53;1598:18;9896:82:49::1;1479:177:53::0;8919:230:49;2334:13:32;:11;:13::i;:::-;9016:21:49::1;:48:::0;;;9079:55:::1;::::0;1625:25:53;;;9079:55:49::1;::::0;1613:2:53;1598:18;9079:55:49::1;1479:177:53::0;9379:285:49;2334:13:32;:11;:13::i;:::-;9496:34:49::1;:74:::0;;;9585:72:::1;::::0;1625:25:53;;;9585:72:49::1;::::0;1613:2:53;1598:18;9585:72:49::1;1479:177:53::0;3405:215:32;2334:13;:11;:13::i;:::-;-1:-1:-1;;;;;3489:22:32;::::1;3485:91;;3534:31;::::0;-1:-1:-1;;;3534:31:32;;3562:1:::1;3534:31;::::0;::::1;2421:51:53::0;2394:18;;3534:31:32::1;2275:203:53::0;3485:91:32::1;3585:28;3604:8;3585:18;:28::i;:::-;3405:215:::0;:::o;6209:280:49:-;6399:15;;6352:63;;6326:13;;6352:63;;6369:7;;6378:11;;6391:6;;-1:-1:-1;;;;;6399:15:49;;6352:63;;;:::i;:::-;;;;-1:-1:-1;;6352:63:49;;;;;;;;;6342:74;;6352:63;6342:74;;;;6434:9;:16;;;;;;;;;;6342:74;;-1:-1:-1;6434:16:49;;:24;;:16;:24;6426:56;;;;-1:-1:-1;;;6426:56:49;;19457:2:53;6426:56:49;;;19439:21:53;19496:2;19476:18;;;19469:30;-1:-1:-1;;;19515:18:53;;;19508:49;19574:18;;6426:56:49;19255:343:53;6426:56:49;6316:173;6209:280;;;:::o;1847:127:32:-;6931:20:33;:18;:20::i;:::-;1929:38:32::1;1954:12;1929:24;:38::i;2970:67:34:-:0;6931:20:33;:18;:20::i;4603:312:34:-;4683:4;-1:-1:-1;;;;;4692:6:34;4675:23;;;:120;;;4789:6;-1:-1:-1;;;;;4753:42:34;:32;-1:-1:-1;;;;;;;;;;;2036:53:38;-1:-1:-1;;;;;2036:53:38;;1958:138;4753:32:34;-1:-1:-1;;;;;4753:42:34;;;4675:120;4658:251;;;4869:29;;-1:-1:-1;;;4869:29:34;;;;;;;;;;;10883:84:49;2334:13:32;:11;:13::i;6057:538:34:-;6174:17;-1:-1:-1;;;;;6156:50:34;;:52;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;6156:52:34;;;;;;;;-1:-1:-1;;6156:52:34;;;;;;;;;;;;:::i;:::-;;;6152:437;;6518:60;;-1:-1:-1;;;6518:60:34;;-1:-1:-1;;;;;2439:32:53;;6518:60:34;;;2421:51:53;2394:18;;6518:60:34;2275:203:53;6152:437:34;-1:-1:-1;;;;;;;;;;;6250:40:34;;6246:120;;6317:34;;-1:-1:-1;;;6317:34:34;;;;;1625:25:53;;;1598:18;;6317:34:34;1479:177:53;6246:120:34;6379:54;6409:17;6428:4;6379:29;:54::i;:::-;6209:235;6057:538;;:::o;5032:213::-;5106:4;-1:-1:-1;;;;;5115:6:34;5098:23;;5094:145;;5199:29;;-1:-1:-1;;;5199:29:34;;;;;;;;;;;2658:162:32;966:10:35;2717:7:32;:5;:7::i;:::-;-1:-1:-1;;;;;2717:23:32;;2713:101;;2763:40;;-1:-1:-1;;;2763:40:32;;966:10:35;2763:40:32;;;2421:51:53;2394:18;;2763:40:32;2275:203:53;3774:248:32;1313:22;3923:8;;-1:-1:-1;;;;;;3941:19:32;;-1:-1:-1;;;;;3941:19:32;;;;;;;;3975:40;;3923:8;;;;;3975:40;;3847:24;;3975:40;3837:185;;3774:248;:::o;8592:321:49:-;8780:13;;8733:61;;8707:13;;8733:61;;8750:7;;8759:11;;8772:6;;-1:-1:-1;;;8780:13:49;;-1:-1:-1;;;;;8780:13:49;;8733:61;;;:::i;7084:141:33:-;8870:21;8560:40;-1:-1:-1;;;8560:40:33;;;;7146:73;;7191:17;;-1:-1:-1;;;7191:17:33;;;;;;;;;;;1980:235:32;6931:20:33;:18;:20::i;2781:335:38:-;2872:37;2891:17;2872:18;:37::i;:::-;2924:27;;-1:-1:-1;;;;;2924:27:38;;;;;;;;2966:11;;:15;2962:148;;2997:53;3026:17;3045:4;2997:28;:53::i;2962:148::-;3081:18;:16;:18::i;2188:281::-;2265:17;-1:-1:-1;;;;;2265:29:38;;2298:1;2265:34;2261:119;;2322:47;;-1:-1:-1;;;2322:47:38;;-1:-1:-1;;;;;2439:32:53;;2322:47:38;;;2421:51:53;2394:18;;2322:47:38;2275:203:53;2261:119:38;-1:-1:-1;;;;;;;;;;;2389:73:38;;-1:-1:-1;;;;;;2389:73:38;-1:-1:-1;;;;;2389:73:38;;;;;;;;;;2188:281::o;4106:253:42:-;4189:12;4214;4228:23;4255:6;-1:-1:-1;;;;;4255:19:42;4275:4;4255:25;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4213:67;;;;4297:55;4324:6;4332:7;4341:10;4297:26;:55::i;:::-;4290:62;;;;4106:253;;;;;:::o;6603:122:38:-;6653:9;:13;6649:70;;6689:19;;-1:-1:-1;;;6689:19:38;;;;;;;;;;;4625:582:42;4769:12;4798:7;4793:408;;4821:19;4829:10;4821:7;:19::i;:::-;4793:408;;;5045:17;;:22;:49;;;;-1:-1:-1;;;;;;5071:18:42;;;:23;5045:49;5041:119;;;5121:24;;-1:-1:-1;;;5121:24:42;;-1:-1:-1;;;;;2439:32:53;;5121:24:42;;;2421:51:53;2394:18;;5121:24:42;2275:203:53;5041:119:42;-1:-1:-1;5180:10:42;4793:408;4625:582;;;;;:::o;5743:516::-;5874:17;;:21;5870:383;;6102:10;6096:17;6158:15;6145:10;6141:2;6137:19;6130:44;5870:383;6225:17;;-1:-1:-1;;;6225:17:42;;;;;;;;;;;14:367:53;77:8;87:6;141:3;134:4;126:6;122:17;118:27;108:55;;159:1;156;149:12;108:55;-1:-1:-1;182:20:53;;225:18;214:30;;211:50;;;257:1;254;247:12;211:50;294:4;286:6;282:17;270:29;;354:3;347:4;337:6;334:1;330:14;322:6;318:27;314:38;311:47;308:67;;;371:1;368;361:12;308:67;14:367;;;;;:::o;386:1088::-;544:6;552;560;568;576;584;637:2;625:9;616:7;612:23;608:32;605:52;;;653:1;650;643:12;605:52;693:9;680:23;722:18;763:2;755:6;752:14;749:34;;;779:1;776;769:12;749:34;818:70;880:7;871:6;860:9;856:22;818:70;:::i;:::-;907:8;;-1:-1:-1;792:96:53;-1:-1:-1;995:2:53;980:18;;967:32;;-1:-1:-1;1011:16:53;;;1008:36;;;1040:1;1037;1030:12;1008:36;1079:72;1143:7;1132:8;1121:9;1117:24;1079:72;:::i;:::-;1170:8;;-1:-1:-1;1053:98:53;-1:-1:-1;1258:2:53;1243:18;;1230:32;;-1:-1:-1;1274:16:53;;;1271:36;;;1303:1;1300;1293:12;1271:36;;1342:72;1406:7;1395:8;1384:9;1380:24;1342:72;:::i;:::-;386:1088;;;;-1:-1:-1;386:1088:53;;-1:-1:-1;386:1088:53;;1433:8;;386:1088;-1:-1:-1;;;386:1088:53:o;1661:173::-;1729:20;;-1:-1:-1;;;;;1778:31:53;;1768:42;;1758:70;;1824:1;1821;1814:12;1758:70;1661:173;;;:::o;1839:322::-;1916:6;1924;1932;1985:2;1973:9;1964:7;1960:23;1956:32;1953:52;;;2001:1;1998;1991:12;1953:52;2037:9;2024:23;2014:33;;2066:38;2100:2;2089:9;2085:18;2066:38;:::i;:::-;2056:48;;2151:2;2140:9;2136:18;2123:32;2113:42;;1839:322;;;;;:::o;2483:173::-;2550:20;;-1:-1:-1;;;;;;2599:32:53;;2589:43;;2579:71;;2646:1;2643;2636:12;2661:188;2729:20;;-1:-1:-1;;;;;2778:46:53;;2768:57;;2758:85;;2839:1;2836;2829:12;2854:768;2983:6;2991;2999;3007;3015;3023;3031;3039;3047;3100:3;3088:9;3079:7;3075:23;3071:33;3068:53;;;3117:1;3114;3107:12;3068:53;3140:29;3159:9;3140:29;:::i;:::-;3130:39;;3216:2;3205:9;3201:18;3188:32;3178:42;;3267:2;3256:9;3252:18;3239:32;3229:42;;3290:38;3324:2;3313:9;3309:18;3290:38;:::i;:::-;3280:48;;3347:39;3381:3;3370:9;3366:19;3347:39;:::i;:::-;3337:49;;3405:38;3438:3;3427:9;3423:19;3405:38;:::i;:::-;3395:48;;3462:38;3495:3;3484:9;3480:19;3462:38;:::i;:::-;3452:48;;3519:39;3553:3;3542:9;3538:19;3519:39;:::i;:::-;3509:49;;3577:39;3611:3;3600:9;3596:19;3577:39;:::i;:::-;3567:49;;2854:768;;;;;;;;;;;:::o;3627:180::-;3686:6;3739:2;3727:9;3718:7;3714:23;3710:32;3707:52;;;3755:1;3752;3745:12;3707:52;-1:-1:-1;3778:23:53;;3627:180;-1:-1:-1;3627:180:53:o;4004:127::-;4065:10;4060:3;4056:20;4053:1;4046:31;4096:4;4093:1;4086:15;4120:4;4117:1;4110:15;4136:995;4213:6;4221;4274:2;4262:9;4253:7;4249:23;4245:32;4242:52;;;4290:1;4287;4280:12;4242:52;4313:29;4332:9;4313:29;:::i;:::-;4303:39;;4393:2;4382:9;4378:18;4365:32;4416:18;4457:2;4449:6;4446:14;4443:34;;;4473:1;4470;4463:12;4443:34;4511:6;4500:9;4496:22;4486:32;;4556:7;4549:4;4545:2;4541:13;4537:27;4527:55;;4578:1;4575;4568:12;4527:55;4614:2;4601:16;4636:2;4632;4629:10;4626:36;;;4642:18;;:::i;:::-;4717:2;4711:9;4685:2;4771:13;;-1:-1:-1;;4767:22:53;;;4791:2;4763:31;4759:40;4747:53;;;4815:18;;;4835:22;;;4812:46;4809:72;;;4861:18;;:::i;:::-;4901:10;4897:2;4890:22;4936:2;4928:6;4921:18;4976:7;4971:2;4966;4962;4958:11;4954:20;4951:33;4948:53;;;4997:1;4994;4987:12;4948:53;5053:2;5048;5044;5040:11;5035:2;5027:6;5023:15;5010:46;5098:1;5093:2;5088;5080:6;5076:15;5072:24;5065:35;5119:6;5109:16;;;;;;;4136:995;;;;;:::o;5748:328::-;5825:6;5833;5841;5894:2;5882:9;5873:7;5869:23;5865:32;5862:52;;;5910:1;5907;5900:12;5862:52;5946:9;5933:23;5923:33;;5975:38;6009:2;5998:9;5994:18;5975:38;:::i;:::-;5965:48;;6032:38;6066:2;6055:9;6051:18;6032:38;:::i;:::-;6022:48;;5748:328;;;;;:::o;6081:460::-;6176:6;6184;6192;6200;6208;6261:3;6249:9;6240:7;6236:23;6232:33;6229:53;;;6278:1;6275;6268:12;6229:53;6314:9;6301:23;6291:33;;6343:38;6377:2;6366:9;6362:18;6343:38;:::i;:::-;6081:460;;6333:48;;-1:-1:-1;;;;6428:2:53;6413:18;;6400:32;;6479:2;6464:18;;6451:32;;6530:3;6515:19;;;6502:33;;-1:-1:-1;6081:460:53:o;6546:186::-;6605:6;6658:2;6646:9;6637:7;6633:23;6629:32;6626:52;;;6674:1;6671;6664:12;6626:52;6697:29;6716:9;6697:29;:::i;6737:250::-;6822:1;6832:113;6846:6;6843:1;6840:13;6832:113;;;6922:11;;;6916:18;6903:11;;;6896:39;6868:2;6861:10;6832:113;;;-1:-1:-1;;6979:1:53;6961:16;;6954:27;6737:250::o;6992:271::-;7034:3;7072:5;7066:12;7099:6;7094:3;7087:19;7115:76;7184:6;7177:4;7172:3;7168:14;7161:4;7154:5;7150:16;7115:76;:::i;:::-;7245:2;7224:15;-1:-1:-1;;7220:29:53;7211:39;;;;7252:4;7207:50;;6992:271;-1:-1:-1;;6992:271:53:o;7268:220::-;7417:2;7406:9;7399:21;7380:4;7437:45;7478:2;7467:9;7463:18;7455:6;7437:45;:::i;7493:184::-;7551:6;7604:2;7592:9;7583:7;7579:23;7575:32;7572:52;;;7620:1;7617;7610:12;7572:52;7643:28;7661:9;7643:28;:::i;7682:1226::-;7858:6;7866;7874;7882;7890;7898;7906;7914;7967:3;7955:9;7946:7;7942:23;7938:33;7935:53;;;7984:1;7981;7974:12;7935:53;8024:9;8011:23;8053:18;8094:2;8086:6;8083:14;8080:34;;;8110:1;8107;8100:12;8080:34;8149:70;8211:7;8202:6;8191:9;8187:22;8149:70;:::i;:::-;8238:8;;-1:-1:-1;8123:96:53;-1:-1:-1;8326:2:53;8311:18;;8298:32;;-1:-1:-1;8342:16:53;;;8339:36;;;8371:1;8368;8361:12;8339:36;8410:72;8474:7;8463:8;8452:9;8448:24;8410:72;:::i;:::-;8501:8;;-1:-1:-1;8384:98:53;-1:-1:-1;8589:2:53;8574:18;;8561:32;;-1:-1:-1;8605:16:53;;;8602:36;;;8634:1;8631;8624:12;8602:36;;8673:72;8737:7;8726:8;8715:9;8711:24;8673:72;:::i;:::-;7682:1226;;;;-1:-1:-1;7682:1226:53;;;;8764:8;;8846:2;8831:18;;8818:32;;8897:3;8882:19;8869:33;;-1:-1:-1;7682:1226:53;-1:-1:-1;;;;7682:1226:53:o;9098:403::-;9300:2;9282:21;;;9339:2;9319:18;;;9312:30;9378:34;9373:2;9358:18;;9351:62;-1:-1:-1;;;9444:2:53;9429:18;;9422:37;9491:3;9476:19;;9098:403::o;9506:340::-;9708:2;9690:21;;;9747:2;9727:18;;;9720:30;-1:-1:-1;;;9781:2:53;9766:18;;9759:46;9837:2;9822:18;;9506:340::o;9851:127::-;9912:10;9907:3;9903:20;9900:1;9893:31;9943:4;9940:1;9933:15;9967:4;9964:1;9957:15;9983:168;10056:9;;;10087;;10104:15;;;10098:22;;10084:37;10074:71;;10125:18;;:::i;10156:125::-;10221:9;;;10242:10;;;10239:36;;;10255:18;;:::i;10286:127::-;10347:10;10342:3;10338:20;10335:1;10328:31;10378:4;10375:1;10368:15;10402:4;10399:1;10392:15;10418:249;10489:10;10531;;;10543;;;10527:27;10574:20;;;;10489:10;10613:24;;;10603:58;;10641:18;;:::i;:::-;10603:58;;10418:249;;;;:::o;10672:172::-;10739:10;10769;;;10781;;;10765:27;;10804:11;;;10801:37;;;10818:18;;:::i;:::-;10801:37;10672:172;;;;:::o;10849:201::-;10887:3;10915:10;10960:2;10953:5;10949:14;10987:2;10978:7;10975:15;10972:41;;10993:18;;:::i;:::-;11042:1;11029:15;;10849:201;-1:-1:-1;;;10849:201:53:o;11055:775::-;11253:4;11301:2;11290:9;11286:18;11331:6;11320:9;11313:25;11357:2;11395:6;11390:2;11379:9;11375:18;11368:34;11438:2;11433;11422:9;11418:18;11411:30;11461:6;11496;11490:13;11527:6;11519;11512:22;11565:3;11554:9;11550:19;11543:26;;11604:2;11596:6;11592:15;11578:29;;11625:1;11635:169;11649:6;11646:1;11643:13;11635:169;;;11710:13;;11698:26;;11779:15;;;;11744:12;;;;11671:1;11664:9;11635:169;;;-1:-1:-1;11821:3:53;;11055:775;-1:-1:-1;;;;;;;;11055:775:53:o;11835:245::-;11914:6;11922;11975:2;11963:9;11954:7;11950:23;11946:32;11943:52;;;11991:1;11988;11981:12;11943:52;-1:-1:-1;;12014:16:53;;12070:2;12055:18;;;12049:25;12014:16;;12049:25;;-1:-1:-1;11835:245:53:o;12085:311::-;12173:19;;;12155:3;-1:-1:-1;;;;;12204:31:53;;12201:51;;;12248:1;12245;12238:12;12201:51;12284:6;12281:1;12277:14;12336:8;12329:5;12322:4;12317:3;12313:14;12300:45;12365:18;;;;12385:4;12361:29;;12085:311;-1:-1:-1;;;12085:311:53:o;12401:447::-;12501:6;12496:3;12489:19;12471:3;12527:4;12556:2;12551:3;12547:12;12540:19;;12582:5;12605:1;12615:208;12629:6;12626:1;12623:13;12615:208;;;-1:-1:-1;;;;;12694:26:53;12713:6;12694:26;:::i;:::-;12690:52;12678:65;;12763:12;;;;12798:15;;;;12651:1;12644:9;12615:208;;;-1:-1:-1;12839:3:53;;12401:447;-1:-1:-1;;;;;12401:447:53:o;12853:864::-;13246:3;13235:9;13228:22;13209:4;13273:74;13342:3;13331:9;13327:19;13319:6;13311;13273:74;:::i;:::-;13395:9;13387:6;13383:22;13378:2;13367:9;13363:18;13356:50;13429:61;13483:6;13475;13467;13429:61;:::i;:::-;13415:75;;13538:9;13530:6;13526:22;13521:2;13510:9;13506:18;13499:50;13566:61;13620:6;13612;13604;13566:61;:::i;:::-;13558:69;;;-1:-1:-1;;;;;13667:6:53;13663:47;13658:2;13647:9;13643:18;13636:75;12853:864;;;;;;;;;;:::o;14736:481::-;14949:19;;;15006:2;15002:15;;;;-1:-1:-1;;14998:53:53;14993:2;14984:12;;14977:75;15077:2;15068:12;;15061:28;15127:3;15123:16;-1:-1:-1;;15119:62:53;15114:2;15105:12;;15098:84;15207:3;15198:13;;14736:481::o;16976:1330::-;17396:1;17392;17387:3;17383:11;17379:19;17371:6;17367:32;17356:9;17349:51;17330:4;17419:2;17457:6;17452:2;17441:9;17437:18;17430:34;17500:3;17495:2;17484:9;17480:18;17473:31;17527:46;17568:3;17557:9;17553:19;17545:6;17527:46;:::i;:::-;17609:6;17604:2;17593:9;17589:18;17582:34;17653:6;17647:3;17636:9;17632:19;17625:35;17709:9;17701:6;17697:22;17691:3;17680:9;17676:19;17669:51;17740:6;17775;17769:13;17806:6;17798;17791:22;17841:2;17833:6;17829:15;17822:22;;17900:2;17890:6;17887:1;17883:14;17875:6;17871:27;17867:36;17938:2;17930:6;17926:15;17959:1;17969:252;17983:6;17980:1;17977:13;17969:252;;;18073:2;18069:7;18060:6;18052;18048:19;18044:33;18039:3;18032:46;18101:40;18134:6;18125;18119:13;18101:40;:::i;:::-;18199:12;;;;18091:50;-1:-1:-1;18164:15:53;;;;18005:1;17998:9;17969:252;;;-1:-1:-1;;;;;;;2232:31:53;;18295:3;18280:19;;2220:44;18238:6;-1:-1:-1;18253:47:53;;-1:-1:-1;;;;2166:104:53;18253:47;16976:1330;;;;;;;;;;:::o;18311:184::-;18381:6;18434:2;18422:9;18413:7;18409:23;18405:32;18402:52;;;18450:1;18447;18440:12;18402:52;-1:-1:-1;18473:16:53;;18311:184;-1:-1:-1;18311:184:53:o;18500:750::-;18865:2;18854:9;18847:21;18828:4;18891:73;18960:2;18949:9;18945:18;18937:6;18929;18891:73;:::i;:::-;19012:9;19004:6;19000:22;18995:2;18984:9;18980:18;18973:50;19046:61;19100:6;19092;19084;19046:61;:::i;:::-;19032:75;;19155:9;19147:6;19143:22;19138:2;19127:9;19123:18;19116:50;19183:61;19237:6;19229;19221;19183:61;:::i;:::-;19175:69;18500:750;-1:-1:-1;;;;;;;;;18500:750:53:o;19603:287::-;19732:3;19770:6;19764:13;19786:66;19845:6;19840:3;19833:4;19825:6;19821:17;19786:66;:::i;:::-;19868:16;;;;;19603:287;-1:-1:-1;;19603:287:53:o","linkReferences":{},"immutableReferences":{"47070":[{"start":6074,"length":32},{"start":6115,"length":32},{"start":6441,"length":32}]}},"methodIdentifiers":{"StarknetChainId()":"6af0abfa","StarknetEscrowAddress()":"1519e961","StarknetEscrowClaimPaymentBatchSelector()":"383bfee4","StarknetEscrowClaimPaymentSelector()":"d788f4c9","UPGRADE_INTERFACE_VERSION()":"ad3cb1cc","ZKSyncChainId()":"83c01387","ZKSyncEscrowAddress()":"942b8aea","ZKSyncEscrowClaimPaymentBatchSelector()":"6835abf4","ZKSyncEscrowClaimPaymentSelector()":"abd43fdd","claimPaymentBatchStarknet(uint256[],address[],uint256[])":"0a21f170","claimPaymentBatchZKSync(uint256[],address[],uint256[],uint256,uint256)":"b2321572","claimPaymentStarknet(uint256,address,uint256)":"1885d25e","claimPaymentZKSync(uint256,address,uint256,uint256,uint256)":"8c23704d","initialize(address,uint256,uint256,address,address,bytes4,bytes4,uint128,uint128)":"3c5035dc","marketMaker()":"1f21f9af","owner()":"8da5cb5b","proxiableUUID()":"52d1902d","renounceOwnership()":"715018a6","setMMAddress(address)":"a7139611","setStarknetClaimPaymentBatchSelector(uint256)":"cb8a48c5","setStarknetClaimPaymentSelector(uint256)":"f12ba5c7","setStarknetEscrowAddress(uint256)":"f04193c8","setZKSyncEscrowAddress(address)":"acfefa52","setZKSyncEscrowClaimPaymentBatchSelector(bytes4)":"afc69b3c","setZKSyncEscrowClaimPaymentSelector(bytes4)":"bf9551bf","transfer(uint256,address,uint128)":"76b5eddc","transferOwnership(address)":"f2fde38b","transfers(bytes32)":"3c64f04b","upgradeToAndCall(address,bytes)":"4f1ef286"},"rawMetadata":"{\"compiler\":{\"version\":\"0.8.20+commit.a1b79de6\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"AddressEmptyCode\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"implementation\",\"type\":\"address\"}],\"name\":\"ERC1967InvalidImplementation\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ERC1967NonPayable\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedInnerCall\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidInitialization\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotInitializing\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"OwnableInvalidOwner\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"OwnableUnauthorizedAccount\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UUPSUnauthorizedCallContext\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"slot\",\"type\":\"bytes32\"}],\"name\":\"UUPSUnsupportedProxiableUUID\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"orderId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint128\",\"name\":\"chainId\",\"type\":\"uint128\"}],\"name\":\"ClaimPayment\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"orderIds\",\"type\":\"uint256[]\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"destAddresses\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"amounts\",\"type\":\"uint256[]\"},{\"indexed\":false,\"internalType\":\"uint128\",\"name\":\"chainId\",\"type\":\"uint128\"}],\"name\":\"ClaimPaymentBatch\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"version\",\"type\":\"uint64\"}],\"name\":\"Initialized\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newEscrowClaimPaymentBatchSelector\",\"type\":\"uint256\"}],\"name\":\"ModifiedStarknetClaimPaymentBatchSelector\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newEscrowClaimPaymentSelector\",\"type\":\"uint256\"}],\"name\":\"ModifiedStarknetClaimPaymentSelector\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newEscrowAddress\",\"type\":\"uint256\"}],\"name\":\"ModifiedStarknetEscrowAddress\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes4\",\"name\":\"newZKSyncEscrowClaimPaymentBatchSelector\",\"type\":\"bytes4\"}],\"name\":\"ModifiedZKSyncClaimPaymentBatchSelector\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes4\",\"name\":\"newZKSyncEscrowClaimPaymentSelector\",\"type\":\"bytes4\"}],\"name\":\"ModifiedZKSyncClaimPaymentSelector\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newEscrowAddress\",\"type\":\"address\"}],\"name\":\"ModifiedZKSyncEscrowAddress\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"orderId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"srcAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint128\",\"name\":\"chainId\",\"type\":\"uint128\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"implementation\",\"type\":\"address\"}],\"name\":\"Upgraded\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"StarknetChainId\",\"outputs\":[{\"internalType\":\"uint128\",\"name\":\"\",\"type\":\"uint128\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"StarknetEscrowAddress\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"StarknetEscrowClaimPaymentBatchSelector\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"StarknetEscrowClaimPaymentSelector\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"UPGRADE_INTERFACE_VERSION\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"ZKSyncChainId\",\"outputs\":[{\"internalType\":\"uint128\",\"name\":\"\",\"type\":\"uint128\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"ZKSyncEscrowAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"ZKSyncEscrowClaimPaymentBatchSelector\",\"outputs\":[{\"internalType\":\"bytes4\",\"name\":\"\",\"type\":\"bytes4\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"ZKSyncEscrowClaimPaymentSelector\",\"outputs\":[{\"internalType\":\"bytes4\",\"name\":\"\",\"type\":\"bytes4\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"orderIds\",\"type\":\"uint256[]\"},{\"internalType\":\"address[]\",\"name\":\"destAddresses\",\"type\":\"address[]\"},{\"internalType\":\"uint256[]\",\"name\":\"amounts\",\"type\":\"uint256[]\"}],\"name\":\"claimPaymentBatchStarknet\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"orderIds\",\"type\":\"uint256[]\"},{\"internalType\":\"address[]\",\"name\":\"destAddresses\",\"type\":\"address[]\"},{\"internalType\":\"uint256[]\",\"name\":\"amounts\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"gasPerPubdataByteLimit\",\"type\":\"uint256\"}],\"name\":\"claimPaymentBatchZKSync\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"orderId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"destAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"claimPaymentStarknet\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"orderId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"destAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"gasPerPubdataByteLimit\",\"type\":\"uint256\"}],\"name\":\"claimPaymentZKSync\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"snMessaging\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"StarknetEscrowClaimPaymentSelector_\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"StarknetEscrowClaimPaymentBatchSelector_\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"marketMaker_\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"ZKSyncDiamondProxyAddress\",\"type\":\"address\"},{\"internalType\":\"bytes4\",\"name\":\"ZKSyncEscrowClaimPaymentSelector_\",\"type\":\"bytes4\"},{\"internalType\":\"bytes4\",\"name\":\"ZKSyncEscrowClaimPaymentBatchSelector_\",\"type\":\"bytes4\"},{\"internalType\":\"uint128\",\"name\":\"StarknetChainId_\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"ZKSyncChainId_\",\"type\":\"uint128\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"marketMaker\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"proxiableUUID\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newMMAddress\",\"type\":\"address\"}],\"name\":\"setMMAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"NewStarknetEscrowClaimPaymentBatchSelector\",\"type\":\"uint256\"}],\"name\":\"setStarknetClaimPaymentBatchSelector\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"NewStarknetEscrowClaimPaymentSelector\",\"type\":\"uint256\"}],\"name\":\"setStarknetClaimPaymentSelector\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newStarknetEscrowAddress\",\"type\":\"uint256\"}],\"name\":\"setStarknetEscrowAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newZKSyncEscrowAddress\",\"type\":\"address\"}],\"name\":\"setZKSyncEscrowAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"NewZKSyncEscrowClaimPaymentBatchSelector\",\"type\":\"bytes4\"}],\"name\":\"setZKSyncEscrowClaimPaymentBatchSelector\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"NewZKSyncEscrowClaimPaymentSelector\",\"type\":\"bytes4\"}],\"name\":\"setZKSyncEscrowClaimPaymentSelector\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"orderId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"destAddress\",\"type\":\"address\"},{\"internalType\":\"uint128\",\"name\":\"chainId\",\"type\":\"uint128\"}],\"name\":\"transfer\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"transfers\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newImplementation\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"upgradeToAndCall\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"errors\":{\"AddressEmptyCode(address)\":[{\"details\":\"There's no code at `target` (it is not a contract).\"}],\"ERC1967InvalidImplementation(address)\":[{\"details\":\"The `implementation` of the proxy is invalid.\"}],\"ERC1967NonPayable()\":[{\"details\":\"An upgrade function sees `msg.value > 0` that may be lost.\"}],\"FailedInnerCall()\":[{\"details\":\"A call to an address target failed. The target may have reverted.\"}],\"InvalidInitialization()\":[{\"details\":\"The contract is already initialized.\"}],\"NotInitializing()\":[{\"details\":\"The contract is not initializing.\"}],\"OwnableInvalidOwner(address)\":[{\"details\":\"The owner is not a valid owner account. (eg. `address(0)`)\"}],\"OwnableUnauthorizedAccount(address)\":[{\"details\":\"The caller account is not authorized to perform an operation.\"}],\"UUPSUnauthorizedCallContext()\":[{\"details\":\"The call is from an unauthorized context.\"}],\"UUPSUnsupportedProxiableUUID(bytes32)\":[{\"details\":\"The storage `slot` is unsupported as a UUID.\"}]},\"events\":{\"Initialized(uint64)\":{\"details\":\"Triggered when the contract has been initialized or reinitialized.\"},\"Upgraded(address)\":{\"details\":\"Emitted when the implementation is upgraded.\"}},\"kind\":\"dev\",\"methods\":{\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"proxiableUUID()\":{\"details\":\"Implementation of the ERC-1822 {proxiableUUID} function. This returns the storage slot used by the implementation. It is used to validate the implementation's compatibility when performing an upgrade. IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier.\"},\"renounceOwnership()\":{\"details\":\"Leaves the contract without owner. It will not be possible to call `onlyOwner` functions. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby disabling any functionality that is only available to the owner.\"},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"},\"upgradeToAndCall(address,bytes)\":{\"custom:oz-upgrades-unsafe-allow-reachable\":\"delegatecall\",\"details\":\"Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call encoded in `data`. Calls {_authorizeUpgrade}. Emits an {Upgraded} event.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/PaymentRegistry.sol\":\"PaymentRegistry\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[\":@matterlabs/interfaces/=lib/era-contracts/l1-contracts/contracts/zksync/interfaces/\",\":@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/\",\":@openzeppelin/contracts/=lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/\",\":ds-test/=lib/forge-std/lib/ds-test/src/\",\":era-contracts/=lib/era-contracts/\",\":erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/\",\":forge-std/=lib/forge-std/src/\",\":openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/\",\":openzeppelin-contracts/=lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/\",\":starknet/=lib/starknet/\"]},\"sources\":{\"lib/era-contracts/l1-contracts/contracts/common/libraries/UncheckedMath.sol\":{\"keccak256\":\"0x0d8dd71e77c1d25bac04d19e77c0859109648e013b658fb91b3f876f083d58ad\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://89f31e4b7849059fec7c917e61afb8f7af2cbb763c01ad0c9c326f86b9037b41\",\"dweb:/ipfs/QmRnrLH4WJ7UnrNmHre9rGVW8t3HYrsY59CrFBYfr6TK6k\"]},\"lib/era-contracts/l1-contracts/contracts/zksync/Storage.sol\":{\"keccak256\":\"0x43a3f4b2e43014892ddd393ec81ade21d5ccdeb7bb8171141878a4ec035c9458\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://29bae2244558feb34bc393ca0ff70c6d3d636947711a150ceaff246d32fa0a46\",\"dweb:/ipfs/QmUPiwprXNV2bJ8CDgUKQtciWFVYYAbBb8SpUYEYhbHGbs\"]},\"lib/era-contracts/l1-contracts/contracts/zksync/interfaces/IAdmin.sol\":{\"keccak256\":\"0xd9845b35414f4b37a3680f36168662ab8b2e355056bdd96bf7d7d4c499849371\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://eb4babe8901e74523ecbebbf192429d9ad3cf9628cc762df98f3a046f40f938a\",\"dweb:/ipfs/QmTadxmp6oexsvZVrhGscSSnZSqL43PEorN4pekzUeL5vy\"]},\"lib/era-contracts/l1-contracts/contracts/zksync/interfaces/IBase.sol\":{\"keccak256\":\"0x5477656c5eef9a9b275dc6784438256ef4e06db048781b01d84fb72e0d60c655\",\"license\":\"UNLICENSED\",\"urls\":[\"bzz-raw://56bc6517aa13539743be67abb214d5934301c31f7b40c6f7fad67c7aec3c5796\",\"dweb:/ipfs/QmdVdQ8iCsDK9C8krQseWCGNB64AMrKTn1ZF8LLDAq96Et\"]},\"lib/era-contracts/l1-contracts/contracts/zksync/interfaces/IExecutor.sol\":{\"keccak256\":\"0xb580f8687e05fe01afb00b2b77e43a24567993c83fc5b38831f5884e51be292b\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://e73dc57c64af937a6aedba62245bd2fae3a84958f0a9abb70a9df0d02c3f34f8\",\"dweb:/ipfs/QmSVaVAPkQvjVXCjK5XrP2VN4zXY9HuTME8Jyx14FJg4XV\"]},\"lib/era-contracts/l1-contracts/contracts/zksync/interfaces/IGetters.sol\":{\"keccak256\":\"0x8b19758b2fe3996f13d9527fcf0d60b838a2a33b16d7a4ddfc79bd64b731f3bc\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://b66cb276ed200456705b23d2e9a7822c3b1746ed4bfda93d94c4528c2b408538\",\"dweb:/ipfs/QmY5uN8mbZZtip6J94XYt6g6xXMpszNRMxEBsDu3mUKaJm\"]},\"lib/era-contracts/l1-contracts/contracts/zksync/interfaces/IMailbox.sol\":{\"keccak256\":\"0x985178de1704e015af86ad465874cea585229a29ebb6595589292cd3683a77c6\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://d5fb1365a5122c0033615bde0439badcdd5fa61fa60a72507ef53a8459c5eeaa\",\"dweb:/ipfs/QmeDiRjUZSDKQsFryHP2ePczKzTRfsAofMTzUTiiqgLQ93\"]},\"lib/era-contracts/l1-contracts/contracts/zksync/interfaces/IVerifier.sol\":{\"keccak256\":\"0x82fb9aa76bde8914827fe1c60a4f424d915d00ee52ac2ee8f5e408e6313714f2\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://cc915ba7c7f5176d246e6aaa17b09792c8dfddbc9b6826d2be2a38c65a427c0a\",\"dweb:/ipfs/QmUDA9nzF3ot3nLPP865841dKWyQhYtHsNnRb73fGndKoj\"]},\"lib/era-contracts/l1-contracts/contracts/zksync/interfaces/IZkSync.sol\":{\"keccak256\":\"0x91bd2b2dacaf33f4558315452dcf8d939e69c4e24bf6062b305aa48f99c1eaf3\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://fda8ff69a1e4dd806aebcde89e99a62ae255d173864a7ff9037f43ee43571931\",\"dweb:/ipfs/QmNQ3VAtToTyYJUBzSb1pz4jRYXPsHseEq2Z624rALGMxy\"]},\"lib/era-contracts/l1-contracts/contracts/zksync/libraries/Diamond.sol\":{\"keccak256\":\"0xea7462be367bdeca41c027dec9a632f28716c33c01d99eefd8de992da2b73992\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7ca0ff34b359dd2d36e098b6d2cc089dea8da03f2ac77d23a823201b91111e0a\",\"dweb:/ipfs/QmVMMH6ckapWMHk1NzfE9TT6st2w8Fjoes3wSfGYdfjVXV\"]},\"lib/era-contracts/l1-contracts/contracts/zksync/libraries/PriorityQueue.sol\":{\"keccak256\":\"0x26f86ed98f0f9d29d03c2a30af5f71cae753a15f21ed615022460c9f735ebfcd\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7bc52833de251772dd0980870756d8d877169094037de4f8319a5925ecb28c43\",\"dweb:/ipfs/QmVrVFZkiZ49F6ftS1U3ummX1NHX3y8V96vKG6eD5N8H1T\"]},\"lib/openzeppelin-contracts-upgradeable/contracts/access/OwnableUpgradeable.sol\":{\"keccak256\":\"0xc163fcf9bb10138631a9ba5564df1fa25db9adff73bd9ee868a8ae1858fe093a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://9706d43a0124053d9880f6e31a59f31bc0a6a3dc1acd66ce0a16e1111658c5f6\",\"dweb:/ipfs/QmUFmfowzkRwGtDu36cXV9SPTBHJ3n7dG9xQiK5B28jTf2\"]},\"lib/openzeppelin-contracts-upgradeable/contracts/proxy/utils/Initializable.sol\":{\"keccak256\":\"0x631188737069917d2f909d29ce62c4d48611d326686ba6683e26b72a23bfac0b\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7a61054ae84cd6c4d04c0c4450ba1d6de41e27e0a2c4f1bcdf58f796b401c609\",\"dweb:/ipfs/QmUvtdp7X1mRVyC3CsHrtPbgoqWaXHp3S1ZR24tpAQYJWM\"]},\"lib/openzeppelin-contracts-upgradeable/contracts/proxy/utils/UUPSUpgradeable.sol\":{\"keccak256\":\"0x490959f972df54829d0ffacb71fa025429d9b7b9ebd118f418b41e9c0041ef73\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://1883bc1a16a88922abccd415d1b41caf00c38ee581ae3e5976018d9c17d2c4b7\",\"dweb:/ipfs/QmP2vzQM8RR8ce675KhuZEaUicAPRMUbPLwBsTpxByvn18\"]},\"lib/openzeppelin-contracts-upgradeable/contracts/utils/ContextUpgradeable.sol\":{\"keccak256\":\"0xdbef5f0c787055227243a7318ef74c8a5a1108ca3a07f2b3a00ef67769e1e397\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://08e39f23d5b4692f9a40803e53a8156b72b4c1f9902a88cd65ba964db103dab9\",\"dweb:/ipfs/QmPKn6EYDgpga7KtpkA8wV2yJCYGMtc9K4LkJfhKX2RVSV\"]},\"lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/interfaces/draft-IERC1822.sol\":{\"keccak256\":\"0xf5c04a8bf51755681f7db413095377dfd1a05b98b6326fb1da0e9a297057caf0\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://f57690465f41860906cf84e6970baaacae9d05b8311674812e6b502bb510441e\",\"dweb:/ipfs/Qme5swSUieatWond1BHyZaEztdLAPu67KcoQTeY4pH5wVd\"]},\"lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/proxy/ERC1967/ERC1967Utils.sol\":{\"keccak256\":\"0xf5769456c75195b708e2b006c58f7f349b79752ad13d7c70ec1db05739972b22\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://d363b2bdfba6d28207d661c3b3c23beeab6405a8960ef444f8c61c2afe997600\",\"dweb:/ipfs/QmNcgJD5RL25RKtShX32WTRp1xRfPyThThA7CajTnXMjMA\"]},\"lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/proxy/beacon/IBeacon.sol\":{\"keccak256\":\"0xc59a78b07b44b2cf2e8ab4175fca91e8eca1eee2df7357b8d2a8833e5ea1f64c\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://5aa4f07e65444784c29cd7bfcc2341b34381e4e5b5da9f0c5bd00d7f430e66fa\",\"dweb:/ipfs/QmWRMh4Q9DpaU9GvsiXmDdoNYMyyece9if7hnfLz7uqzWM\"]},\"lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/utils/Address.sol\":{\"keccak256\":\"0xaf28a975a78550e45f65e559a3ad6a5ad43b9b8a37366999abd1b7084eb70721\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://b7bd24e224f67f65bfadf85dc2929fa965456bb2415478bd0125471b5ce35245\",\"dweb:/ipfs/QmRaydGr8BTHs1kvaZfsNU69pKzUAGFrvABn1KiRSbE51y\"]},\"lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/utils/StorageSlot.sol\":{\"keccak256\":\"0x70d9a9cf8d5cc830d7396505ef8eb9686bd0c60a29c6644bd6cc278f9bab8ebe\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://719abb402c11be12355088da587ffd971fee1b035b5aa6b1ba3b1a9493d3c1d7\",\"dweb:/ipfs/QmanHMFVDqVtZAFFaH1CeGQWoHWsFnWHH75fCrguwi77Hq\"]},\"lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/utils/math/SafeCast.sol\":{\"keccak256\":\"0xe19a4d5f31d2861e7344e8e535e2feafb913d806d3e2b5fe7782741a2a7094fe\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://4aed79c0fa6f0546ed02f2f683e8f77f0fd2ed7eb34d8bbf3d373c9a6d95b13c\",\"dweb:/ipfs/QmWqVz6UAVqmnWU5pqYPt1o6iDEZyPaBraAA3rKfTTSfYj\"]},\"lib/starknet/IStarknetMessaging.sol\":{\"keccak256\":\"0x40014108e2795fd544af0f6322882e99cc3f0872990d504c1ccebce2afea9617\",\"license\":\"Apache-2.0.\",\"urls\":[\"bzz-raw://d3eec1c3f47243734573b4ac3fc42db2eee4d110d8c39be16fbc6f93498e318d\",\"dweb:/ipfs/QmdYdJFPdEPUFQATa24jNvL59GtdoJeym1w7EARyCq8CvY\"]},\"lib/starknet/IStarknetMessagingEvents.sol\":{\"keccak256\":\"0x71171b10854a020b53b175ed9dc068a56675e2b80f823c0f841ae18977b96e8c\",\"license\":\"Apache-2.0.\",\"urls\":[\"bzz-raw://70d345e80b4fbbceba9bc0b64be0688710434a5b5d6eb4a60fae808d2bcc03d9\",\"dweb:/ipfs/QmQBdERT6NHiC2cDvTwS7aob1CwuuqQZvZt5ibGzvYawvB\"]},\"src/PaymentRegistry.sol\":{\"keccak256\":\"0x2d0df1742eb98363d82f167983a918ac38ea78f0e9660b8ae599a53f8ab28e8e\",\"license\":\"Apache-2.0\",\"urls\":[\"bzz-raw://cc6d46115fcc63f0a624b518a33c03a90bdbc017e22a00324b1946870c056c34\",\"dweb:/ipfs/QmbcVXeXN422JT9A55fYEZfKzMz2bQgM5N1oDjgPm9QVUs\"]}},\"version\":1}","metadata":{"compiler":{"version":"0.8.20+commit.a1b79de6"},"language":"Solidity","output":{"abi":[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"type":"error","name":"AddressEmptyCode"},{"inputs":[{"internalType":"address","name":"implementation","type":"address"}],"type":"error","name":"ERC1967InvalidImplementation"},{"inputs":[],"type":"error","name":"ERC1967NonPayable"},{"inputs":[],"type":"error","name":"FailedInnerCall"},{"inputs":[],"type":"error","name":"InvalidInitialization"},{"inputs":[],"type":"error","name":"NotInitializing"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"type":"error","name":"OwnableInvalidOwner"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"type":"error","name":"OwnableUnauthorizedAccount"},{"inputs":[],"type":"error","name":"UUPSUnauthorizedCallContext"},{"inputs":[{"internalType":"bytes32","name":"slot","type":"bytes32"}],"type":"error","name":"UUPSUnsupportedProxiableUUID"},{"inputs":[{"internalType":"uint256","name":"orderId","type":"uint256","indexed":true},{"internalType":"address","name":"destAddress","type":"address","indexed":false},{"internalType":"uint256","name":"amount","type":"uint256","indexed":false},{"internalType":"uint128","name":"chainId","type":"uint128","indexed":false}],"type":"event","name":"ClaimPayment","anonymous":false},{"inputs":[{"internalType":"uint256[]","name":"orderIds","type":"uint256[]","indexed":false},{"internalType":"address[]","name":"destAddresses","type":"address[]","indexed":false},{"internalType":"uint256[]","name":"amounts","type":"uint256[]","indexed":false},{"internalType":"uint128","name":"chainId","type":"uint128","indexed":false}],"type":"event","name":"ClaimPaymentBatch","anonymous":false},{"inputs":[{"internalType":"uint64","name":"version","type":"uint64","indexed":false}],"type":"event","name":"Initialized","anonymous":false},{"inputs":[{"internalType":"uint256","name":"newEscrowClaimPaymentBatchSelector","type":"uint256","indexed":false}],"type":"event","name":"ModifiedStarknetClaimPaymentBatchSelector","anonymous":false},{"inputs":[{"internalType":"uint256","name":"newEscrowClaimPaymentSelector","type":"uint256","indexed":false}],"type":"event","name":"ModifiedStarknetClaimPaymentSelector","anonymous":false},{"inputs":[{"internalType":"uint256","name":"newEscrowAddress","type":"uint256","indexed":false}],"type":"event","name":"ModifiedStarknetEscrowAddress","anonymous":false},{"inputs":[{"internalType":"bytes4","name":"newZKSyncEscrowClaimPaymentBatchSelector","type":"bytes4","indexed":false}],"type":"event","name":"ModifiedZKSyncClaimPaymentBatchSelector","anonymous":false},{"inputs":[{"internalType":"bytes4","name":"newZKSyncEscrowClaimPaymentSelector","type":"bytes4","indexed":false}],"type":"event","name":"ModifiedZKSyncClaimPaymentSelector","anonymous":false},{"inputs":[{"internalType":"address","name":"newEscrowAddress","type":"address","indexed":false}],"type":"event","name":"ModifiedZKSyncEscrowAddress","anonymous":false},{"inputs":[{"internalType":"address","name":"previousOwner","type":"address","indexed":true},{"internalType":"address","name":"newOwner","type":"address","indexed":true}],"type":"event","name":"OwnershipTransferred","anonymous":false},{"inputs":[{"internalType":"uint256","name":"orderId","type":"uint256","indexed":true},{"internalType":"address","name":"srcAddress","type":"address","indexed":false},{"internalType":"address","name":"destAddress","type":"address","indexed":false},{"internalType":"uint256","name":"amount","type":"uint256","indexed":false},{"internalType":"uint128","name":"chainId","type":"uint128","indexed":false}],"type":"event","name":"Transfer","anonymous":false},{"inputs":[{"internalType":"address","name":"implementation","type":"address","indexed":true}],"type":"event","name":"Upgraded","anonymous":false},{"inputs":[],"stateMutability":"view","type":"function","name":"StarknetChainId","outputs":[{"internalType":"uint128","name":"","type":"uint128"}]},{"inputs":[],"stateMutability":"view","type":"function","name":"StarknetEscrowAddress","outputs":[{"internalType":"uint256","name":"","type":"uint256"}]},{"inputs":[],"stateMutability":"view","type":"function","name":"StarknetEscrowClaimPaymentBatchSelector","outputs":[{"internalType":"uint256","name":"","type":"uint256"}]},{"inputs":[],"stateMutability":"view","type":"function","name":"StarknetEscrowClaimPaymentSelector","outputs":[{"internalType":"uint256","name":"","type":"uint256"}]},{"inputs":[],"stateMutability":"view","type":"function","name":"UPGRADE_INTERFACE_VERSION","outputs":[{"internalType":"string","name":"","type":"string"}]},{"inputs":[],"stateMutability":"view","type":"function","name":"ZKSyncChainId","outputs":[{"internalType":"uint128","name":"","type":"uint128"}]},{"inputs":[],"stateMutability":"view","type":"function","name":"ZKSyncEscrowAddress","outputs":[{"internalType":"address","name":"","type":"address"}]},{"inputs":[],"stateMutability":"view","type":"function","name":"ZKSyncEscrowClaimPaymentBatchSelector","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}]},{"inputs":[],"stateMutability":"view","type":"function","name":"ZKSyncEscrowClaimPaymentSelector","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}]},{"inputs":[{"internalType":"uint256[]","name":"orderIds","type":"uint256[]"},{"internalType":"address[]","name":"destAddresses","type":"address[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"payable","type":"function","name":"claimPaymentBatchStarknet"},{"inputs":[{"internalType":"uint256[]","name":"orderIds","type":"uint256[]"},{"internalType":"address[]","name":"destAddresses","type":"address[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint256","name":"gasPerPubdataByteLimit","type":"uint256"}],"stateMutability":"payable","type":"function","name":"claimPaymentBatchZKSync"},{"inputs":[{"internalType":"uint256","name":"orderId","type":"uint256"},{"internalType":"address","name":"destAddress","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"stateMutability":"payable","type":"function","name":"claimPaymentStarknet"},{"inputs":[{"internalType":"uint256","name":"orderId","type":"uint256"},{"internalType":"address","name":"destAddress","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint256","name":"gasPerPubdataByteLimit","type":"uint256"}],"stateMutability":"payable","type":"function","name":"claimPaymentZKSync"},{"inputs":[{"internalType":"address","name":"snMessaging","type":"address"},{"internalType":"uint256","name":"StarknetEscrowClaimPaymentSelector_","type":"uint256"},{"internalType":"uint256","name":"StarknetEscrowClaimPaymentBatchSelector_","type":"uint256"},{"internalType":"address","name":"marketMaker_","type":"address"},{"internalType":"address","name":"ZKSyncDiamondProxyAddress","type":"address"},{"internalType":"bytes4","name":"ZKSyncEscrowClaimPaymentSelector_","type":"bytes4"},{"internalType":"bytes4","name":"ZKSyncEscrowClaimPaymentBatchSelector_","type":"bytes4"},{"internalType":"uint128","name":"StarknetChainId_","type":"uint128"},{"internalType":"uint128","name":"ZKSyncChainId_","type":"uint128"}],"stateMutability":"nonpayable","type":"function","name":"initialize"},{"inputs":[],"stateMutability":"view","type":"function","name":"marketMaker","outputs":[{"internalType":"address","name":"","type":"address"}]},{"inputs":[],"stateMutability":"view","type":"function","name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}]},{"inputs":[],"stateMutability":"view","type":"function","name":"proxiableUUID","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}]},{"inputs":[],"stateMutability":"nonpayable","type":"function","name":"renounceOwnership"},{"inputs":[{"internalType":"address","name":"newMMAddress","type":"address"}],"stateMutability":"nonpayable","type":"function","name":"setMMAddress"},{"inputs":[{"internalType":"uint256","name":"NewStarknetEscrowClaimPaymentBatchSelector","type":"uint256"}],"stateMutability":"nonpayable","type":"function","name":"setStarknetClaimPaymentBatchSelector"},{"inputs":[{"internalType":"uint256","name":"NewStarknetEscrowClaimPaymentSelector","type":"uint256"}],"stateMutability":"nonpayable","type":"function","name":"setStarknetClaimPaymentSelector"},{"inputs":[{"internalType":"uint256","name":"newStarknetEscrowAddress","type":"uint256"}],"stateMutability":"nonpayable","type":"function","name":"setStarknetEscrowAddress"},{"inputs":[{"internalType":"address","name":"newZKSyncEscrowAddress","type":"address"}],"stateMutability":"nonpayable","type":"function","name":"setZKSyncEscrowAddress"},{"inputs":[{"internalType":"bytes4","name":"NewZKSyncEscrowClaimPaymentBatchSelector","type":"bytes4"}],"stateMutability":"nonpayable","type":"function","name":"setZKSyncEscrowClaimPaymentBatchSelector"},{"inputs":[{"internalType":"bytes4","name":"NewZKSyncEscrowClaimPaymentSelector","type":"bytes4"}],"stateMutability":"nonpayable","type":"function","name":"setZKSyncEscrowClaimPaymentSelector"},{"inputs":[{"internalType":"uint256","name":"orderId","type":"uint256"},{"internalType":"address","name":"destAddress","type":"address"},{"internalType":"uint128","name":"chainId","type":"uint128"}],"stateMutability":"payable","type":"function","name":"transfer"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"stateMutability":"nonpayable","type":"function","name":"transferOwnership"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function","name":"transfers","outputs":[{"internalType":"bool","name":"","type":"bool"}]},{"inputs":[{"internalType":"address","name":"newImplementation","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"stateMutability":"payable","type":"function","name":"upgradeToAndCall"}],"devdoc":{"kind":"dev","methods":{"owner()":{"details":"Returns the address of the current owner."},"proxiableUUID()":{"details":"Implementation of the ERC-1822 {proxiableUUID} function. This returns the storage slot used by the implementation. It is used to validate the implementation's compatibility when performing an upgrade. IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier."},"renounceOwnership()":{"details":"Leaves the contract without owner. It will not be possible to call `onlyOwner` functions. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby disabling any functionality that is only available to the owner."},"transferOwnership(address)":{"details":"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner."},"upgradeToAndCall(address,bytes)":{"custom:oz-upgrades-unsafe-allow-reachable":"delegatecall","details":"Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call encoded in `data`. Calls {_authorizeUpgrade}. Emits an {Upgraded} event."}},"version":1},"userdoc":{"kind":"user","methods":{},"version":1}},"settings":{"remappings":["@matterlabs/interfaces/=lib/era-contracts/l1-contracts/contracts/zksync/interfaces/","@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/","@openzeppelin/contracts/=lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/","ds-test/=lib/forge-std/lib/ds-test/src/","era-contracts/=lib/era-contracts/","erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/","forge-std/=lib/forge-std/src/","openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/","openzeppelin-contracts/=lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/","starknet/=lib/starknet/"],"optimizer":{"enabled":true,"runs":200},"metadata":{"bytecodeHash":"ipfs"},"compilationTarget":{"src/PaymentRegistry.sol":"PaymentRegistry"},"evmVersion":"paris","libraries":{}},"sources":{"lib/era-contracts/l1-contracts/contracts/common/libraries/UncheckedMath.sol":{"keccak256":"0x0d8dd71e77c1d25bac04d19e77c0859109648e013b658fb91b3f876f083d58ad","urls":["bzz-raw://89f31e4b7849059fec7c917e61afb8f7af2cbb763c01ad0c9c326f86b9037b41","dweb:/ipfs/QmRnrLH4WJ7UnrNmHre9rGVW8t3HYrsY59CrFBYfr6TK6k"],"license":"MIT"},"lib/era-contracts/l1-contracts/contracts/zksync/Storage.sol":{"keccak256":"0x43a3f4b2e43014892ddd393ec81ade21d5ccdeb7bb8171141878a4ec035c9458","urls":["bzz-raw://29bae2244558feb34bc393ca0ff70c6d3d636947711a150ceaff246d32fa0a46","dweb:/ipfs/QmUPiwprXNV2bJ8CDgUKQtciWFVYYAbBb8SpUYEYhbHGbs"],"license":"MIT"},"lib/era-contracts/l1-contracts/contracts/zksync/interfaces/IAdmin.sol":{"keccak256":"0xd9845b35414f4b37a3680f36168662ab8b2e355056bdd96bf7d7d4c499849371","urls":["bzz-raw://eb4babe8901e74523ecbebbf192429d9ad3cf9628cc762df98f3a046f40f938a","dweb:/ipfs/QmTadxmp6oexsvZVrhGscSSnZSqL43PEorN4pekzUeL5vy"],"license":"MIT"},"lib/era-contracts/l1-contracts/contracts/zksync/interfaces/IBase.sol":{"keccak256":"0x5477656c5eef9a9b275dc6784438256ef4e06db048781b01d84fb72e0d60c655","urls":["bzz-raw://56bc6517aa13539743be67abb214d5934301c31f7b40c6f7fad67c7aec3c5796","dweb:/ipfs/QmdVdQ8iCsDK9C8krQseWCGNB64AMrKTn1ZF8LLDAq96Et"],"license":"UNLICENSED"},"lib/era-contracts/l1-contracts/contracts/zksync/interfaces/IExecutor.sol":{"keccak256":"0xb580f8687e05fe01afb00b2b77e43a24567993c83fc5b38831f5884e51be292b","urls":["bzz-raw://e73dc57c64af937a6aedba62245bd2fae3a84958f0a9abb70a9df0d02c3f34f8","dweb:/ipfs/QmSVaVAPkQvjVXCjK5XrP2VN4zXY9HuTME8Jyx14FJg4XV"],"license":"MIT"},"lib/era-contracts/l1-contracts/contracts/zksync/interfaces/IGetters.sol":{"keccak256":"0x8b19758b2fe3996f13d9527fcf0d60b838a2a33b16d7a4ddfc79bd64b731f3bc","urls":["bzz-raw://b66cb276ed200456705b23d2e9a7822c3b1746ed4bfda93d94c4528c2b408538","dweb:/ipfs/QmY5uN8mbZZtip6J94XYt6g6xXMpszNRMxEBsDu3mUKaJm"],"license":"MIT"},"lib/era-contracts/l1-contracts/contracts/zksync/interfaces/IMailbox.sol":{"keccak256":"0x985178de1704e015af86ad465874cea585229a29ebb6595589292cd3683a77c6","urls":["bzz-raw://d5fb1365a5122c0033615bde0439badcdd5fa61fa60a72507ef53a8459c5eeaa","dweb:/ipfs/QmeDiRjUZSDKQsFryHP2ePczKzTRfsAofMTzUTiiqgLQ93"],"license":"MIT"},"lib/era-contracts/l1-contracts/contracts/zksync/interfaces/IVerifier.sol":{"keccak256":"0x82fb9aa76bde8914827fe1c60a4f424d915d00ee52ac2ee8f5e408e6313714f2","urls":["bzz-raw://cc915ba7c7f5176d246e6aaa17b09792c8dfddbc9b6826d2be2a38c65a427c0a","dweb:/ipfs/QmUDA9nzF3ot3nLPP865841dKWyQhYtHsNnRb73fGndKoj"],"license":"MIT"},"lib/era-contracts/l1-contracts/contracts/zksync/interfaces/IZkSync.sol":{"keccak256":"0x91bd2b2dacaf33f4558315452dcf8d939e69c4e24bf6062b305aa48f99c1eaf3","urls":["bzz-raw://fda8ff69a1e4dd806aebcde89e99a62ae255d173864a7ff9037f43ee43571931","dweb:/ipfs/QmNQ3VAtToTyYJUBzSb1pz4jRYXPsHseEq2Z624rALGMxy"],"license":"MIT"},"lib/era-contracts/l1-contracts/contracts/zksync/libraries/Diamond.sol":{"keccak256":"0xea7462be367bdeca41c027dec9a632f28716c33c01d99eefd8de992da2b73992","urls":["bzz-raw://7ca0ff34b359dd2d36e098b6d2cc089dea8da03f2ac77d23a823201b91111e0a","dweb:/ipfs/QmVMMH6ckapWMHk1NzfE9TT6st2w8Fjoes3wSfGYdfjVXV"],"license":"MIT"},"lib/era-contracts/l1-contracts/contracts/zksync/libraries/PriorityQueue.sol":{"keccak256":"0x26f86ed98f0f9d29d03c2a30af5f71cae753a15f21ed615022460c9f735ebfcd","urls":["bzz-raw://7bc52833de251772dd0980870756d8d877169094037de4f8319a5925ecb28c43","dweb:/ipfs/QmVrVFZkiZ49F6ftS1U3ummX1NHX3y8V96vKG6eD5N8H1T"],"license":"MIT"},"lib/openzeppelin-contracts-upgradeable/contracts/access/OwnableUpgradeable.sol":{"keccak256":"0xc163fcf9bb10138631a9ba5564df1fa25db9adff73bd9ee868a8ae1858fe093a","urls":["bzz-raw://9706d43a0124053d9880f6e31a59f31bc0a6a3dc1acd66ce0a16e1111658c5f6","dweb:/ipfs/QmUFmfowzkRwGtDu36cXV9SPTBHJ3n7dG9xQiK5B28jTf2"],"license":"MIT"},"lib/openzeppelin-contracts-upgradeable/contracts/proxy/utils/Initializable.sol":{"keccak256":"0x631188737069917d2f909d29ce62c4d48611d326686ba6683e26b72a23bfac0b","urls":["bzz-raw://7a61054ae84cd6c4d04c0c4450ba1d6de41e27e0a2c4f1bcdf58f796b401c609","dweb:/ipfs/QmUvtdp7X1mRVyC3CsHrtPbgoqWaXHp3S1ZR24tpAQYJWM"],"license":"MIT"},"lib/openzeppelin-contracts-upgradeable/contracts/proxy/utils/UUPSUpgradeable.sol":{"keccak256":"0x490959f972df54829d0ffacb71fa025429d9b7b9ebd118f418b41e9c0041ef73","urls":["bzz-raw://1883bc1a16a88922abccd415d1b41caf00c38ee581ae3e5976018d9c17d2c4b7","dweb:/ipfs/QmP2vzQM8RR8ce675KhuZEaUicAPRMUbPLwBsTpxByvn18"],"license":"MIT"},"lib/openzeppelin-contracts-upgradeable/contracts/utils/ContextUpgradeable.sol":{"keccak256":"0xdbef5f0c787055227243a7318ef74c8a5a1108ca3a07f2b3a00ef67769e1e397","urls":["bzz-raw://08e39f23d5b4692f9a40803e53a8156b72b4c1f9902a88cd65ba964db103dab9","dweb:/ipfs/QmPKn6EYDgpga7KtpkA8wV2yJCYGMtc9K4LkJfhKX2RVSV"],"license":"MIT"},"lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/interfaces/draft-IERC1822.sol":{"keccak256":"0xf5c04a8bf51755681f7db413095377dfd1a05b98b6326fb1da0e9a297057caf0","urls":["bzz-raw://f57690465f41860906cf84e6970baaacae9d05b8311674812e6b502bb510441e","dweb:/ipfs/Qme5swSUieatWond1BHyZaEztdLAPu67KcoQTeY4pH5wVd"],"license":"MIT"},"lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/proxy/ERC1967/ERC1967Utils.sol":{"keccak256":"0xf5769456c75195b708e2b006c58f7f349b79752ad13d7c70ec1db05739972b22","urls":["bzz-raw://d363b2bdfba6d28207d661c3b3c23beeab6405a8960ef444f8c61c2afe997600","dweb:/ipfs/QmNcgJD5RL25RKtShX32WTRp1xRfPyThThA7CajTnXMjMA"],"license":"MIT"},"lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/proxy/beacon/IBeacon.sol":{"keccak256":"0xc59a78b07b44b2cf2e8ab4175fca91e8eca1eee2df7357b8d2a8833e5ea1f64c","urls":["bzz-raw://5aa4f07e65444784c29cd7bfcc2341b34381e4e5b5da9f0c5bd00d7f430e66fa","dweb:/ipfs/QmWRMh4Q9DpaU9GvsiXmDdoNYMyyece9if7hnfLz7uqzWM"],"license":"MIT"},"lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/utils/Address.sol":{"keccak256":"0xaf28a975a78550e45f65e559a3ad6a5ad43b9b8a37366999abd1b7084eb70721","urls":["bzz-raw://b7bd24e224f67f65bfadf85dc2929fa965456bb2415478bd0125471b5ce35245","dweb:/ipfs/QmRaydGr8BTHs1kvaZfsNU69pKzUAGFrvABn1KiRSbE51y"],"license":"MIT"},"lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/utils/StorageSlot.sol":{"keccak256":"0x70d9a9cf8d5cc830d7396505ef8eb9686bd0c60a29c6644bd6cc278f9bab8ebe","urls":["bzz-raw://719abb402c11be12355088da587ffd971fee1b035b5aa6b1ba3b1a9493d3c1d7","dweb:/ipfs/QmanHMFVDqVtZAFFaH1CeGQWoHWsFnWHH75fCrguwi77Hq"],"license":"MIT"},"lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/utils/math/SafeCast.sol":{"keccak256":"0xe19a4d5f31d2861e7344e8e535e2feafb913d806d3e2b5fe7782741a2a7094fe","urls":["bzz-raw://4aed79c0fa6f0546ed02f2f683e8f77f0fd2ed7eb34d8bbf3d373c9a6d95b13c","dweb:/ipfs/QmWqVz6UAVqmnWU5pqYPt1o6iDEZyPaBraAA3rKfTTSfYj"],"license":"MIT"},"lib/starknet/IStarknetMessaging.sol":{"keccak256":"0x40014108e2795fd544af0f6322882e99cc3f0872990d504c1ccebce2afea9617","urls":["bzz-raw://d3eec1c3f47243734573b4ac3fc42db2eee4d110d8c39be16fbc6f93498e318d","dweb:/ipfs/QmdYdJFPdEPUFQATa24jNvL59GtdoJeym1w7EARyCq8CvY"],"license":"Apache-2.0."},"lib/starknet/IStarknetMessagingEvents.sol":{"keccak256":"0x71171b10854a020b53b175ed9dc068a56675e2b80f823c0f841ae18977b96e8c","urls":["bzz-raw://70d345e80b4fbbceba9bc0b64be0688710434a5b5d6eb4a60fae808d2bcc03d9","dweb:/ipfs/QmQBdERT6NHiC2cDvTwS7aob1CwuuqQZvZt5ibGzvYawvB"],"license":"Apache-2.0."},"src/PaymentRegistry.sol":{"keccak256":"0x2d0df1742eb98363d82f167983a918ac38ea78f0e9660b8ae599a53f8ab28e8e","urls":["bzz-raw://cc6d46115fcc63f0a624b518a33c03a90bdbc017e22a00324b1946870c056c34","dweb:/ipfs/QmbcVXeXN422JT9A55fYEZfKzMz2bQgM5N1oDjgPm9QVUs"],"license":"Apache-2.0"}},"version":1},"id":49} \ No newline at end of file diff --git a/mm-bot/requirements.txt b/mm-bot/requirements.txt index e9e9ea1e..e0b1174e 100644 --- a/mm-bot/requirements.txt +++ b/mm-bot/requirements.txt @@ -1,8 +1,9 @@ python-dotenv==1.0.0 Requests==2.31.0 starknet_py==0.19.0-alpha -web3==6.5.0 +web3==6.10.0 SQLAlchemy==2.0.23 psycopg2-binary==2.9.9 schedule==1.2.1 zksync2==1.1.0 +hexbytes==1.2.0 diff --git a/mm-bot/resources/schema.sql b/mm-bot/resources/schema.sql index 5123b1dc..64649770 100644 --- a/mm-bot/resources/schema.sql +++ b/mm-bot/resources/schema.sql @@ -3,6 +3,7 @@ CREATE TABLE IF NOT EXISTS orders order_id INT NOT NULL, origin_network VARCHAR(32) NOT NULL, + from_address VARCHAR(66) NOT NULL, -- 66 chars to allow Starknet and zkSync compatibility recipient_address VARCHAR(42) NOT NULL, -- 0x + 40 bytes amount NUMERIC(78, 0) NOT NULL, -- uint 256 fee NUMERIC(78, 0) NOT NULL, -- uint 256 @@ -33,8 +34,6 @@ CREATE TABLE IF NOT EXISTS block created_at TIMESTAMP NOT NULL DEFAULT clock_timestamp() ); -INSERT INTO block (latest_block) VALUES (0) ON CONFLICT DO NOTHING; - CREATE TABLE IF NOT EXISTS error ( id SERIAL PRIMARY KEY, @@ -45,3 +44,12 @@ CREATE TABLE IF NOT EXISTS error FOREIGN KEY (order_id, origin_network) REFERENCES orders (order_id, origin_network) ON DELETE CASCADE ); + +CREATE INDEX IF NOT EXISTS orders_transferred_at_idx ON public.orders USING btree (transferred_at); +CREATE INDEX IF NOT EXISTS orders_amount_idx ON public.orders USING btree (amount); +CREATE INDEX IF NOT EXISTS orders_origin_network_idx ON public.orders USING btree (origin_network); +CREATE INDEX IF NOT EXISTS orders_recipient_address_idx ON public.orders USING btree (recipient_address); +CREATE INDEX IF NOT EXISTS orders_order_id_idx ON public.orders USING btree (order_id); +CREATE INDEX IF NOT EXISTS orders_status_idx ON public.orders USING btree (status); +CREATE INDEX IF NOT EXISTS orders_created_at_idx ON public.orders USING btree (created_at); +CREATE INDEX IF NOT EXISTS orders_completed_at_idx ON public.orders USING btree (completed_at); diff --git a/mm-bot/src/config/constants.py b/mm-bot/src/config/constants.py index 87acc590..3344e386 100644 --- a/mm-bot/src/config/constants.py +++ b/mm-bot/src/config/constants.py @@ -6,7 +6,8 @@ ENVIRONMENT = os.getenv('ENVIRONMENT') ETHEREUM_CHAIN_ID = os.getenv('ETHEREUM_CHAIN_ID') -STARKNET_CHAIN_ID = os.getenv('STARKNET_CHAIN_ID') +STARKNET_CHAIN_ID = int(os.getenv('STARKNET_CHAIN_ID'), 16) +ZKSYNC_CHAIN_ID = int(os.getenv('ZKSYNC_CHAIN_ID')) ETHEREUM_RPC = os.getenv('ETHEREUM_RPC') STARKNET_RPC = os.getenv('STARKNET_RPC') diff --git a/mm-bot/src/main.py b/mm-bot/src/main.py index 07b34762..25570cee 100644 --- a/mm-bot/src/main.py +++ b/mm-bot/src/main.py @@ -10,6 +10,7 @@ from persistence.block_dao import BlockDao from persistence.error_dao import ErrorDao from persistence.order_dao import OrderDao +from services.block_service import BlockService from services.executors.order_executor import OrderExecutor from services.fee_calculators.starknet_fee_calculator import StarknetFeeCalculator from services.fee_calculators.zksync_fee_calculator import ZksyncFeeCalculator @@ -22,6 +23,7 @@ from services.payment_claimer.payment_claimer import PaymentClaimer from services.processors.accepted_blocks_orders_processor import AcceptedBlocksOrdersProcessor from services.processors.failed_orders_processor import FailedOrdersProcessor +from services.processors.long_range_orders_processor import LongRangeOrdersProcessor from services.processors.orders_processor import OrdersProcessor from services.senders.ethereum_sender import EthereumSender @@ -30,6 +32,7 @@ SLEEP_TIME = 5 PROCESS_FAILED_ORDERS_MINUTES_TIMER = 5 PROCESS_ACCEPTED_BLOCKS_MINUTES_TIMER = 5 +PROCESS_LONG_RANGE_ORDERS_MINUTES_TIMER = 5 MAX_ETH_TRANSFER_WEI = 100000000000000000 # TODO move to env variable @@ -46,6 +49,10 @@ async def run(): # Initialize services order_service = OrderService(order_dao, error_dao) + block_service = BlockService(block_dao) + + # Insert the first block of the zkSync and Starknet networks + block_service.init_blocks() # Initialize concurrency primitives eth_lock = asyncio.Lock() @@ -82,11 +89,17 @@ async def run(): accepted_blocks_orders_processor = AcceptedBlocksOrdersProcessor(starknet_order_indexer, starknet_order_executor, block_dao) + # Initialize long range orders processor for zksync + long_range_orders_processor = LongRangeOrdersProcessor(zksync_order_indexer, zksync_order_executor, block_dao) + (schedule.every(PROCESS_FAILED_ORDERS_MINUTES_TIMER).minutes .do(failed_orders_processor.process_orders_job)) (schedule.every(PROCESS_ACCEPTED_BLOCKS_MINUTES_TIMER).minutes .do(accepted_blocks_orders_processor.process_orders_job)) + (schedule.every(PROCESS_LONG_RANGE_ORDERS_MINUTES_TIMER).minutes + .do(long_range_orders_processor.process_orders_job)) + try: # Get all orders that are not completed from the db orders = order_service.get_incomplete_orders() diff --git a/mm-bot/src/models/error.py b/mm-bot/src/models/error.py index c9751d26..7d6ba736 100644 --- a/mm-bot/src/models/error.py +++ b/mm-bot/src/models/error.py @@ -1,16 +1,26 @@ from datetime import datetime -from sqlalchemy import Column, Integer, ForeignKey, String, DateTime +from sqlalchemy import Column, Integer, ForeignKeyConstraint, String, DateTime, Enum from sqlalchemy.orm import relationship, Mapped from config.database_config import Base +from models.network import Network from models.order import Order class Error(Base): __tablename__ = "error" id: int = Column(Integer, primary_key=True, nullable=False) - order_id: int = Column(Integer, ForeignKey("orders.order_id"), nullable=False) + order_id: int = Column(Integer, nullable=False) + origin_network: Network = Column(Enum(Network), nullable=False) order: Mapped[Order] = relationship("Order") message: str = Column(String, nullable=False) created_at: datetime = Column(DateTime, nullable=False, server_default="clock_timestamp()") + + # Set order_id and origin_network as composite foreign key + __table_args__ = ( + ForeignKeyConstraint( + ["order_id", "origin_network"], + ["orders.order_id", "orders.origin_network"] + ), + ) diff --git a/mm-bot/src/models/network.py b/mm-bot/src/models/network.py index 480f26df..a651d335 100644 --- a/mm-bot/src/models/network.py +++ b/mm-bot/src/models/network.py @@ -1,6 +1,8 @@ from enum import Enum +from config import constants class Network(Enum): - STARKNET = 0 - ZKSYNC = 1 + STARKNET = constants.STARKNET_CHAIN_ID + ZKSYNC = constants.ZKSYNC_CHAIN_ID + \ No newline at end of file diff --git a/mm-bot/src/models/order.py b/mm-bot/src/models/order.py index d2257361..c870b3f6 100644 --- a/mm-bot/src/models/order.py +++ b/mm-bot/src/models/order.py @@ -15,6 +15,7 @@ class Order(Base): order_id: int = Column(Integer, primary_key=True, nullable=False) origin_network: Network = Column(Enum(Network), primary_key=True, nullable=False) + from_address: str = Column(String(64), nullable=False) recipient_address: str = Column(String(42), nullable=False) amount: decimal = Column(Numeric(78, 0), nullable=False) fee: decimal = Column(Numeric(78, 0), nullable=False) @@ -57,6 +58,7 @@ def from_set_order_event(set_order_event: SetOrderEvent): return Order( order_id=set_order_event.order_id, origin_network=set_order_event.origin_network, + from_address=set_order_event.from_address, recipient_address=set_order_event.recipient_address, amount=set_order_event.amount, fee=set_order_event.fee, diff --git a/mm-bot/src/models/set_order_event.py b/mm-bot/src/models/set_order_event.py index f97dadbe..c88e7617 100644 --- a/mm-bot/src/models/set_order_event.py +++ b/mm-bot/src/models/set_order_event.py @@ -9,6 +9,7 @@ class SetOrderEvent: def __init__(self, order_id, origin_network, + from_address, set_order_tx_hash, recipient_address, amount, @@ -17,6 +18,7 @@ def __init__(self, is_used=False): self.order_id = order_id self.origin_network = origin_network + self.from_address = from_address self.set_order_tx_hash = set_order_tx_hash self.recipient_address = recipient_address self.amount = amount @@ -28,7 +30,8 @@ def __init__(self, async def from_starknet(event): """ event = { - "tx_hash": "0x + "from_address": "0x", + "tx_hash": "0x", "block_number": 0, "data": [0, 0, 0, 0, 0, 0, 0] } @@ -40,10 +43,12 @@ async def from_starknet(event): recipient_address = hex(event.data[2]) amount = SetOrderEvent.parse_u256_from_double_u128(event.data[3], event.data[4]) fee = SetOrderEvent.parse_u256_from_double_u128(event.data[5], event.data[6]) - is_used = await asyncio.to_thread(ethereum.get_is_used_order, order_id, recipient_address, amount, Network.STARKNET.value) + is_used = await asyncio.to_thread(ethereum.get_is_used_order, order_id, recipient_address, amount, + Network.STARKNET.value) return SetOrderEvent( order_id=order_id, origin_network=Network.STARKNET, + from_address=event.from_address, set_order_tx_hash=set_order_tx_hash, recipient_address=recipient_address, amount=amount, @@ -56,6 +61,7 @@ async def from_starknet(event): async def from_zksync(log): """ log = { + "from_address": "0x", "transactionHash": "0x", "blockNumber": 0, "args": { @@ -68,20 +74,23 @@ async def from_zksync(log): transactionHash: HexBytes recipient_address: str """ - order_id = log.args.order_id - set_order_tx_hash = log.transactionHash - recipient_address = log.args.recipient_address - amount = log.args.amount - fee = log.args.fee - is_used = await asyncio.to_thread(ethereum.get_is_used_order, order_id, recipient_address, amount, Network.ZKSYNC.value) # TODO change to new contract signature + order_id = log['args'].order_id + set_order_tx_hash = log['transactionHash'] + recipient_address = log['args'].recipient_address + amount = log['args'].amount + fee = log['args'].fee + is_used = await asyncio.to_thread(ethereum.get_is_used_order, order_id, recipient_address, amount, + Network.ZKSYNC.value) # TODO change to new contract signature + return SetOrderEvent( order_id=order_id, origin_network=Network.ZKSYNC, + from_address=log['from_address'], set_order_tx_hash=set_order_tx_hash, recipient_address=recipient_address, amount=amount, fee=fee, - block_number=log.blockNumber, + block_number=log['blockNumber'], is_used=is_used ) @@ -90,8 +99,9 @@ def parse_u256_from_double_u128(low, high) -> int: return high << 128 | low def __str__(self): - return f"Order: {self.order_id} - Origin: {self.origin_network} - Amount: {self.amount} - Fee: {self.fee} - " \ - f"Recipient: {self.recipient_address} - Is used: {self.is_used} - Block: {self.block_number}" + return f"Order: {self.order_id} - Origin: {self.origin_network} - From: {self.from_address} - "\ + f"Amount: {self.amount} - Fee: {self.fee} - Recipient: {self.recipient_address} - " \ + f"Is used: {self.is_used} - Block: {self.block_number}" def __repr__(self): return self.__str__() diff --git a/mm-bot/src/models/zksync_log.py b/mm-bot/src/models/zksync_log.py new file mode 100644 index 00000000..5be3cd12 --- /dev/null +++ b/mm-bot/src/models/zksync_log.py @@ -0,0 +1,8 @@ +from web3.types import EventData + + +class ZksyncLog(EventData): + """ + EventData web3 library class doesn't have a from_address field, so we need to extend it to store it + """ + from_address: str diff --git a/mm-bot/src/persistence/block_dao.py b/mm-bot/src/persistence/block_dao.py index e12a290e..ceca0220 100644 --- a/mm-bot/src/persistence/block_dao.py +++ b/mm-bot/src/persistence/block_dao.py @@ -8,12 +8,12 @@ class BlockDao: def __init__(self, db: Session): self.db = db - def get_latest_block(self, network: Network) -> int: - return (self.db.query(Block) - .filter(Block.network == network) - .order_by(Block.id.desc()) - .first() - .latest_block) + def get_latest_block(self, network: Network) -> int | None: + latest_block = (self.db.query(Block) + .filter(Block.network == network) + .order_by(Block.id.desc()) + .first()) + return latest_block.latest_block if latest_block else None def update_latest_block(self, latest_block: int, network: Network): if self.get_latest_block(network) == latest_block: @@ -22,3 +22,9 @@ def update_latest_block(self, latest_block: int, network: Network): self.db.add(block) self.db.commit() return block + + def create_block(self, latest_block: int, network: Network): + block = Block(latest_block=latest_block, network=network) + self.db.add(block) + self.db.commit() + return block diff --git a/mm-bot/src/services/block_service.py b/mm-bot/src/services/block_service.py new file mode 100644 index 00000000..5764c333 --- /dev/null +++ b/mm-bot/src/services/block_service.py @@ -0,0 +1,30 @@ +import logging + +from models.network import Network +from persistence.block_dao import BlockDao + + +class BlockService: + def __init__(self, block_dao: BlockDao): + self.logger = logging.getLogger(__name__) + self.block_dao = block_dao + + def init_blocks(self): + """ + Insert the first block of the zkSync and Starknet networks + """ + if not self.block_dao.get_latest_block(Network.ZKSYNC): + self.logger.info("[+] Inserting first block for zkSync") + self.create_block(0, Network.ZKSYNC) + if not self.block_dao.get_latest_block(Network.STARKNET): + self.logger.info("[+] Inserting first block for Starknet") + self.create_block(0, Network.STARKNET) + + def create_block(self, latest_block: int, network: Network): + """ + Insert a block in the database + + :param latest_block: the latest block to insert + :param network: the network of the block + """ + return self.block_dao.create_block(latest_block, network) diff --git a/mm-bot/src/services/ethereum.py b/mm-bot/src/services/ethereum.py index 46758340..05bae7d2 100644 --- a/mm-bot/src/services/ethereum.py +++ b/mm-bot/src/services/ethereum.py @@ -39,11 +39,10 @@ def get_latest_block(rpc_node=main_rpc_node) -> int: @use_fallback(rpc_nodes, logger, "Failed to get order status") def get_is_used_order(order_id, recipient_address, amount, chain_id, rpc_node=main_rpc_node) -> bool: - is_used_index = 2 - order_data = Web3.solidity_keccak(['uint256', 'uint256', 'uint256', 'uint8'], - [order_id, int(recipient_address, 0), amount, chain_id]) - res = rpc_node.contract.functions.transfers(order_data).call() - return res[is_used_index] + order_data = Web3.solidity_keccak(['uint256', 'address', 'uint256', 'uint128'], + [order_id, Web3.to_checksum_address(recipient_address), amount, chain_id]) + is_used = rpc_node.contract.functions.transfers(order_data).call() + return is_used @use_fallback(rpc_nodes, logger, "Failed to get balance") @@ -56,11 +55,10 @@ def has_funds(amount: int) -> bool: def transfer(order_id: int, destination_address: str, amount: int, chain_id: Network): - destination_address_bytes = int(destination_address, 0) order_id = Web3.to_int(order_id) amount = Web3.to_int(amount) - unsent_tx, signed_tx = create_transfer(order_id, destination_address_bytes, amount, chain_id.value) + unsent_tx, signed_tx = create_transfer(order_id, destination_address, amount, chain_id.value) gas_fee = estimate_transaction_fee(unsent_tx) if not has_enough_funds(amount, gas_fee): @@ -73,9 +71,9 @@ def transfer(order_id: int, destination_address: str, amount: int, chain_id: Net # we need amount so the transaction is valid with the transfer that will be transferred # TODO separate create_transfer_unsent_tx and sign_transaction @use_fallback(rpc_nodes, logger, "Failed to create ethereum transfer") -def create_transfer(order_id: int, destination_address_bytes: int, amount: int, chain_id: int, +def create_transfer(order_id: int, destination_address: str, amount: int, chain_id: int, rpc_node=main_rpc_node): - unsent_tx = rpc_node.contract.functions.transfer(order_id, destination_address_bytes, chain_id).build_transaction({ + unsent_tx = rpc_node.contract.functions.transfer(order_id, Web3.to_checksum_address(destination_address), chain_id).build_transaction({ "chainId": ETHEREUM_CHAIN_ID, "from": rpc_node.account.address, "nonce": get_nonce(rpc_node.w3, rpc_node.account.address), @@ -85,12 +83,11 @@ def create_transfer(order_id: int, destination_address_bytes: int, amount: int, return unsent_tx, signed_tx -def claim_payment(deposit_id, dst_addr, amount, value): +def claim_payment(deposit_id, dst_addr, amount, value): # TODO rename parameters to order_id and destination_address deposit_id = Web3.to_int(deposit_id) - dst_addr_bytes = int(dst_addr, 0) amount = Web3.to_int(amount) - unsent_tx, signed_tx = create_claim_payment(deposit_id, dst_addr_bytes, amount, value) + unsent_tx, signed_tx = create_claim_payment(deposit_id, dst_addr, amount, value) gas_fee = estimate_transaction_fee(unsent_tx) if not has_enough_funds(gas_fee=gas_fee): @@ -101,8 +98,8 @@ def claim_payment(deposit_id, dst_addr, amount, value): @use_fallback(rpc_nodes, logger, "Failed to create claim payment eth") -def create_claim_payment(deposit_id, dst_addr_bytes, amount, value, rpc_node=main_rpc_node): - unsent_tx = rpc_node.contract.functions.claimPayment(deposit_id, dst_addr_bytes, amount).build_transaction({ +def create_claim_payment(deposit_id, destination_address, amount, value, rpc_node=main_rpc_node): + unsent_tx = rpc_node.contract.functions.claimPaymentStarknet(deposit_id, Web3.to_checksum_address(destination_address), amount).build_transaction({ "chainId": ETHEREUM_CHAIN_ID, "from": rpc_node.account.address, "nonce": get_nonce(rpc_node.w3, rpc_node.account.address), @@ -115,20 +112,19 @@ def create_claim_payment(deposit_id, dst_addr_bytes, amount, value, rpc_node=mai def claim_payment_zksync(order_id: int, destination_address: str, amount: int, value: int, gas_limit: int, gas_per_pub_data_byte_limit: int): order_id = Web3.to_int(order_id) # I think it is not necessary because it is already an int - destination_address_bytes = int(destination_address, 0) amount = Web3.to_int(amount) - unsent_tx, signed_tx = create_claim_payment_zksync(order_id, destination_address_bytes, amount, + unsent_tx, signed_tx = create_claim_payment_zksync(order_id, destination_address, amount, value, gas_limit, gas_per_pub_data_byte_limit) return send_raw_transaction(signed_tx) @use_fallback(rpc_nodes, logger, "Failed to create claim payment eth") -def create_claim_payment_zksync(order_id: int, destination_address_bytes: int, amount: int, +def create_claim_payment_zksync(order_id: int, destination_address: str, amount: int, value: int, gas_limit: int, gas_per_pub_data_byte_limit: int, rpc_node=main_rpc_node): - unsent_tx = rpc_node.contract.functions.claimPaymentZKSync(order_id, destination_address_bytes, amount, gas_limit, gas_per_pub_data_byte_limit).build_transaction({ + unsent_tx = rpc_node.contract.functions.claimPaymentZKSync(order_id, Web3.to_checksum_address(destination_address), amount, gas_limit, gas_per_pub_data_byte_limit).build_transaction({ "chainId": ETHEREUM_CHAIN_ID, "from": rpc_node.account.address, "nonce": get_nonce(rpc_node.w3, rpc_node.account.address), diff --git a/mm-bot/src/services/fee_calculators/fee_calculator.py b/mm-bot/src/services/fee_calculators/fee_calculator.py index 028d0fee..e5b48cac 100644 --- a/mm-bot/src/services/fee_calculators/fee_calculator.py +++ b/mm-bot/src/services/fee_calculators/fee_calculator.py @@ -18,7 +18,7 @@ async def estimate_overall_fee(self, order: Order) -> int: This includes: calling the transfer (from PaymentRegistry) + claimPayment (from PaymentRegistry) + - msg fee paid to Starknet (when calling claim_payment) + msg fee paid to L2 (when calling claim_payment) """ transfer_fee = await asyncio.to_thread(self.estimate_transfer_fee, order) message_fee = await self.estimate_message_fee(order) @@ -28,23 +28,20 @@ async def estimate_overall_fee(self, order: Order) -> int: return overall_fee def estimate_transfer_fee(self, order: Order) -> int: - dst_addr_bytes = int(order.recipient_address, 0) deposit_id = Web3.to_int(order.order_id) + destination_address = Web3.to_checksum_address(order.recipient_address) amount = Web3.to_int(order.get_int_amount()) chain_id = order.origin_network.value - unsent_tx, signed_tx = create_transfer(deposit_id, dst_addr_bytes, amount, chain_id) - + unsent_tx, signed_tx = create_transfer(deposit_id, destination_address, amount, chain_id) + # TODO rename parameters to order_id return estimate_transaction_fee(unsent_tx) + @abstractmethod def estimate_claim_payment_fee(self) -> int: """ - Due to the deposit does not exist on ethereum at this point, - we cannot estimate the gas fee of the claim payment transaction - So we will use fixed values for the gas """ - eth_claim_payment_gas = 86139 # TODO this is a fixed value, if the contract changes, this should be updated - return eth_claim_payment_gas * get_gas_price() + pass @abstractmethod async def estimate_message_fee(self, order: Order) -> int: diff --git a/mm-bot/src/services/fee_calculators/starknet_fee_calculator.py b/mm-bot/src/services/fee_calculators/starknet_fee_calculator.py index 74ff05dd..4d5cc3ca 100644 --- a/mm-bot/src/services/fee_calculators/starknet_fee_calculator.py +++ b/mm-bot/src/services/fee_calculators/starknet_fee_calculator.py @@ -3,11 +3,21 @@ from config import constants from models.order import Order from services import starknet +from services.ethereum import get_gas_price from services.fee_calculators.fee_calculator import FeeCalculator class StarknetFeeCalculator(FeeCalculator): + def estimate_claim_payment_fee(self) -> int: + """ + Due to the deposit does not exist on ethereum at this point, + we cannot estimate the gas fee of the claim payment transaction + So we will use fixed values for the gas + """ + eth_claim_payment_gas = 94_642 # TODO this is a fixed value, if the contract changes, this should be updated + return eth_claim_payment_gas * get_gas_price() + async def estimate_message_fee(self, order: Order) -> int: """ Estimate the message fee for the claim payment transaction diff --git a/mm-bot/src/services/fee_calculators/zksync_fee_calculator.py b/mm-bot/src/services/fee_calculators/zksync_fee_calculator.py index 9a18d416..a84fa696 100644 --- a/mm-bot/src/services/fee_calculators/zksync_fee_calculator.py +++ b/mm-bot/src/services/fee_calculators/zksync_fee_calculator.py @@ -1,22 +1,32 @@ from zksync2.core.utils import DEPOSIT_GAS_PER_PUBDATA_LIMIT from models.order import Order +from services import zksync +from services.ethereum import get_gas_price from services.fee_calculators.fee_calculator import FeeCalculator class ZksyncFeeCalculator(FeeCalculator): - async def estimate_overall_fee(self, order: Order) -> int: - return 0 # TODO: implement + def estimate_claim_payment_fee(self) -> int: + """ + Due to the deposit does not exist on ethereum at this point, + we cannot estimate the gas fee of the claim payment transaction + So we will use fixed values for the gas + """ + eth_claim_payment_gas = 143_785 # TODO this is a fixed value, if the contract changes, this should be updated + return eth_claim_payment_gas * get_gas_price() async def estimate_message_fee(self, order: Order) -> int: """ This fee is used as value in claim payment tx to ethereum """ - return 10_000_000_000_000_000 # 0.01 ETH TODO implement estimation - + l2_gas_limit = await self.estimate_gas_limit(order) + gas_price = get_gas_price() + return await zksync.estimate_message_fee(gas_price, l2_gas_limit) + async def estimate_gas_limit(self, order: Order) -> int: - return 300_000 + return await zksync.estimate_gas_limit(order.recipient_address) def estimate_gas_per_pub_data_byte_limit(self, order: Order) -> int: return DEPOSIT_GAS_PER_PUBDATA_LIMIT # This is a constant from zksync2.core.utils diff --git a/mm-bot/src/services/mm_full_node_client.py b/mm-bot/src/services/mm_full_node_client.py index 52360a93..47a5212c 100644 --- a/mm-bot/src/services/mm_full_node_client.py +++ b/mm-bot/src/services/mm_full_node_client.py @@ -12,6 +12,7 @@ @dataclass class MmEvent(Event): tx_hash: str + from_address: str block_number: int diff --git a/mm-bot/src/services/order_service.py b/mm-bot/src/services/order_service.py index 72150dfd..cab8dc7c 100644 --- a/mm-bot/src/services/order_service.py +++ b/mm-bot/src/services/order_service.py @@ -141,7 +141,7 @@ def set_order_failed(self, order: Order, error_message: str) -> Order: :param error_message: the error message to store in the database """ order = self.set_failed(order, True) - error = Error(order_id=order.order_id, message=error_message) + error = Error(order_id=order.order_id, origin_network=order.origin_network, message=error_message) self.error_dao.create_error(error) return order diff --git a/mm-bot/src/services/payment_claimer/ethereum_payment_claimer.py b/mm-bot/src/services/payment_claimer/ethereum_payment_claimer.py index ba2fd52e..6faa6d84 100644 --- a/mm-bot/src/services/payment_claimer/ethereum_payment_claimer.py +++ b/mm-bot/src/services/payment_claimer/ethereum_payment_claimer.py @@ -17,7 +17,7 @@ def __init__(self, fee_calculator: StarknetFeeCalculator): async def send_payment_claim(self, order: Order, order_service: OrderService): # TODO remove order_service """ Makes the payment claim on ethereum - Sends a 'claimPayment' transaction to ethereum smart contract + Sends a 'claimPaymentStarknet' transaction to ethereum smart contract """ self.logger.info(f"[+] Sending payment claim tx to ethereum") order_id, recipient_address, amount = order.order_id, order.recipient_address, order.get_int_amount() diff --git a/mm-bot/src/services/processors/accepted_blocks_orders_processor.py b/mm-bot/src/services/processors/accepted_blocks_orders_processor.py index 52680071..855362a2 100644 --- a/mm-bot/src/services/processors/accepted_blocks_orders_processor.py +++ b/mm-bot/src/services/processors/accepted_blocks_orders_processor.py @@ -1,22 +1,11 @@ import asyncio -import logging from models.network import Network -from persistence.block_dao import BlockDao from services import starknet -from services.executors.order_executor import OrderExecutor -from services.indexers.order_indexer import OrderIndexer +from services.processors.catch_up_orders_processor import CatchUpOrdersProcessor -class AcceptedBlocksOrdersProcessor: - - def __init__(self, order_indexer: OrderIndexer, - order_executor: OrderExecutor, - block_dao: BlockDao): - self.logger = logging.getLogger(__name__) - self.order_indexer: OrderIndexer = order_indexer - self.order_executor: OrderExecutor = order_executor - self.block_dao: BlockDao = block_dao +class AcceptedBlocksOrdersProcessor(CatchUpOrdersProcessor): async def process_orders(self, ): """ diff --git a/mm-bot/src/services/processors/catch_up_orders_processor.py b/mm-bot/src/services/processors/catch_up_orders_processor.py new file mode 100644 index 00000000..7ee3d032 --- /dev/null +++ b/mm-bot/src/services/processors/catch_up_orders_processor.py @@ -0,0 +1,31 @@ +import logging +from abc import ABC, abstractmethod + +from persistence.block_dao import BlockDao +from services.executors.order_executor import OrderExecutor +from services.indexers.order_indexer import OrderIndexer + + +class CatchUpOrdersProcessor(ABC): + + def __init__(self, order_indexer: OrderIndexer, + order_executor: OrderExecutor, + block_dao: BlockDao): + self.logger = logging.getLogger(__name__) + self.order_indexer: OrderIndexer = order_indexer + self.order_executor: OrderExecutor = order_executor + self.block_dao: BlockDao = block_dao + + @abstractmethod + async def process_orders(self): + """ + + """ + pass + + @abstractmethod + def process_orders_job(self): + """ + Process orders job for the scheduler + """ + pass diff --git a/mm-bot/src/services/processors/long_range_orders_processor.py b/mm-bot/src/services/processors/long_range_orders_processor.py new file mode 100644 index 00000000..d65b9239 --- /dev/null +++ b/mm-bot/src/services/processors/long_range_orders_processor.py @@ -0,0 +1,30 @@ +import asyncio + +from models.network import Network +from services import zksync +from services.processors.catch_up_orders_processor import CatchUpOrdersProcessor + +# The maximum number of blocks that can be queried in a single request is 500. +# https://docs.blastapi.io/blast-documentation/apis-documentation/core-api/oktc/eth_getlogs#limits +BLOCK_BATCH_SIZE = 500 + + +class LongRangeOrdersProcessor(CatchUpOrdersProcessor): + + async def process_orders(self): + try: + latest_block = self.block_dao.get_latest_block(Network.ZKSYNC) + new_latest_block = await zksync.get_latest_block() + + for order_block in range(latest_block, new_latest_block, BLOCK_BATCH_SIZE): + end_block = min(order_block + BLOCK_BATCH_SIZE, new_latest_block) + orders = await self.order_indexer.get_orders(order_block, end_block) + for order in orders: + self.order_executor.execute(order) + self.block_dao.update_latest_block(new_latest_block, Network.ZKSYNC) + except Exception as e: + self.logger.error(f"[-] Error: {e}") + + def process_orders_job(self): + asyncio.create_task(self.process_orders(), + name="Long Range Orders") diff --git a/mm-bot/src/services/starknet.py b/mm-bot/src/services/starknet.py index d82093af..c46e878f 100644 --- a/mm-bot/src/services/starknet.py +++ b/mm-bot/src/services/starknet.py @@ -1,11 +1,11 @@ import asyncio import logging -from typing import Literal +from typing import Literal, cast from starknet_py.common import int_from_bytes from starknet_py.hash.selector import get_selector_from_name from starknet_py.net.account.account import Account -from starknet_py.net.client_models import Call +from starknet_py.net.client_models import Call, InvokeTransaction from starknet_py.net.models.chains import StarknetChainId from starknet_py.net.signer.stark_curve_signer import KeyPair @@ -14,7 +14,6 @@ from services.decorators.use_fallback import use_async_fallback from services.mm_full_node_client import MmFullNodeClient -STARKNET_CHAIN_ID = int_from_bytes(constants.STARKNET_CHAIN_ID.encode("utf-8")) SET_ORDER_EVENT_KEY = 0x2c75a60b5bdad73ebbf539cc807fccd09875c3cbf3f44041f852cdb96d8acd3 @@ -35,12 +34,12 @@ def __init__(self, rpc_url, private_key, wallet_address, contract_address, chain constants.STARKNET_PRIVATE_KEY, constants.STARKNET_WALLET_ADDRESS, constants.STARKNET_CONTRACT_ADDRESS, - STARKNET_CHAIN_ID) + constants.STARKNET_CHAIN_ID) fallback_rpc_node = StarknetRpcNode(constants.STARKNET_FALLBACK_RPC, constants.STARKNET_PRIVATE_KEY, constants.STARKNET_WALLET_ADDRESS, constants.STARKNET_CONTRACT_ADDRESS, - STARKNET_CHAIN_ID) + constants.STARKNET_CHAIN_ID) rpc_nodes = [main_rpc_node, fallback_rpc_node] logger = logging.getLogger(__name__) @@ -75,8 +74,9 @@ async def get_is_used_order(order_id, rpc_node=main_rpc_node) -> bool: async def get_order_events(from_block_number, to_block_number) -> list[SetOrderEvent]: continuation_token = None events = [] + event_tasks = [] order_events = [] - tasks = [] + order_tasks = [] while True: events_response = await get_starknet_events(from_block_number, to_block_number, continuation_token) events.extend(events_response.events) @@ -85,12 +85,20 @@ async def get_order_events(from_block_number, to_block_number) -> list[SetOrderE break for event in events: - tasks.append(asyncio.create_task(SetOrderEvent.from_starknet(event))) + event_tasks.append(asyncio.create_task(get_transaction(event.tx_hash))) - for task in tasks: - order = await task - order_events.append(order) - return order_events + transactions = await asyncio.gather(*event_tasks) + + # asyncio.gather() returns the results in the same order as the input list, so we can zip the two lists + # https://docs.python.org/3/library/asyncio-task.html#running-tasks-concurrently + for event, transaction in zip(events, transactions): + transaction = cast(InvokeTransaction, transaction) + event.from_address = f'0x{transaction.sender_address:064x}' + order_tasks.append(asyncio.create_task(SetOrderEvent.from_starknet(event))) + + order_events = await asyncio.gather(*order_tasks) + + return cast(list[SetOrderEvent], order_events) @use_async_fallback(rpc_nodes, logger, "Failed to get latest block number") @@ -139,3 +147,7 @@ async def send_transaction(transaction, rpc_node=main_rpc_node): async def wait_for_tx(transaction_hash, rpc_node=main_rpc_node): await rpc_node.account.client.wait_for_tx(transaction_hash) + +@use_async_fallback(rpc_nodes, logger, "Failed to get the tx") +async def get_transaction(transaction_hash, rpc_node=main_rpc_node): + return await rpc_node.account.client.get_transaction(transaction_hash) diff --git a/mm-bot/src/services/zksync.py b/mm-bot/src/services/zksync.py index ec878819..c4eadb12 100644 --- a/mm-bot/src/services/zksync.py +++ b/mm-bot/src/services/zksync.py @@ -7,10 +7,22 @@ from web3 import AsyncWeb3 from web3.eth.async_eth import AsyncContract from web3.types import EventData +from hexbytes import HexBytes + from config import constants from models.set_order_event import SetOrderEvent +from models.zksync_log import ZksyncLog from services.decorators.use_fallback import use_async_fallback +from services.ethereum import main_rpc_node as ethereum_main_rpc_node, fallback_rpc_node as ethereum_fallback_rpc_node + +from zksync2.account.wallet import Wallet +from zksync2.core.utils import DEPOSIT_GAS_PER_PUBDATA_LIMIT, apply_l1_to_l2_alias +from zksync2.module.request_types import EIP712Meta +from zksync2.module.module_builder import ZkSyncBuilder + +from web3 import Web3 + # Just for keep consistency with the ethereum and starknet # services it won't be a class. It will be a set of functions @@ -26,22 +38,30 @@ class EthereumAsyncRpcNode: https://stackoverflow.com/questions/68954638/how-to-use-asynchttpprovider-in-web3py """ - def __init__(self, rpc_url, private_key, contract_address, abi): + def __init__(self, rpc_url, private_key, contract_address, ethereum_rpc_node, abi): self.w3 = AsyncWeb3(AsyncWeb3.AsyncHTTPProvider(rpc_url)) - # self.account = self.w3.eth.account.from_key(private_key) # TODO use private key when necessary + self.account = self.w3.eth.account.from_key(private_key) self.contract: AsyncContract = self.w3.eth.contract(address=contract_address, abi=abi) + + # TODO: create ZKSyncAsyncRpcNode that extends EthereumAsyncRpcNode and adds zksync and wallet + zk_w3 = ZkSyncBuilder.build(constants.ZKSYNC_RPC) + self.zksync = zk_w3.zksync + self.wallet = Wallet(zk_w3, ethereum_rpc_node.w3, self.account) main_rpc_node = EthereumAsyncRpcNode(constants.ZKSYNC_RPC, - None, + constants.ETHEREUM_PRIVATE_KEY, constants.ZKSYNC_CONTRACT_ADDRESS, + ethereum_main_rpc_node, escrow_abi_file) fallback_rpc_node = EthereumAsyncRpcNode(constants.ZKSYNC_FALLBACK_RPC, - None, + constants.ETHEREUM_PRIVATE_KEY, constants.ZKSYNC_CONTRACT_ADDRESS, + ethereum_fallback_rpc_node, escrow_abi_file) -rpc_nodes = [main_rpc_node, fallback_rpc_node] + +rpc_nodes = [main_rpc_node, fallback_rpc_node] logger = logging.getLogger(__name__) @@ -60,12 +80,46 @@ async def get_set_order_logs(from_block_number: int, to_block_number: int, rpc_n return logs +@use_async_fallback(rpc_nodes, logger, "Failed to estimate message fee") +async def estimate_message_fee(gas_price, l2_gas_limit, rpc_node=main_rpc_node): + return await asyncio.to_thread(rpc_node.wallet.get_base_cost, gas_price=gas_price, l2_gas_limit=l2_gas_limit) + + +@use_async_fallback(rpc_nodes, logger, "Failed to estimate gas limit") +async def estimate_gas_limit(recipient, rpc_node=main_rpc_node): + meta = EIP712Meta(gas_per_pub_data=DEPOSIT_GAS_PER_PUBDATA_LIMIT) + return await asyncio.to_thread(rpc_node.zksync.zks_estimate_gas_l1_to_l2, transaction={ + "from": Web3.to_checksum_address(apply_l1_to_l2_alias(constants.ETHEREUM_CONTRACT_ADDRESS)), + "to": recipient, + "value": 0, + "eip712Meta": meta, + }) + async def get_set_order_events(from_block, to_block) -> list[SetOrderEvent]: """ Get set_orders events from the escrow """ set_order_logs: list[EventData] = await get_set_order_logs(from_block, to_block) - # Create a list of tasks to parallelize the creation of the SetOrderEvent list - tasks = [asyncio.create_task(SetOrderEvent.from_zksync(log)) for log in set_order_logs] - set_order_events = await asyncio.gather(*tasks) + log_tasks = [] + order_tasks = [] + + for log in set_order_logs: + log_tasks.append(asyncio.create_task(get_tx(log['transactionHash']))) + + transactions = await asyncio.gather(*log_tasks) + + # asyncio.gather() returns the results in the same order as the input list, so we can zip the two lists + # https://docs.python.org/3/library/asyncio-task.html#running-tasks-concurrently + for log, transaction in zip(set_order_logs, transactions): + from_address = transaction['from'] + zksync_log = ZksyncLog(**log, from_address=from_address) + # Create a list of tasks to parallelize the creation of the SetOrderEvent list + order_tasks.append(asyncio.create_task(SetOrderEvent.from_zksync(zksync_log))) + + set_order_events = await asyncio.gather(*order_tasks) return cast(list[SetOrderEvent], set_order_events) + + +@use_async_fallback(rpc_nodes, logger, "Failed to get the tx") +async def get_tx(tx_hash: HexBytes, rpc_node=main_rpc_node): + return await rpc_node.w3.eth.get_transaction(tx_hash)